本文出自 Eddy Wiki ,转载请注明出处:http://eddy.wiki/interview-android.html
本文收集整理了 Android 面试中会遇到与 Android 知识相关的简述题。
基本概念
Android 的四大组件
Acitivity、Service、BroadcastReceiver、ContentProvider
Activity :
应用程序中,一个Activity通常就是一个单独的屏幕,它上面可以显示一些控件也可以监听并处理用户的事件做出响应。
BroadcastReceiver广播接收器:
应用程序可以使用它对外部事件进行过滤只对感兴趣的外部事件(如当电话呼入时,或者数据网络可用时)进行接收并做出响应。广播接收器没有用户界面。然而,它们可以启动一个activity或serice 来响应它们收到的信息,或者用NotificationManager 来通知用户。通知可以用很多种方式来吸引用户的注意力──闪动背灯、震动、播放声音等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。
Service 服务:
一个Service 是一段长生命周期的,没有用户界面的程序,可以用来开发如监控类程序。
Content Provider内容提供者 :
android平台提供了Content Provider使一个应用程序的指定数据集提供给其他应用程序。这些数据可以存储在文件系统中、在一个SQLite数据库、或以任何其他合理的方式。其他应用可以通过ContentResolver类(见ContentProviderAccessApp例子)从该内容提供者中获取或存入数据.(相当于在应用外包了一层壳),只有需要在多个应用程序间共享数据是才需要内容提供者。例如,通讯录数据被多个应用程序使用,且必须存储在一个内容提供者中。它的好处:统一数据访问方式。
参考:
四大组件的具体作用以及用法
- Acitivity 用于显示界面,接收用户输入,和用户交互。
- Service 运行于后台无界面的程序,用于在后台完成一下任务,例如:音乐播放等。
- BroadCast Receiver 接收系统或应用发出的广播并作出响应,例如:电话的呼入呼出等。
- Content Provider 用于把APP本身的数据共享给其他APP,提供本APP数据的存取接口给其他APP。
Android平台的framework的层次结构?
应用层、应用框架层、中间件(核心库和运行时)、Linux内核
Activity
Activity 生命周期
- 启动Activity:onCreate->onStart->onResume
- 锁屏或被其它Activity覆盖:onPause->onStop
- 解锁或由被覆盖状态再回到前台:onRestart->onStart->onResume
- 跳转到其它Activity或按Home进入后台:onPause->onStop
- 退回到此Activity:onRestart->onStart->onResume
- 退出此Activity:onPause->onStop->onDestory
- 对话框弹出不会执行任何生命周期(注:对话框如果是Activity(Theme为Dialog),还是会执行生命周期的)
- 从A跳转到B:当B的主题为透明时,A只会执行onPause(A-onPause->B-(onCreate->onStart->onResume))
- 从A跳转到B:A-onPause->B-(onCreate->onStart->onResume)-A-onStop(注意是A执行onPause后开始执行B的生命周期,B执行onResume后,A才执行onStop,所以尽量不要在onPause中做耗时操作)
- 从B返回到A:B-onPause->A-(onRestart->onStart->onResume)-B-(onStop->onDestroy)
Activity和Fragment生命周期有哪些?
Activity——onCreate->onStart->onResume->onPause->onStop->onDestroy
Fragment——onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume->onPause->onStop->onDestroyView->onDestroy->onDetach
Activity四种启动模式的区别(LanchMode 的应用场景)
- standard 模式
这是默认模式,每次激活Activity时都会创建Activity实例,并放入任务栈中。
- singleTop 模式
如果在任务的栈顶正好存在该Activity的实例,就重用该实例( 会调用实例的 onNewIntent() ),否则就会创建新的实例并放入栈顶,即使栈中已经存在该Activity的实例,只要不在栈顶,都会创建新的实例。
- singleTask 模式
如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的 onNewIntent() )。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。如果栈中不存在该实例,将会创建新的实例放入栈中。
- singleInstance 模式
在一个新栈中创建该Activity的实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例( 会调用实例的 onNewIntent() )。其效果相当于多个应用共享一个应用,不管谁激活该 Activity 都会进入同一个应用中。
设置启动模式的位置在 AndroidManifest.xml 文件中 Activity 元素的 Android:launchMode 属性。
singleTop适合接收通知启动的内容显示页面。例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。
singleTask适合作为程序入口点。例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。
singleInstance应用场景:闹铃的响铃界面。 你以前设置了一个闹铃:上午6点。在上午5点58分,你启动了闹铃设置界面,并按 Home 键回桌面;在上午5点59分时,你在微信和朋友聊天;在6点时,闹铃响了,并且弹出了一个对话框形式的 Activity(名为 AlarmAlertActivity) 提示你到6点了(这个 Activity 就是以 SingleInstance 加载模式打开的),你按返回键,回到的是微信的聊天界面,这是因为 AlarmAlertActivity 所在的 Task 的栈只有他一个元素, 因此退出之后这个 Task 的栈空了。如果是以 SingleTask 打开 AlarmAlertActivity,那么当闹铃响了的时候,按返回键应该进入闹铃设置界面。
Activity中类似onCreate、onStart运用了哪种设计模式,优点是什么
模板模式。每次新建一个Actiivty时都会覆盖onCreate,onStart等方法,这些方法在父类中就相当于一个模板。
如何将一个Activity设置成窗口的样式
- 在AndroidManifest.xml文件中设置当前需要改变成窗口样式的Activity的属性。
android:theme="@android:style/Theme.Dialog"
- 在styles.xml文件中自定义一个主题样式,改主题样式必须继承Dialog的样式.
Activity的启动过程
- 无论是通过Launcher来启动Activity,还是通过Activity内部调用startActivity接口来启动新的Activity,都通过Binder进程间通信进入到ActivityManagerService进程中,并且调用ActivityManagerService.startActivity接口;
- ActivityManagerService调用ActivityStack.startActivityMayWait来做准备要启动的Activity的相关信息;
- ActivityStack通知ApplicationThread要进行Activity启动调度了,这里的ApplicationThread代表的是调用ActivityManagerService.startActivity接口的进程,对于通过点击应用程序图标的情景来说,这个进程就是Launcher了,而对于通过在Activity内部调用startActivity的情景来说,这个进程就是这个Activity所在的进程了;
- ApplicationThread不执行真正的启动操作,它通过调用ActivityManagerService.activityPaused接口进入到ActivityManagerService进程中,看看是否需要创建新的进程来启动Activity;
- 对于通过点击应用程序图标来启动Activity的情景来说,ActivityManagerService在这一步中,会调用startProcessLocked来创建一个新的进程,而对于通过在Activity内部调用startActivity来启动新的Activity来说,这一步是不需要执行的,因为新的Activity就在原来的Activity所在的进程中进行启动;
- ActivityManagerService调用ApplicationThread.scheduleLaunchActivity接口,通知相应的进程执行启动Activity的操作;
- ApplicationThread把这个启动Activity的操作转发给ActivityThread,ActivityThread通过ClassLoader导入相应的Activity类,然后把它启动起来。
window和activity之间关系?
WindowManager 的相关知识
Activity、Window 和 View 三者的区别
- 一个 Activity 构造的时候一定会构造一个 Window(PhoneWindow),并且只有一个。
- 这个Window会有一个ViewRoot(View、ViewGroup)。
- 通过addView()加载布局。
- WindowMangerService 接收消息,并且回到 Activity 函数,比如onKeyDown()。
Activity 是控制单元,Window 是承载模型,View 是显示视图
一个activity打开另外一个activity,再打开一个activity?回去的时候发生了什么操作?
onActivityResult(int requestCode, int resultCode, Intent data)方法的用法;
如果你想在Activity中得到新打开Activity关闭后返回的数据,你需要使用系统提供的startActivityForResult(Intent intent,int requestCode)方法打开新的Activity,新的Activity关闭后会向前面的Activity传回数据,为了得到传回的数据,你必须在前面的Activity中重写onActivityResult(int requestCode, int resultCode,Intent data)方法。
不用Service,B页面为音乐播放,从A跳到B,再返回,如何使音乐继续播放?
A使用startActivityForResult方法开启B,B类结束时调用finish;A类的Intent有一个子Activity结束事件onActivityResult,在这个事件里继续播放音乐。
内存不足时,怎么保持Activity的一些状态,在哪个方法里面做具体操作?
在onSaveInstanceState方法中保存Activity的状态,在onRestoreInstanceState或onCreate方法中恢复Activity的状态
onSaveInstanceState方法
- 用于保存Activity的状态存储一些临时数据
- Activity被覆盖或进入后台,由于系统资源不足被kill会被调用
- 用户改变屏幕方向会被调用
- 跳转到其它Activity或按Home进入后台会被调用
- 会在onStop之前被调用,和onPause的顺序不固定的
onRestoreInstanceState(Bundle savedInstanceState)方法
- 用于恢复保存的临时数据,此方法的Bundle参数也会传递到onCreate方法中,你也可以在onCreate(Bundle savedInstanceState)方法中恢复数据
- onRestoreInstanceState和onCreate的区别:当onRestoreInstanceState被调用时Bundle参数一定是有值的,不用做为null判断,onCreate的Bundle则可能会为null。官方文档建议在此方法中进行数据恢复。
- 由于系统资源不足被kill之后又回到此Activity会被调用
- 用户改变屏幕方向重建Activity时会被调用
- 会在onStart之后被调用
同一个程序不同的Activity如何放在不同的任务栈中?
需要为不同的activity设置不同的affinity属性,启动activity的Intent需要包含FLAG_ACTIVITY_NEW_TASK标记。
如何安全退出已调用多个Activity的Application?
- 记录打开的Activity:每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
- 发送特定广播:在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
- 递归退出:在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。
有几种在activity之间切换的方法?
startActivity()
startActivityForResult()
Fragment
Fragment生命周期
Activity中如何动态的添加Fragment?
//向活动添加碎片,根据屏幕的纵向和横向显示
//1,获取碎片管理器
FragmentManager fragment=getFragmentManager();
//2,碎片的显示需要使用FragmentTransaction类操作
FragmentTransaction transacction=fragment.beginTransaction();
//获取屏幕管理器和默认的显示
Display display=getWindowManager().getDefaultDisplay();
//判断横屏
if(display.getWidth()>display.getHeight()){
//获取java类
Frament1 frament1 = new Frament1();
transacction.replace(android.R.id.content, frament1);
}else{
Frament2 frament2 = new Frament2();
transacction.replace(android.R.id.content, frament2);
}
//使用FragmentTransaction必须要commit
transacction.commit();
Fragment 特点
- Fragment可以作为Activity界面的一部分组成出现;
- 可以在一个Activity中同时出现多个Fragment,并且一个Fragment也可以在多个Activity中使用;
- 在Activity运行过程中,可以添加、移除或者替换Fragment;
- Fragment可以响应自己的输入事件,并且有自己的生命周期,它们的生命周期会受宿主Activity的生命周期影响。
- Fragment可以轻松得创建动态灵活的UI设计,可以适应于不同的屏幕尺寸。从手机到平板电脑。
- Fragment 解决Activity间的切换不流畅,轻量切换。
- Fragment 替代TabActivity做导航,性能更好。
- Fragment做局部内容更新更方便,原来为了达到这一点要把多个布局放到一个activity里面,现在可以用多Fragment来代替,只有在需要的时候才加载Fragment,提高性能。
Fragment嵌套多个Fragment会出现bug吗?
参考:http://blog.csdn.net/megatronkings/article/details/51417510
怎么理解Activity和Fragment的关系?
- Fragment 拥有和 Activity 一致的生命周期,它和 Activity 一样被定义为 Controller 层的类。有过中大型项目开发经验的开发者,应该都会遇到过 Activity 过于臃肿的情况,而 Fragment 的出现就是为了缓解这一状况,可以说 它将屏幕分解为多个「Fragment(碎片)」(这句话很重要),但它又不同于 View,它干的实质上就是 Activity 的事情,负责控制 View 以及它们之间的逻辑。
- 将屏幕碎片化为多个 Fragment 后,其实 Activity 只需要花精力去管理当前屏幕内应该显示哪些 Fragments,以及应该对它们进行如何布局就行了。这是一种组件化的思维,用 Fragment 去组合了一系列有关联的 UI 组件,并管理它们之间的逻辑,而 Activity 负责在不同屏幕下(例如横竖屏)布局不同的 Fragments 组合。
- 这种碎片不单单能管理可视的 Views,它也能执行不可视的 Tasks,它提供了 retainInstance 属性,能够在 Activity 因为屏幕状态发生改变(例如切换横竖屏时)而销毁重建时,依然保留实例。这示意着我们能在 RetainedFragment 里面执行一些在屏幕状态发生改变时不被中断的操作。例如使用 RetainedFragment 来缓存在线音乐文件,它在横竖屏切换时依然维持下载进度,并通过一个 DialogFragment 来展示进度。
Service
Service的生命周期。
Service是运行在后台的android组件,没有用户界面,不能与用户交互,可以运行在自己的进程,也可以运行在其他应用程序的上下
文里。
Service随着启动形式的不同,其生命周期稍有差别。当用Context.startService()来启动时,Service的生命周期依次为:oncreate——>onStartCommand——>onDestroy
当用Context.bindService()启动时:onStart——>onBind——>onUnbind——>onDestroy
Service有哪些启动方法,有什么区别,怎样停用Service?
Service启动方式有两种;一是Context.startService和Context.bindService。
区别是通过startService启动时Service组件和应用程序没多大的联系;当用访问者启动之后,如果访问者不主动关闭,Service就不会关闭,Service组件之间因为没什么关联,所以Service也不能和应用程序进行数据交互。
而通过bindService进行绑定时,应用程序可以通过ServiceConnection进行数据交互。在实现Service时重写的onBind方法中,其返回的对象会传给ServiceConnection对象的onServiceConnected(ComponentName name, IBinder service)中的service参数;也就是说获取了serivce这个参数就得到了Serivce组件返回的值。Context.bindService(Intent intent,ServiceConnection conn,int flag)其中只要与Service连接成功conn就会调用其onServiceConnected方法
停用Service使用Context.stopService
注册Service需要注意什么
无论使用哪种启动方法,都需要在xml里注册你的Service,就像这样:
<service
android:name=".packnameName.youServiceName"
android:enabled="true" />
service 可以执行耗时操作吗
不能,超过20s就会出现ARN
Service和Activity在同一个线程吗
默认情况下是在同一个主线程中。但可以通过配置android:process=":remote" 属性让 Service 运行在不同的进程。
Service分为本地服务(LocalService)和远程服务(RemoteService):
1、本地服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC,
也不需要AIDL。相应bindService会方便很多。主进程被Kill后,服务便会终止。
2、远程服务为独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,
不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。
按使用方式可以分为以下三种:
- startService 启动的服务:主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService;
- bindService 启动的服务:该方法启动的服务可以进行通信。停止服务使用unbindService
- startService 同时也 bindService 启动的服务:停止服务应同时使用stepService与unbindService
参考:http://www.cnblogs.com/linlf03/p/3296323.html
Service与Activity怎么实现通信
- 通过Binder对象。Activity调用bindService (Intent service, ServiceConnection conn, int flags)方法,得到Service对象的一个引用,这样Activity可以直接调用到Service中的方法,如果要主动通知Activity,我们可以利用回调方法。Binder 相关知识参考:http://blog.csdn.net/boyupeng/article/details/47011383
- 通过广播。Service向Activity发送消息,可以使用广播,当然Activity要注册相应的接收器。比如Service要向多个Activity发送同样的消息的话,用这种方法就更好。
Service里面可以弹出 dialog 或 Toast 吗
可以。getApplicationContext()
Toast必须在UI主线程上才能正常显示,而在Service中是无法获得Acivity的Context的,在service中想显示出Toast只需将show的消息发送给主线程Looper就可以了。此时便可显示Toast。
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), "存Service is runing!",
Toast.LENGTH_SHORT).show();
}
});
Dialog的用法与此类似,但是要多加个权限,在manifest中添加此权限以弹出dialog
<uses-permission Android:name="android.permission.SYSTEM_ALERT_WINDOW" />
dialog.getWindow().setType((WindowManager.LayoutParams.TYPE_SYSTEM_ALERT));
什么时候使用Service?
比如播放多媒体的时候,用户启动了其他的Activity这个时候程序要在后台继续播放。比如检测SD卡上文件的变化。在或者在后台记录你地理位置的改变等等。
说说Activity、Intent、Service是什么关系
一个Activity通常是一个单独的屏幕,每一个Activity都被实现为一个单独的类,这些类都是从Activity基类中继承来的,Activity类显示有视图控件组成的用户接口,并对视图控件的事件做出响应。
Intent的调用是用来进行架构屏幕之间的切换的。Intent是描述应用想要做什么。Intent数据结果中最重要的部分是动作和动作对应的数据,一个动作对应一个动作数据。
Service是运行在后台的代码,不能与用户交互,可以运行在自己的进程,也可以运行在其他应用程序的上下文里。需要通过某一个Activity或其他Context对象来调用。
Activity 跳转到Activity,Activtiy启动Service,Service打开Activity都需要Intent表明跳转的意图,以及传递参数,Intent是这些组件间信号传递的传承者。
怎么在启动一个activity时就启动一个service
在activity的onCreate里写startService(xxx);然后this.finish();结束自己..
这是最简单的方法 可能会有屏幕一闪的现象,如果UI要求严格的话用AIDL把
为什么在Service中创建子线程而不是Activity中
这是因为Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。
Service 与 Thread 的区别
很多时候,你可能会问,为什么要用 Service,而不用 Thread 呢,因为用 Thread 是很方便的,比起 Service 也方便多了,下面我详细的来解释一下。
1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。
2). Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有!
既然这样,那么我们为什么要用 Service 呢?其实这跟 android 的系统机制有关,我们先拿 Thread 来说。Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制。
举个例子:如果你的 Thread 需要不停地隔一段时间就要连接服务器做某种同步的话,该 Thread 需要在 Activity 没有start的时候也在运行。这个时候当你 start 一个 Activity 就没有办法在该 Activity 里面控制之前创建的 Thread。因此你便需要创建并启动一个 Service ,在 Service 里面创建、运行并控制该 Thread,这样便解决了该问题(因为任何 Activity 都可以控制同一 Service,而系统也只会创建一个对应 Service 的实例)。
因此你可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在 Service 里注册 BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread 做不到的。
如何保证 Service 在后台不被 kill
- onStartCommand方法,返回START_STICKY
START_STICKY 在运行onStartCommand后service进程被kill后,那将保留在开始状态,但是不保留那些传入的intent。不久后service就会再次尝试重新创建,因为保留在开始状态,在创建 service后将保证调用onstartCommand。如果没有传递任何开始命令给service,那将获取到null的intent。
START_NOT_STICKY 在运行onStartCommand后service进程被kill后,并且没有新的intent传递给它。Service将移出开始状态,并且直到新的明显的方法(startService)调用才重新创建。因为如果没有传递任何未决定的intent那么service是不会启动,也就是期间onstartCommand不会接收到任何null的intent。
START_REDELIVER_INTENT 在运行onStartCommand后service进程被kill后,系统将会再次启动service,并传入最后一个intent给onstartCommand。直到调用stopSelf(int)才停止传递intent。如果在被kill后还有未处理好的intent,那被kill后服务还是会自动启动。因此onstartCommand不会接收到任何null的intent。
- 提升service优先级
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。
- 提升service进程优先级
Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。Android将进程分为6个等级,它们按优先级顺序由高到低依次是:
1.前台进程( FOREGROUND_APP)
2.可视进程(VISIBLE_APP )
3.次要服务进程(SECONDARY_SERVER )
4.后台进程 (HIDDEN_APP)
5.内容供应节点(CONTENT_PROVIDER)
6.空进程(EMPTY_APP)
当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以使用startForeground 将service放到前台状态。这样在低内存时被kill的几率会低一些。
- onDestroy方法里重启service
service +broadcast 方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service;
- Application加上Persistent属性
- 监听系统广播判断Service状态
通过系统的一些广播,比如:手机重启、界面唤醒、应用状态改变等等监听并捕获到,然后判断我们的Service是否还存活,别忘记加权限啊。
什么是IntentService?有何优点?
IntentService也是一个Service,是Service的子类;IntentService和Service有所不同,通过Looper和Thread来解决标准Service中处理逻辑的阻塞的问题。
优点:Activity的进程,当处理Intent的时候,会产生一个对应的Service,Android的进程处理器现在会尽可能的不kill掉你。
IntentService的使用场景与特点。
IntentService是Service的子类,是一个异步的,会自动停止的服务,很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题
优点:
- 一方面不需要自己去new Thread
- 另一方面不需要考虑在什么时候关闭该Service
onStartCommand中回调了onStart,onStart中通过mServiceHandler发送消息到该handler的handleMessage中去。最后handleMessage中回调onHandleIntent(intent)。
IntentService 作用是什么
IntentService 是继承于 Service 并处理异步请求的一个类,在IntentService 内有一个工作线程来处理耗时操作,启动 IntentService 的方式和启动传统 Service 一样,同时,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制。另外,可以启动 IntentService 多次,而每一个耗时操作会以工作队列的方式在 IntentService 的 onHandleIntent 回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。
IntentService 与 Service的异同
- 直接创建一个默认的工作线程,该线程执行所有的intent传递给onStartCommand()区别于应用程序的主线程。
- 直接创建一个工作队列,将一个意图传递给你onHandleIntent()的实现,所以我们就永远不必担心多线程。
- 当请求完成后自己会调用stopSelf(),所以你就不用调用该方法了。
- 提供的默认实现onBind()返回null,所以也不需要重写这个方法。so easy啊
- 提供了一个默认实现onStartCommand(),将意图工作队列,然后发送到你onHandleIntent()实现。真是太方便了
ContentProvider
参考:http://blog.csdn.net/coder_pig/article/details/47858489
ContentProvider 简介
ContentProvider(内容提供者):为存储和获取数据提供统一的接口。可以在不同的应用程序之间共享数据。Android已经为常见的一些数据提供了默认的ContentProvider
- ContentProvider 为存储和读取数据提供了统一的接口
- 使用ContentProvider,应用程序可以实现 app 间数据共享
- Android内置的许多数据都是使用ContentProvider形式,供开发者调用的(如视频,音频,图片,通讯录等)
请介绍下ContentProvider是如何实现数据共享的
创建一个属于你自己的Content provider或者将你的数据添加到一个已经存在的Content provider中,前提是有相同数据类型并且有写入Content provider的权限。
ContentProvider使用方法
参考:http://blog.csdn.net/juetion/article/details/17481039
Broadcast
注册广播有哪几种方式,有什么区别
- 在应用程序的代码中注册
registerReceiver(receiver,filter);// 注册BroadcastReceiver
unregisterReceiver(receiver);// 取消注册BroadcastReceiver
当BroadcastReceiver更新UI,通常会使用这样的方法注册。启动Activity时候注册BroadcastReceiver,Activity不可见时候,取消注册。
- 在androidmanifest.xml当中注册
<receiver>
<intent-filter>
<action Android:name = "android.intent.action.PICK"/>
</intent-filter>
</receiver>
1)第一种不是常驻型广播,也就是说广播跟随程序的生命周期。
2)第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。
- 静态注册:在AndroidManifest.xml文件中进行注册,当App退出后,Receiver仍然可以接收到广播并且进行相应的处理
- 动态注册:在代码中动态注册,当App退出后,也就没办法再接受广播了
一个 app 被杀掉进程后,是否还能收到广播
静态注册的常驻型广播接收器还能接收广播。
Android引入广播机制的用意?
无序广播、有序广播
本地广播和全局广播有什么差别
全局广播 BroadcastReceiver 是针对应用间、应用与系统间、应用内部进行通信的一种方式。
本地广播 LocalBroadcastReceiver 仅在自己的应用内发送接收广播,也就是只有自己的应用能收到。因广播数据在本应用范围内传播,不用担心隐私数据泄露的问题。 不用担心别的应用伪造广播,造成安全隐患。 相比在系统内发送全局广播,它更高效。
Intent
Intent的使用方法,可以传递哪些数据类型。
通过查询Intent/Bundle的API文档,我们可以获知,Intent/Bundle支持传递基本类型的数据和基本类型的数组数据,以及String/CharSequence类型的数据和String/CharSequence类型的数组数据。而对于其它类型的数据貌似无能为力,其实不然,我们可以在Intent/Bundle的API中看到Intent/Bundle还可以传递Parcelable(包裹化,邮包)和Serializable(序列化)类型的数据,以及它们的数组/列表数据。
所以要让非基本类型和非String/CharSequence类型的数据通过Intent/Bundle来进行传输,我们就需要在数据类型中实现Parcelable接口或是Serializable接口。
参考:http://blog.csdn.net/kkk0526/article/details/7214247
介绍一下Intent、IntentFilter
Context
Context区别
- Activity和Service以及Application的Context是不一样的,Activity继承自ContextThemeWraper.其他的继承自ContextWrapper
- 每一个Activity和Service以及Application的Context都是一个新的ContextImpl对象
- getApplication()用来获取Application实例的,但是这个方法只有在Activity和Service中才能调用的到。那么也许在绝大多数情况下我们都是在Activity或者Service中使用Application的,但是如果在一些其它的场景,比如BroadcastReceiver中也想获得Application的实例,这时就可以借助getApplicationContext()方法,getApplicationContext()比getApplication()方法的作用域会更广一些,任何一个Context的实例,只要调用getApplicationContext()方法都可以拿到我们的Application对象。
- Activity在创建的时候会new一个ContextImpl对象并在attach方法中关联它,Application和Service也差不多。ContextWrapper的方法内部都是转调ContextImpl的方法
- 创建对话框传入Application的Context是不可以的
- 尽管Application、Activity、Service都有自己的ContextImpl,并且每个ContextImpl都有自己的mResources成员,但是由于它们的mResources成员都来自于唯一的ResourcesManager实例,所以它们看似不同的mResources其实都指向的是同一块内存
- Context的数量等于Activity的个数 + Service的个数 + 1,这个1为Application
Application Context 和 Activity Context 异同
Context 的理解
Handler
Handler 原理
Andriod提供了Handler 和 Looper 来满足线程间的通信。Handler先进先出原则。Looper类用来管理特定线程内对象之间的消息交换(MessageExchange)。
Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。
Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
Message Queue(消息队列):用来存放线程放入的消息。
线程:UIthread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。
参考:
Handler、Looper、Message、MessageQueue基础流程分析
Handler消息机制,postDelayed会造成线程阻塞吗?对内存有什么影响?
Handler, Looper的理解
Handler,Message,Looper异步实现机制与源码分析
参考:
Android 消息处理机制(Looper、Handler、MessageQueue,Message)
Handler有何作用?如何使用之(具体讲需要实现什么function)?
Android设计了Handler机制,由Handler来负责与子线程进行通讯,从而让子线程与主线程之间建立起协作的桥梁,使Android的UI更新的问题得到完美的解决。
参考:
Handler、Thread 和 HandlerThread 的区别
Handler 会关联一个单独的线程和消息队列。Handler默认关联主线程(即 UI 线程),虽然要提供Runnable参数 ,但默认是直接调用Runnable中的run()方法。也就是默认下会在主线程执行,如果在这里面的操作会有阻塞,界面也会卡住。如果要在其他线程执行,可以使用 HandlerThread。
HandlerThread继承于Thread,所以它本质就是个Thread。与普通Thread的差别就在于,主要的作用是建立了一个线程,并且创立了消息队列,有自己的looper,可以让我们在自己的线程中分发和处理消息。
android.os.Handler可以通过Looper对象实例化,并运行于另外的线程中,Android提供了让Handler运行于其它线程的线程实现,也是就HandlerThread。HandlerThread对象start后可以获得其Looper对象,并且使用这个Looper对象实例Handler。
参考:
Android中的Thread & HandlerThread & Handler
使用 Handler 时怎么避免引起内存泄漏
一旦Handler被声明为内部类,那么可能导致它的外部类不能够被垃圾回收。如果Handler是在其他线程(我们通常成为worker thread)使用Looper或MessageQueue(消息队列),而不是main线程(UI线程),那么就没有这个问题。如果Handler使用Looper或MessageQueue在主线程(main thread),你需要对Handler的声明做如下修改:
- 声明Handler为static类;
- 在外部类中实例化一个外部类的WeakReference(弱引用)并且在Handler初始化时传入这个对象给你的Handler;
- 将所有引用的外部类成员使用WeakReference对象。
private static class MyHandler extends Handler {
private final WeakReference<HandlerActivity2> mActivity;
public MyHandler(HandlerActivity2 activity) {
mActivity = new WeakReference<HandlerActivity2>(activity);
}
@Override
public void handleMessage(Message msg) {
System.out.println(msg);
if (mActivity.get() == null) {
return;
}
mActivity.get().todo();
}
}
当Activity finish后 handler对象还是在Message中排队。 还是会处理消息,这些处理有必要?正常Activitiy finish后,已经没有必要对消息处理,那需要怎么做呢?解决方案也很简单,在Activity onStop或者onDestroy的时候,取消掉该Handler对象的Message和Runnable。通过查看Handler的API,它有几个方法:removeCallbacks(Runnable r)和removeMessages(int what)等。
/** * 一切都是为了不要让mHandler拖泥带水 */
@Override
public void onDestroy() {
mHandler.removeMessages(MESSAGE_1);
mHandler.removeMessages(MESSAGE_2);
mHandler.removeMessages(MESSAGE_3);
// ... ...
mHandler.removeCallbacks(mRunnable);
// ... ...
}
参考:
AsyncTask
AsyncTask原理
参考:
网络请求是怎么做的异步呢?什么情况下用Handler,什么情况下用AsyncTask
Handler和AsyncTask的区别
这俩类都是用来实现异步的,其中AsyncTask的集成度较高,使用简单,Handler则需要手动写Runnable或者Thread的代码;另外,由于AsyncTask内部实现了一个非常简单的线程池,实际上是只适用于轻量级的异步操作的,一般不应该用于网络操作。(感谢网友指正,AsyncTask 通过重写的方式是可以用于长耗时操作的,而我只考虑了直接使用的情况就说它不适合网络操作,是不对的。)我问他Handler和AsyncTask的区别,一方面是因为他说用AsyncTask联网,因此我认为他对AsyncTask并不熟悉;但更重要的是在我问他实现异步的具体手段的时候,他同时提到了Handler和AsyncTask——用这种“混搭”的使用方式来写联网框架,就算不考虑AsyncTask的可用性,也显得非常怪异,这听起来更像是在“列举Android实现异步操作最常用的类”,而非“讲述实现网络异步操作的具体方式”。也就是说,我听了这句话后开始怀疑他封装过联网框架这件事的真实性。但我只是怀疑,并不确定,因此接着问了我想问的。
参考:
https://www.zhihu.com/question/30804052
AsyncTask的优缺点?能否同时并发100+AsyncTask呢?
参考: