一、Activity的生命周期

Activity其实是继承了ApplicationContext这个类

public class Activity extends ApplicationContext {      protected void onCreate(Bundle savedInstanceState);      protected void onStart();      protected void onResume();      protected void onPause();      protected void onStop();      protected void onDestroy();   }

显示过程:onCreate -> onStart -> onResume
销毁过程:onPause -> onStop -> onDestroy

当前Activity被中断:
若新出的一个Activity是全屏,那么:onPause->onStop ,恢复的时候onReStart->onStart->onResume .
如果打断这个应用程序的是一个Theme 为 Translucent 或者是 Dialog 的Activity 那么只是 onPause ,恢复时 onResume .

  1. 按Back键时:onPause()->onStop()->onDestory()
  2. 按Home键时:onPause()->onStop()
    这时候应用程序并没有销毁,再次回到该应用时:onRestart()->onStart()->onResume()

下面使用一个例子:EditText的内容保存

  1. 问题
    • 在一个EditText里输入如”Hello World !”字符串。
    • 按一下HOME键,然后再次启动刚才的应用程序。
      这时候EditText里并没有我们输入的”Hello World !”字样.
  2. 解决办法
    // 定义一个String 类型用来存取我们EditText输入的值     private String mString;     //当我们按HOME键时,我在onPause方法里,将输入的值赋给mString     @Override      protected void onPause() {          super.onPause();          mString = mEditText.getText().toString();      }      //再次启动应用时,我们要恢复先前状态     @Override      protected void onRestart() {          super.onRestart();          mEditText.setText(mString);      }   

二、生命周期方法中系统在做什么和我们应该做什么

   onCreate:  在这里创建界面,做一些数据的初始化工作。 onStart:  到这一步变成用户可见不可交互的。  onResume: 变成和用户可交互的。 (在activity 栈系统通过栈的方式管理这些个 Activity的最上面,运行完弹出栈,则回到上一个Activity) onPause: 到这一步是可见但不可交互的。 1.系统会停止动画等消耗CPU的事情 2.从上文的描述已经知道,应该在这里保存你的一些数据,因为这个时候 你的程序的优先级降低,有可能被系统收回。 3.在这里保存的数据,应该在onResume里读出来, 注意:这个方法里做的事情时间要短,因为下一个activity不会等到这个方法完成才启动。 onstop: 变得不可见 ,被下一个activity覆盖了。 onDestroy: 这是activity被干掉前最后一个被调用方法了,可能是外面类调用finish方法 或者是系统为了节省空间将它暂时性的干掉,可以用isFinishing()来判断它, 如果你有一个Progress Dialog在线程中转动,请在onDestroy里把他cancel掉, 不然等线程结束的时候,调用Dialog的cancel方法会抛异常的。

onPause,onstop, onDestroy 三种状态 下Activity都有可能被系统干掉。

  • 为了保证程序的正确性,你 要在onPause()里写上持久层操作的代码,将用户编辑的内容都保存到存储介质上(一般是数据库 )。
  • 实际工作中因为生命周期的变化而带来的问题也很多,比如你的应用程序起了新的线程在跑,这时候中断了,你还要去维护那个线程,是暂停还是杀掉还是数据回滚,是吧?因为Activity可能被杀掉,所以线程中使用的变量和一些界面元素就千万要注意了,一般我都是采用Android的消息机制 [Handler,Message]来处理多线程和界面交互的问题。

三、如何让Activity变成一个窗口

  1. 在AndroidManifest.xml 中设置Activity的主题
<!-- 使得Activity对话框的形式弹出来 -->android :theme="@android:style/Theme.Dialog"android:theme="@android:style/Theme.Dialog" <!-- 变成半透明 -->android:theme="@android:style/Theme.Translucent"android:theme="@android:style/Theme.Translucent" 

类似这种Activity的属性可以在android.R.styleable 类的AndroidManifestActivity 方法中看到,AndroidManifest.xml中所有元素的属性的介绍都可以参考这个类 android.R.styleable.

四、Service使用场景和生命周期

1. 概念

Service不能与用户交互,不能自己启动,运行在后台。
如果我们退出应用时,Service进程并没有结束,它仍然在后台运行。

2. 使用场景

  • 当我们想音乐在后台播放,就得Service,否则就听不到歌。
  • 当应用的数据是通过网络获取的,不同时间段的数据是不同的
    我们可以用Service在后台定时更新,而不用每打开应用的时候在去获取。

3. Service生命周期

Service的生命周期比Activity简单,它只继承了onCreate(),onStart(),onDestroy()三个方法。

  • 第一次启动Service时,先后调用了onCreate() , onStart()
  • 停止Service时,则执行onDestroy()
  • 如果Service已经启动,当我们再次启动Service时,不会在执行onCreate(),而是直接执行onStart()

五、JNI 的书写步骤

  1. 声明 native 方法
  2. 编译该java类
  3. 使用 javah ? jni java 类名 生成扩展名为.h的头文件
  4. 使用 C/C++实现本地方法
  5. 将 C/C++编写的文件生成动态连接库

这里以HelloWorld为例:

class HelloWorld {    // 声明native方法,并且不能实现    public native void displayHelloWorld();    /* 加载动态库, 参数“hello”是动态库的名字 * 可以这样理解:我们的方法displayHelloWorld()没有实现, * 但是我们在下面就直接使用了,所以必须在使用之前对它进行初始化 * 这里一般是以static块进行加载 */    static {        System.loadLibrary("hello");    }    public static void main(String[] args) {        new HelloWorld().displayHelloWorld();    }}

六、JNI 调用中考虑的问题

1. java和c是如何互通的?

  • 不能互通的原因主要是 数据类型 的问题。
  • 但jni解决了这个问题,例如c文件中的 jstring 数据类型就是 java传入的String对象 ,经过jni函数的转化就能成为c的 char*

对应数据类型关系如下表:

Java 类型 本地c类型 说明
boolean jboolean 无符号,8 位
byte jbyte 无符号,8 位
char jchar 无符号,16 位
short jshort 有符号,16 位
int jint 有符号,32 位
long jlong 有符号,64 位
float jfloat 32 位
double jdouble 64 位
void void N/A

2. 如何将java传入的String参数转换为c的char*,然后使用?

  • java 传入的String参数,在c文件中被jni转换为jstring的数据类型
  • 在c文件中声明 char* test,然后
    test = (char*)(*env)->GetStringUTFChars(env, jstring, NULL);
  • 注意:test使用完后,通知虚拟机平台相关代码无需再访问:
    (*env)->ReleaseStringUTFChars(env, jstring, test);

3. 将c中获取的一个char*的buffer传递给java?

  1. 这个char*如果是一般的字符串的话,作为 string 传回去就可以了。
  2. 如果是含有’/0’的buffer,最好作为 bytearray 传出,
    因为可以制定copy的length,如果copy到string,可能到’/0’就截断了。

有两种方式传递得到的数据:

  1. 在jni中直接new一个byte数组,然后调用函数(*env)->SetByteArrayRegion(env, bytearray, 0, len, buffer);将buffer的值copy到bytearray中,函数直接return bytearray就可以了。
  2. return 错误号,数据作为参数传出,但是java的基本数据类型是传值,对象是传递的引用,所以将这个需要传出的byte数组用某个类包一下,如下:
class RetObj {    public byte[] bytearray;}

这个对象作为函数的参数retobj传出,通过如下函数将retobj中的byte数组赋值便于传出。代码如下:

jclass cls;jfieldID fid;jbyteArray bytearray;bytearray = (*env)->NewByteArray(env,len);(*env)->SetByteArrayRegion(env, bytearray, 0, len, buffer);cls = (*env)->GetObjectClass(env, retobj);fid = (*env)->GetFieldID(env, cls, "retbytes", "[B"]);(*env)->SetObjectField(env, retobj, fid, bytearray);

4. 不知道占用多少空间的buffer,如何传递出去呢?

  • 在 jni 的c文件中new出空间,传递出去。
  • java的数据不初始化,指向传递出去的空间即可。

七、Android中的动画有哪几类,它们的特点和区别是什么?

  1. Tween动画:使视图组件移动、放大、缩小以及产生透明度的变化
    给出两个关键帧,通过一些算法将给定属性值在给定的时间内在两个关键帧间渐变。
  2. Frame动画:传统的动画方法,通过顺序的播放排列好的图片来实现。
  3. 属性动画:真正的改变属性。

八、Handler机制的原理

