这段时间,上班和下班都在加点做公司两个不同的项目,忙得昏天黑地,也没来得及更新博客,距离上次写博客都过了快接近1个月了吧.最近又累计了一些自定义View的使用,以及开发过程中一些异常出来以及一些开发心得体会.会陆续更新到博客上面.
最近打算把android大部分基础都按照自理的理解整理下,因此建了这个博客分类.因为随着笔者做android的时间越长,项目接触的越多,才意识到自己有些基础很薄弱,知其然知其所以然.感觉自己以前学东西太囫囵吞枣了,一个东西实现了(baidu,goolge做出来了),并不代表所有就会了,特别是随着开发时间增加,基础东西掌握不牢靠,很难自己写一些东西出来(肺腑之言).
今天,想补充一下四大组件中--Activity的相关知识点,相信从新手到老鸟对这个东西都不陌生,有的读者可能会问我,这么初级的东西还有什么值得记录的,相信activity生命周期那幅图以及四大启动模式大家一定滚瓜烂熟了吧,不过在笔者看来,越是简单的东西越能体现出一个开发者的水平.还记得刚做android不久,拿着自己开发的1个APP和一些demo找工作,几乎面试的每家公司都问过android四大组件.为什么这些公司都乐此不疲的问这么初级的东西呢,可能大家会认为几乎没学过android的新手只要百度一下android面试宝典都能回答得上来,能够侃侃而谈几句吧,我当时就是这么想的,不过,其实这恰恰反应了一个开发者接触项目的程度和自身思考深度(而非按部就班的码代码,虽然说每一次开发都是一个码代码的过程 = =b),但是提升往往实在学习和反思过程中,好了,先闲话几句后,接下来的文章,我将言简意赅的记录一些平时我们都遗漏或者不清楚的知识点,当然还会有笔者在具体开发过程中所涉及到的一些应用,对于刚接触android同学来说,拿去面试跟面试官吹吹牛是可以参考的,嘿嘿(*^__^*) .
一.activity生命周期
1.onstart-onstop与onresume-onpause都表示activity被唤醒时候,生命周期的过程.其区别:onStart和onStop表示activity已经可见,但还是没出现在前台,不能被用户看见,在实际开发过程中区别不大,但不能做太耗时的操作(尤其是onresume和onpause),否则影响界面显示的时间,影响用户体验.开发中应用:不能做太耗时的操作,比如像动态注册广播register和unregister,还有一些回收工作.onresume和onpause表示activity已经可见,并且出现在前台.开发中应用:一般就是数据保存和一些动画显示等操作.
(注:在开发中如果一定要在onPause或者onResume做一些联网操作,更新数据那些,建议不要这么做,建议用service+广播去网络连接耗时操作,用广播的形式通知修改UI)
★ 其实在生命周期里面最想强调的是异常生命周期,onSaveInstanceState和onRestoreInsatanceState这两个方法,可能很多才接触android的童鞋对这两个方法都不是很了解,这两个方法是activity在异常情况下终止,会调用onSaveInstanceState来保存数据,在通过Bundle来传递参数,在onRestoreInsatanceState获取Bundle传递过来的参数,并显示.
举个最简单的例子:笔者最近在做一个多线程断点异步下载,在测试过程中,如果用户以非主流的操作导致activity异常关闭(暂时叫他非主流吧,说不准用户用什么手段就让activity异常终止了).那么,我们在本地数据库保存的用户下载信息可能发生错误或者没保存,实际的效果是没保存,当用户再次进入activity会提示用户安装,但安装失败(因为没下完,所以安装时会报解析apk错误),而且没办法继续下载,因为本地数据库可能没保存或者保存错误,导致无法二次继续下载.那么这两个方法就很管用了,直接在这两个方法里进行数据库保存,为了万无一失,如果没发生异常终止,activity是不会调用这两个方法的.所以大可放心.
onSaveInstanceState和onRestoreInsatanceState简单的demo:
执行顺序:activity意外终止-调用onSaveInstanceState保存数据-onCreate重新创建activity(可以获取Bundle传递过来的值)-onStart-最后执行onRestoreInsatanceState(可以获取Bundle传递过来的值)
public class MainActivity extends Activity{ private static final String TAG = "com.max.jsondemo"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //判断系统是否异常终止,如果有就会在这里调onSaveInstanceState保存的数据 if (savedInstanceState != null) { String key = savedInstanceState.getString("value"); Log.i(TAG, "======onCreate====="); } } /** * activity异常终止的时候,把要记录的东西,储存在Bundle里面传递 * 如果没有异常终止,不会执行这个方法 */ @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString("value", "test"); Log.i(TAG, "======onSaveInstanceState====="); } /** * 在onCreate后调用这个方法 */ @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); String key = savedInstanceState.getString("value"); Log.i(TAG, "======onRestoreInstanceState====="); } }
顺带在这里在补充下,除了用户操作不当导致activity异常终止外,资源相关的系统配置发生改变的话,也会触发这两个方法.举个例吧:在做聊天APP通信录索引的时候,弹出手机输入键盘,右方的索引是否被压缩了呢?如果在menifest配置activity中加入这段代码,就不会发生改变了.(注:keyboard表示键盘类型,比如外接键盘,keyboardHidden表示调用了键盘)
android:configChanges="keyboardHidden"
二.启动模式
1.结合实际开发,举例某些案例需要用到的启动模式
singleTop:笔者在做聊天APP的时候,用于聊天界面.配合onNewIntent()方法--主要用于通过notification通知新消息,点击唤醒chatactivity;onActivityResult()--配合startActivityForResult()返回聊天记录界面,更新聊天列表(因为接受了新消息,因此聊天列表用户顺序也会跟着发生改变)使用.
singleTask:笔者刚接触android的时候,很喜欢用这个方式去管理activity,感觉栈里面只有一个不用去想那么复杂,其实不然,而且所有activity启动模式都用它的话,管理起来很麻烦.并且如果是启动页面是singleTask的话,那么会出现BUG--用户按home键返回桌面的时候,每次重新进入APP,都回不到之前退出的数据,都是会重启整个APP
singleInstance:表示多个不同应用调用一个activity实例,例如:浏览器,笔者开发用得少,第三方调用的话,微信用的比较多,后面会说.
2.onNewIntent():
主要是singleTop和singleTask这两种启动模式,如果在activity栈中都已存在实例,那么调用实例返回栈顶的时候,就会调用这个方法,不过,singleTask返回栈顶会移除再其之上的其他activity实例(栈的特性后进先出)
上面已经提到过了,其实我们在开发过程中很容易遗漏这个方法,其实这个方法很方便,实际用起来可以少了很多不必要的判断.
3.taskAffinity在menifest的配置:通常和allowTaskReparenting或singleTask一起使用
android:taskAffinity="com.max.test"taskAffinity表示一个新的栈名.
其实,这个很少用到不过很有用,给大家简单举个例子就明白了:A代表一个APP,B代表微信,C代表B中分享朋友圈的activity并且c的menifest配置了taskAffinity并且allowTaskReparenting=true;那么B启动时候,C就在B的栈中了.
三.menifest的activity配置过滤规则
activity和service以及broadcast配置过滤规则都类似,只是简单说一下action,category和data三个过滤规则的区别:
1.action:Intent中必须有一个action和menifest中的action中的任意一个匹配
2.category:Intent中可以没有一个category,如果有那么和menifest中的category中的任意一个匹配,
3.data:跟action是类似的,不过Intent要调用setDataAndType的方法来指定属性和值.