他山之石可以攻玉:
https://blog.csdn.net/luyuqin0115/article/details/79815560 转载于 luyuqin0115
https://blog.csdn.net/yuzhiqiang_1993/article/details/72675497 转载于 喻志强
注:本文借鉴了上述两个blog中部分内容,作者若感到有侵犯版权的话,请及时与我联系,我会尽快修改,谢谢。
Activity是安卓四大组件之一,应该是我们用的最多的一个组件了。它主要负责的是提供界面用于和用户交互,使用户可以在界面上进行点击、滑动等操作。可以理解为MVC中的V(View)。
基本上面试都会问到以下几个问题:
onCreate() //onCreate是Activity被创建的时候调用,是生命周期的第一个方法,我们新建的Activity几乎都会重写这个方法,在这里我们可以做一些初始化操作等,如加载布局文件。
onStart() //表明Activity正在启动,此时处于用户可见状态,但是并不能与用户交互
onResume() //表明Activity已经处于前台状态,可以与用户交互了。此时Activity就处于Running状态了
----------------------------------------------以上 为 Activity 启动过程------------------------------------------------------------------------------
onPause() //表明Activity处于paused状态,此时Activity无法与用户交互
onStop() //一般在onPause()后执行,此时Activity处于不可见状态
----------------------------------------------以上 为退出但不销毁Activity时执行的过程,如点击HOME键-------------------------------
onRestart() //表明Activity重新启动,从不可见变为可见状态
----------------------------------------------以上 为重新回到Activity时执行的方法-------------------------------------------------------------
onDsetory() //表明Activity正在被销毁,是整个生命周期方法中的最后一个方法,在该方法中我们可以做一些资源回收的工作。
----------------------------------------------以上 为销毁Activity时执行的方法-------------------------------------------------------------------
上述操作为正常时候的生命周期,如果系统内存不足时导致要对Activity进行强行回收,此时生命周期就不会正常执行了。
我们可以使用onSaveInstanceState这个方法进行一些数据保存的工作,然后在onCreate或onRestoreInstanceState方法中恢复数据。
1.standard
默认的启动模式,每次启动Activity的时候都会创建一个新的实例。不会复用Activity,对内存消耗较大。
2.singleTop
栈顶复用模式,如果要创建的Activity已经在栈顶的话,那么不会重新创建,直接复用,否则,仍然会重新创建。
适合接受通知启动的内容页面,例如:某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。
3.singletask
栈内复用模式,如果要创建的Activity在栈内已经存在的话,不会重新创建,直接复用栈内存在的Activity,且会调用onNewIntent()方法,并且将该Activity以上的所有的Activity销毁。
适合做程序的入口点,例如浏览器的主界面,不管从多少个应用启动浏览器,只会启动主界面一次,其余的情况都走onNewIntent,并且会清空主界面上面的其他页面
4.singleInstance
单一实例,独享一个任务栈,整个手机操作系统里面只有一个实例存在。用的较少。
适合需要与程序分离的页面
例如:闹铃提醒,将闹铃提醒与闹铃设置分离
前台>可见>服务>后台>空
前台:包含正在处于和用户交互的Activity或者是前台Activity绑定了service
可见:activity处于可见状态但不可与用户进行交互
服务:包含一个service服务的进程
后台:处于不可见的状态下(比如按了home键)
空:没有活跃的组件 只是为了缓存的目的存在的,随时都可能被系统杀掉
Activity提供了onSaveInstanceState()回调方法,这个方法可以保证在活动回收之前被调用,
onSaveInstanceState()方法会携带一个Bundle类型的参数,Bundle提供了一些方法用于保存数据
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("data", "保存数据");
}
保存的数据在onCreate()方法中可获取
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState!=null){
String data = savedInstanceState.getString("data");
}
}
Service是一种能在后台执行耗时任务的没有界面显示的组件。需要注意的是Service和BroadCastReceiver都是运行在主线程的,所以,Service本身不能做耗时操作,而是通过子线程去完成!
详细可以看这篇博客service和thread的区别
讲的非常仔细。
在这里做个总结:
Thread和Service实际上是没有任何关系,只不过因为字面上的意思,我们可能会误解为Service可以执行耗时任务的,实际上Service是运行在主线程上的,也就是说,Service本身并不能做耗时操作,一般都是在Service中启线程去执行耗时任务。
Thread是程序执行的最小单元,是独立与Activity运行的,也就是说,如果我们在Activity中启线程去执行任务,即使这个activity被销毁了,该任务也会继续执行。
而Service是Android中一种机制,在一些运行在后台的不需要界面的地方可以使用Service。
onbind/onCreate/onStartCommand/ondestory
onBind(): 该方法返回的是一个IBinder接口,当我们使用bindService的时候才会被调用
onCreate(): 服务首次创建时调用,注意,只有service第一个被创建时才会调用
onStartCommand(): 每次调用startService的时候都会执行该方法,该方法有一个int类型的返回值
分别是:START_STICKY、START_NOT_STICKY、START_REDELIVER_INTENT、START_STICKY_COMPATIBILITY。
START_STICKY:“粘性的”,如果service进程被意外kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务
START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
onDestory(): 服务销毁时调用,在这里可以做一些资源回收操作。
startService 和 bindService
startService
1.定义一个类继承自Service
2.在清单配置文件中声明
3.使用Context.startService(Intent)启动Service
4.调用Context.stopService(Intent)停止Service
Intent intent = new Intent();
intent.setClass(activity, UpdateApkService.class);
activity.startService(intent);//开启服务
activity.stopService(intent);//停止服务
执行startService时,Service会经历onCreate->onStartCommand。当执行stopService时,直接调用onDestroy方法。调用者如果没有stopService,那么即使Activity被销毁了,Service也会继续执行,下次调用者再起来仍然可以stopService。
bindService
1.创建一个类继承自Service,并在类中创建一个实现IBinder接口的实例对象并提供公共方法。
/*这里定义一个类 用于返回Service*/
public class MyBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
/*提供一个公共方法*/
public Date getTime(){
return new Date();
}
2.在onBind()中返回自定义的IBinder实例
private MyBinder myBinder=new MyBinder();
@Override
public IBinder onBind(Intent intent) {
return myBinder;
}
3.在需要调用的地方,从onServiceConnected中获取IBinder实例并调用公共方法
sc = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("aaa","onServiceConnected");
MyService.MyBinder myBinder = (MyService.MyBinder) service;
Date date = ((MyService.MyBinder) service).getService().getTime();
Log.i("aaa",date.toString());
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
Intent intent = new Intent(this, MyService.class);
bindService(intent, sc, BIND_AUTO_CREATE);
执行bindService时,Service会经历onCreate->onBind。这个时候调用者和Service绑定在一起。调用者调用unbindService方法或者调用者Context不存在了(如Activity被finish了),Service就会调用onUnbind->onDestroy。这里所谓的绑定在一起就是说两者共存亡了。
startService():开启Service,调用者退出后Service仍然存在。
bindService():开启Service,调用者退出后Service也随即退出。
四大组件之一,在Android中,Broadcast是一种广泛运用在应用程序之间传输信息的机制,Android中我们要发送的是一个intent,intent可易携带我们需要传输的数据。
广播的使用场景
1.同一app中不同组件之间的数据传递
2.不同app之间组件的数据传递
广播的种类
1.普通广播 Context.sendBroadcast
是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎同时都会在同一时刻受到这条广播消息,这种广播的效率比较高,但同时也意味着它是无法被截断的
2.有序广播 Context.sendOrderedBroadcast 根据优先级传播,优先级高的接收器可以阻止继续传播或修改数据
是一个同步执行的广播,广播发出后,同一时刻只有一个广播接收器能够受到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所有此时的广播接收器是有先后顺序的,优先级高的先受到广播,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法接收到广播消息了
3.本地广播
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
lbm.sendBroadcast(new Intent(LOCAL_ACTION));
只会在应用内部传播,相对来说数据安全。
广播的注册方式
1.静态注册 在清单配置文件中声明,即使进程被杀死,该广播仍然运行
2.动态注册 在代码中注册,受activity生命周期的影响。
MyReceiver receiver = new MyReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.MY_BROADCAST");
registerReceiver(receiver, filter);
内部实现机制
1.自定义BroadcastReceiver,重写onReceive()方法
2.通过Binder机制向AMS(Activity Manager Service)进行注册
3.广播发送者通过Binder机制向AMS发送广播
4.AMS查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到BroadCastReceiver相应的消息循环队列中
5.消息循环执行拿到广播,回调BroadCastReceiver中的onReceive()方法。
LocalBroadcastManager
1.使用LocalBroadcastManager发送的广播只能在app内部传播,因此数据传输很安全。
2.比系统广播更加高效,底层是通过Handler发送message实现的。
创建一个广播接收器,新建一个类让它继承BroadCast,并重写onReceive()方法就行
使用场景:
1.App全局监听,这种主要用于在AndroidManifest中静态注册的广播接收器,一般我们在收到该消息后,需要做一些相应的动作,而这些动作与当前App的组件,比如Activity或者Service的是否运行无关,比如我们在集成第三方Push SDK时,一般都会添加一个静态注册的BroadcastReceiver来监听Push消息,当有Push消息过来时,会在后台做一些网络请求或者发送通知等等。
2.组件局部监听,这种主要是在Activity或者Service中使用registerReceiver()动态注册的广播接收器,因为当我们收到一些特定的消息,比如网络连接发生变化时,我们可能需要在当前Activity页面给用户一些UI上的提示,或者将Service中的网络请求任务暂停。所以这种动态注册的广播接收器适合特定组件的特定消息处理
动态注册:在代码中注册,动态广播最好在Activity 的 onResume()注册、onPause()注销,在onResume()注册、onPause()注销是因为onPause()在App死亡前一定会被执行,从而保证广播在App死亡前一定会被注销,从而防止内存泄露
非 常驻系统,跟随组件的生命周期变化而变化,组件结束,广播结束。
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.ACTION_SHUTDOWN");
registerReceiver(new CommonBroadcastReceiver(),intentFilter);
静态注册:在AndroidManifest.xml中注册
常驻系统,不受组件的生命周期影响,即便应用退出,广播还是可以被接受,耗电,占用内存
继承BroadcastReceiver,重写onReceive()方法。
通过Binder机制向ActivityManagerService注册广播。
通过Binder机制向ActivityMangerService发送广播。
public abstract void sendBroadcast(Intent intent);
1
ActivityManagerService查找符合相应条件的广播(IntentFilter/Permission)的
BroadcastReceiver,将广播发送到BroadcastReceiver所在的消息队列中。
BroadcastReceiver所在消息队列拿到此广播后,回调它的onReceive()方法。
Android Binder是用来做进程通信的,Android的各个应用以及系统服务都运行在独立的进程中,它们的通信都依赖于Binder。
Intent传递数据大小的限制大概在1M左右,超过这个限制就会静默崩溃。处理方式如下:
进程内:EventBus,文件缓存、磁盘缓存。
进程间:通过ContentProvider进行款进程数据共享和传递。
ContentProvider管理android以结构化方式存放的数据。他以相对安全的方式封装数据并且提供简易的处理机制。Content provider提供不同进程间数据交互的标准化接口。保证被访问数据的安全性。内容提供器可以选择只对哪一部分数据进行共享,从而保证我们程序中的隐私数据不会有泄漏的风险。
ContentResolver中提供了一系列的方法用于对数据进行CRUD,内容URI给内容提供器ContentProvider中的数据建立了唯一标识符,ContentObserver监听Uri数据的变化
①ContentProvider:管理数据,提供数据的增删改查操作,数据源可以是数据库、文件、XML
网络等。ContentProvider为这些数据提供了统一的接口,可以用来做进程间数据共享
②ContentResolver:ContentResolver可以不同的URI操作不同的ContentProvider中的数据库,外部进程可以通过ContentResolver 与ContentProvider进行交互
③ContentObserver :观察ContentProvider中的数据变化,并将变化通知给外界。