Andriod 提供了 Handler 和 Looper 来满足线程间的通信。

  1. Looper : 一个线程可以产生一个Looper对象,管理此线程里的MessageQueue(消息队列)。
  2. Handler : 构造Handler对象来与Looper沟通,
    如push新消息到MessageQueue里,或者接收Looper从MessageQueue取出的消息。
  3. MessageQueue : 消息队列,用来存放线程放入的消息。
  4. 线程 : UI线程通常就是主线程,程序启动时会替它建立一个MessageQueue。

九、mvc模式的原理以及在Android中的运用

松耦合,组件的重用。

  1. view:视图层,一般采用xml文件进行界面的描述,也可以使用javascript+html等的方式作为view层。
  2. controller:一般指Acitvity,所以不要在acitivity中数据操作等耗时操作的代码,要通过activity交割model业务逻辑层处理。
  3. model:对数据库的操作、对网络等的操作都应该在model里面处理,当然对业务计算等操作也是必须放在的该层的。

十、介绍下Android的数据存储方式

  1. 使用SharedPreferences存储数据;
  2. 文件存储数据;
  3. SQLite数据库存储数据;
  4. 使用ContentProvider存储数据;
  5. 网络存储数据;
    Android 中的数据存储都是私有的,其他应用程序都是无法访问的,除非通过ContentResolver获取其他程序共享的数据。

十一、介绍下ContentProvider是如何实现数据共享的

ContentProvider:为存储和获取数据提供统一的接口,可以在不同的应用程序之间共享数据。
无论数据的来源是什么,ContentProvider都会认为是一种表,然后把数据组织成表格。

  1. 定义一个继承ContentProvider的类
  2. 实现ContentProvider的所有方法 (query、insert、update、delete、getType、onCreate)
  3. 在AndroidMinifest.xml中进行声明

十二、如何启用Service,如何停用Service

  1. 通过调用Context.startService()启动,调用Context.stopService()结束,
    startService()可以传递参数给Service.
  2. 第二种方式是通过调用Context.bindService()启动,调用Context.unbindservice()结束
    这种方式可以通过ServiceConnection访问Service。
    • 在Service每一次的开启关闭过程中,只有onStartCommand()可被多次调用(通过多次startService调用),
    • 其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。

十三、注册广播接收器有几种方式,这些方式有何优缺点?

Android中,不同 进程之间 传递信息要用到广播。

方式1. 在Manifest.xml中注册广播

是一种比较推荐的方法,不需要手动注销广播。
(如果广播未注销,程序退出时可能会出错),范例代码:

<receiver android:name = ".MyBroadcastReceiver" <intent-filter>        <action android:name = "com.zhuanghongji.broadcastreceiver.test" />    <intent-filter/><receiver/>

上面两个android:name分别是 广播名广播动作名
如果要自己发送一个广播,在代码中为:

Intent i = new Intent(“com.zhuanghongji.broadcastreceiver.test”);sendBroadcast(i);

广播就发出去了,然后是接收。
新建一个类,继承至BroadcastReceiver,也可以建一个BroadcastReceiver的实例,然后得写onReceive()方法,实现如下:

protected BroadcastReceiver mEvtReceiver = new BroadcastReceiver() {    @Override    public void onReceive(Context context, Intent intent) {        String action = intent.getAction();        if (action.equals("com.zhuanghongji.broadcastreceiver.test")) {            //Do something        }    }};

方式2. 接在代码中实现,但需要手动注册注销

通过IntentFilter设置action,使用 registerReceiver() 方法进行注册。

IntentFilter filter = new IntentFilter();filter.addAction("com.zhuanghongji.broadcastreceiver.test");registerReceiver(mEvtReceiver, filter); // 这时注册了一个recevier ,名为mEvtReceiver,// 然后同样用上面的方法以重写onReceiver,// 最后在程序的onDestroy中要注销广播,实现如下:@Overridepublic void onDestroy() {    super.onDestroy();    unregisterReceiver(mPlayerEvtReceiver);}

十四、请谈谈Android引入广播机制的用意

1. 解答

  • Android系统中的广播是广泛用于 应用程序之间通信 的一种手段。
    类似于事件处理机制,不同的地方就是广播的处理是系统级别的事件处理过程(一般事件处理是控件级别的)。在此过程中仍然是离不开Intent对象,理解广播事件的处理过程,灵活运用广播处理机制,在关键之处往往能实现特别的效果。

  • 在Android 中如果要发送一个广播必须使用sendBroadCast(Intent intent) 向系统发送对其感兴趣的广播接收器中。

  • 使用广播必须要有一个intent 对象必设置其action动作对象使用广播必须在配置文件中显式的指明该广播对象。
  • 每次接收广播 都会重新生成一个接收广播的对象,在 BroadCast中 尽量不要处理太多逻辑问题,建议复杂的逻辑交给Activity 或者 Service 去处理.

补充:

2. BroadcastReceiver的生命周期:

这里写图片描述
大意为:如果一个广播处理完onReceive 那么系统将认定此对象将不再是一个活动的对象,也就会finished掉它。

3. 如何在一个广播接收器中处理多个动作呢?

  • 同样的你必须在 Intent-filter 里面注册该动作,可以是系统的广播动作也可以是自己需要的广播。
  • 之后你之需要在onReceive 方法中,通过 intent.getAction() 判断传进来的动作即可做出不同的处理,不同的动作。

小结:

  • 在Android 中如果要发送一个广播必须使用sendBroadCast 向系统发送对其感兴趣的广播接收器中。
  • 使用广播必须要有一个intent 对象必设置其action动作对象
  • 使用广播必须在配置文件中显式的指明该广播对象
  • 每次接收广播都会重新生成一个接收广播的对象
  • 在BroadCast 中尽量不要处理太多逻辑问题,建议复杂的逻辑交给Activity 或者 Service 去处理

十五、单线程模型中Message,Handler,MessageQueue,Looper之间的关系

  • Message:Handler接收和处理的消息对象。
  • Handler:发送和处理消息。
  • MessageQueue:消息队列,以”先进先出”的方式管理Message。
  • Looper:读取MessageQueue的消息,然后把消息交给”发送该消息的Handler”进行处理。

详细内容可以看我的另一篇总结:Android 总结:Message,MessageQueue,Looper,Handler 消息机制

十六、AIDL 如何工作?能处理哪些类型的数据?

1. 概述

AIDL:Android Interface Definition Language(安卓接口描述语言)

  • 编译器可以通过 aidl文件 生成一段代码,通过预先定义的接口达到 两个进程内部通信,进程间跨界对象访问的目的。
  • AIDL的IPC机制是基于接口的,是轻量级的。使用代理类在客户端和实现层间传递值.。

2. 使用AIDL, 需要完成2件事情

  1. 引入AIDL的相关类
  2. 调用aidl产生的class
    理论上, 参数可以传递基本数据类型和String, 还有就是Bundle的派生类。

3. 具体实现步骤

  1. 创建AIDL文件,
    在这个文件里面定义接口, 该接口定义了可供客户端访问的方法和属性
  2. 编译AIDL文件
    用Ant的话, 可能需要手动, 使用Eclipse plugin的话,可以根据adil文件自动生产java文件并编译, 不需要人为介入。
  3. 在Java文件中, 实现AIDL中定义的接口
    编译器会根据AIDL接口, 产生一个JAVA接口。这个接口有一个名为Stub的内部抽象类,它继承扩展了接口并实现了远程调用需要的几个方法。
  4. 向客户端提供接口 ITaskBinder
    如果写的是service,扩展该Service并重载 onBind () 方法来返回一个实现上述接口的类的实例。
  5. 在服务器端回调客户端的函数
    前提是当客户端获取的IBinder接口的时候,要去注册回调函数, 只有这样, 服务器端才知道该调用那些函数。

4. AIDL语法和支持的数据类型

AIDL语法很简单,可以用来声明一个带一个或多个方法的接口,也可以传递参数和返回值。
由于远程调用的需要, 这些参数和返回值并不是任何类型。
下面是些AIDL支持的数据类型:

  1. 不需要import声明的简单Java编程语言类型(int,boolean等)
  2. String, CharSequence 不需要特殊声明
  3. List, Map和Parcelables类型, 这些类型内所包含的数据成员也只能是简单数据类型, String等其他比支持的类型.

5. 实现接口时有几个原则

  1. 抛出的异常不要返回给调用者. 跨进程抛异常处理是不可取的.
  2. IPC调用是同步的。
    如果你知道一个IPC服务需要超过几毫秒的时间才能完成地话,你应该避免在Activity的主线程中调用。
    也就是说IPC调用会挂起应用程序导致界面失去响应。
    这种情况应该考虑单起一个线程来处理.
  3. 不能在AIDL接口中声明静态属性。

6. IPC的调用步骤

  1. 声明一个接口类型的变量,该接口类型在.aidl文件中定义。
  2. 实现ServiceConnection。
  3. 调用ApplicationContext.bindService(),并在ServiceConnection实现中进行传递.
  4. 在ServiceConnection.onServiceConnected()实现中,
    你会接收一个IBinder实例(被调用的Service).
    调用YourInterfaceName.Stub.asInterface((IBinder)service)将参数转换为YourInterface类型。
  5. 调用接口中定义的方法。 你总要检测到DeadObjectException异常,该异常在连接断开时被抛出。它只会被远程方法抛出。
  6. 断开连接,调用接口实例中的ApplicationContext.unbindService()

十七、什么是ANR?如何避免它?

1. 什么是ANR?

  1. ANR:Application Not Responding

    • 在Android中,活动管理器和窗口管理器这两个系统服务负责监视应用程序的响应。
    • Android应用程序完全运行在一个独立的线程中当出现下列情况时,任何在主线程中运行的,需要消耗大量时间的操作都会引发ANR。
    • 因为此时,你的应用程序已经没有机会去响应输入事件和意向广播(Intent broadcast)。
  2. 当出现下列情况时,Android就会显示ANR对话框了:

    • 对输入事件(如按键、触摸屏事件)的响应超过5秒
    • 意向接受器(intentReceiver)超过10秒钟仍未执行完毕

2. 如何避免它?

  • 潜在的比较耗时的操作,如访问网络和数据库;
  • 或者是开销很大的计算,比如改变位图的大小;
  • 需要在一个单独的子线程中完成 (或者是使用异步请求,如数据库操作)

主线程为子线程提供了 Handler,让子线程在即将结束的时候调用它与主线程通信。

十八、谈谈你对Intent的理解

一个intent是一个Intent对象,它保存了消息的内容。

  1. 对于activity和service来说,它指定了请求的操作名称和待操作数据的URI
  2. Intent对象可以显式的指定一个目标组件。
    • 如果这样的话,android会找到这个组件 (基于manifest文件中的声明)并激活它。
    • 但如果一个目标不是显式指定的,android必须找到响应intent的最佳组件。
      它是通过将Intent对象和目标的intent filter相比较来完成这一工作的。一个组件的intent filter告诉android该组件能处理的intent。intent filter也是在manifest文件中声明的。

十九、如何将SQLite数据库(dictionary.db文件)与apk文件一起发布?

  • 可以将.db文件复制到res的raw目录中。
  • 所有在raw目录中的文件不会被压缩,这样可以直接提取该目录中的文件。

二十、如何操作raw目录中的数据库文件?

在Android中不能直接打开raw目录中的数据库文件

  1. 需要在程序第一次启动时将该文件复制到手机内存或SD卡的某个目录中,然后再打开该数据库文件。
  2. 复制的基本方法是使用 getResources().openRawResource() 方法获得raw目录中资源的 InputStream 对象,然后将该InputStream对象中的数据写入其他的目录中相应文件中。
  3. 在Android SDK中可以使用 SQLiteDatabase.openOrCreateDatabase() 方法来打开任意目录中的SQLite数据库文件。

二十一、Android引入广播机制的用意?

  1. 在同一个应用中,方便几大组件的信息和数据交互。
  2. 在应用间,实现互相通信 (例如在自己的应用程序内监听系统来电)。
  3. 效率上(参考UDP的广播协议在局域网的方便性)。
  4. 设计模式上(反转控制的一种应用,类似监听者模式)

二十二、DDMS和TraceView的区别?

  • DDMS:一个程序执行查看器,在里面可以看见线程和堆栈等信息
  • TraceView:程序性能分析器

二十三、谈谈Android的IPC机制

IPC:内部进程通信

  • 是为了让Activity和Service之间可以随时的进行交互
    且只适用于Activity和Service之间的通信。
  • 通过定义AIDL接口文件来定义IPC接口
    Servier端实现IPC接口
    Client端调用IPC接口本地代理。

二十四、描述一下android的系统架构

android系统架构分“自上而下”为:

  • 应用程序层
  • 应用程序框架层
  • 运行库
  • linux 内核层

    1. applications : 该层是java的应用程序层
      android内置的googlemaps、e-mail、即时通信工具、浏览器、mp3播放 器等处于该层,java开发人员开发的程序也处于该层,而且和内置的应用程序具有平等的位置,可以调用内置的应用程序,也可以替换内置的应用程序。
    2. application framework:应用软件架构
      java应用程序开发人员主要是使用该层封装好的api进行快速开发。
    3. libraries和 androidruntime:
      • libraries:即c/c++函数库部分 :
        大多数都是开放源代码的函数库,例如webkit,该函数库负责 android网页浏览器的运行,例如标准的c函数库libc、openssl、sqlite等,当然也包括支持游戏开发2dsgl和 3dopengles,在多媒体方面有mediaframework框架来支持各种影音和图形文件的播放与显示,例如mpeg4、h.264、mp3、 aac、amr、jpg和png等众多的多媒体文件格式。
      • android的runtime : 负责解释和执行生成的dalvik格式的字节码。
    4. linuxkernel:负责硬件的驱动程序、网络、电源、系统安全以及内存管理等功能
  • Android应用程序使用框架的api并在框架下运行,这就带来了程序开发的高度一致性。

  • 另一方面也告诉我们,要想写出优质高效的程序就必须对整个 applicationframework进行非常深入的理解
  • 精通application framework,你就可以真正的理解android的设计和运行机制,也就更能够驾驭整个应用层的开发。

二十五、某公司高级面试题(2015-03-14)

  1. 详述Android系统架构,包括层与层之间调用、binder、jni、底层文件读写方法。
  2. 描述自己的一个项目,要求画出结构图,UML图,详细描述项目种的技术点,技术难点以及解决方案。
  3. 一道算法。
  4. 谈谈自己项目管理的方法、对敏捷软件开发的理解

二十六、请解释下在单线程模型中Message,Handler,Message Queue,Looper之间的关系。

  1. 拿主线程来说,主线程启动时会调用Looper.prepare()方法,会初始化一个Looper,放入Threadlocal中,接着调用Looper.loop()不断遍历Message Queue 。
  2. Handler的创建依赖与当前线程中的Looper,如果当前线程没有Looper则必须调用Looper.prepare()。
  3. Handler通过sendMessage到MessageQueue,Looper不断从MessageQueue中取出消息,回调handleMessage方法。

二十七、如果有个100M大的文件,需要上传至服务器中,而服务器form表单最大只能上传2M,可以用什么方法?

  1. 这个问题不是很明确我觉得,首先来说使用http协议上传数据,特别在android下,跟form没什么关系。
  2. 传统的在web中,在form中写文件上传,其实浏览器所做的就是将我们的数据进行解析组拼成字符串,以流的方式发送到服务器,且上传文件用的都是POST方式,POST方式对大小没什么限制。
  3. 回到题目,可以说假设每次真的只能上传2M,那么可能我们只能把文件截断,然后分别上传了。

二十八、内存溢出和内存泄漏有什么区别?何时会产生内存泄漏?内存优化有哪些方法?

  1. 内存溢出通俗理解就是软件(应用)运行需要的内存,超出了它可用的最大内存。
    内存泄漏就是我们对某一内存空间的使用,使用完成后没有释放。

  2. 内存优化:Android中容易内存溢出的部分,就是图片的加载,我们可以使用图片的压缩加上使用LruCache缓存的目的来控制图片所能够使用的内存。

    • 还有对于比较耗资源的对象及时的关闭,例如Database Conn , 各种传感器 , Service 等等。

二十九、AsyncTask使用在哪些场景?它的缺陷是什么?如何解决?

  1. 场景:比如我们需要进行一些耗时的操作,耗时操作完成后更新主线程,或者在操作过程中对主线程的UI进行更新。

  2. 缺陷:AsyncTask中维护着一个长度为128的线程池,同时可以执行5个工作线程,还有一个缓冲队列,当线程池中已有128个线程,缓冲队列已满时,如果此时向线程提交任务,将会抛出RejectedExecutionException。

  3. 解决:由一个控制线程来处理AsyncTask的调用判断线程池是否满了,如果满了则线程睡眠否则请求AsyncTask继续处理。

三十、assest文件夹里放文件,对于文件的大小有没有限制?

  1. Android不会为这个目录中的文件生成ID并保存在R类当中,因此它与Android中的一些类和方法兼容度更低。
  2. 同时,由于你需要一个字符串路径来获取这个目录下的文件描述符,访问的速度会更慢。
    • 但是把一些文件放在这个目录下会使一些操作更加方便,比方说拷贝一个数据库文件到系统内存中。
    • 要注意的是,你无法在Android XML文件中引用到assets目录下的文件,只能通过AssetManager来访问这些文件。
    • 数据库文件和游戏数据等放在这个目录下是比较合适的。

另外,网上关于assets和raw的资料都千篇一律了,因此关于这两者中单个文件大小不能超过1M的错误描述也在传播,即如果读取超过1M的文件会报”Data exceeds UNCOMPRESS_DATA_MAX (1314625 vs 1048576)”的IOException,还引申出种种解决方案。

  • 个人认为不应该有这样的限制,为了验证这个说法写了个Demo,发现将近5M的压缩包在assets和raw中都能正常访问。
  • 因此在这里纠正一下,理论上只要打包不超过Android APK 50M大小的限制都是没有问题的。
  • 当然了,不排除是Android很早期的时候因为设备硬件原因aapt在编译的时候对这两个文件夹大小做出了限制,如果是这样,较新版的ADT应该不会出现这种情。

三十一、启动一个程序,可以主界面点击图标进入,也可以从一个程序中跳转过去,二者有什么区别?

是因为启动程序,发现了在这个程序中存在一个设置为<category android:name="android.intent.category.LAUNCHER" />的activity (主界面也是一个app)。

所以这个launcher会把icon提出来,放在主界面上。
当用户点击icon的时候,发出一个Intent:

Intent intent = mActivity.getPackageManager().getLaunchIntentForPackage(packageName);mActivity.startActivity(intent);   

跳过去可以跳到任意允许的页面,如一个程序可以下载,那么真正下载的页面可能不是首页(也有可能是首页),这时还是构造一个Intent进行startActivity.

  • 这个intent中的action可能有多种view,download都有可能。系统会根据第三方程序向系统注册的功能,为你的Intent选择可以打开的程序或者页面。
  • 所以唯一的一点不同的是从icon的点击启动的intent的action是相对单一的,从程序中跳转或者启动可能样式更多一些。本质是相同的。

三十二、程序之间的亲和性的理解。

  1. 默认情况下一个应用的所有Activity都是具有相同的affinity,都是从application中继承,application的affinity默认就是manifest的包名。
  2. affinity对Activity来说,就像是身份证一样,可以告诉所在的Task,自己属于其中的一员。
  3. 应用场合:
    • 根据affinity重新为Activity选择合适的宿主Task;
    • 与allowTaskReparenting属性配合;
    • 启动Activity使用Intent设置了FLAG_ACTIVITY_NEW_TASK标记。

三十三、同一个程序,但不同的Activity是否可以放在不同的Task任务栈中?

可以放在不同的Task中。

  • 需要为不同的activity设置不同的affinity属性,启动activity的Intent需要包含FLAG_ACTIVITY_NEW_TASK标记。

三十四、横竖屏切换时候Activity的生命周期?

  1. 不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
  2. 设置Activity的android:configChanges=”orientation”时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
  3. 设置Activity的android:configChanges=”orientation|keyboardHidden”时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法

三十五、dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念?

Dvm的进程是dalivk虚拟机进程:

  • 每个android程序都运行在自己的进程里面,
  • 每个android程序系统都会给他分配一个单独的liunx uid(user id),
  • 每个dvm都是linux里面的一个进程.

所以说这两个进程是一个进程。

三十六、

参考文章:
1. Android 面试精华题目总结

更多相关文章

  1. android 网络下载获取文件大小
  2. android 判断文件是否存在
  3. Android项目初始时的文件
  4. Android在外部修改了工程名文件夹名称,报错
  5. Android之文件存储
  6. Android 解压文件包
  7. Android 加载图片文件 函数
  8. android EditText 不自动弹出键盘的方法

随机推荐

  1. 婚恋网后台管理路由
  2. easywechat实现微信接入并不同消息回复+
  3. easywechat的使用
  4. 微信公众号接入与发送接收消息
  5. 婚恋网后台的资源路由 普通控制器和资源
  6. PDO预处理与会话控制
  7. vue_1
  8. 意派Epub360丨中秋节合成海报H5案例赏析,
  9. 定义网站相关路由内容
  10. 豆瓣" 饭圈 " 整治,如何采集分析评论