android在onPause里面不应该做耗时操作,因为跳转页面时,先调用当前页面的onPause,再去调用创建,所以这里如果做了耗时操作,就会出现卡顿!当然onStart onResume onStop都不应该做耗时操作,否则会造成页面卡顿!
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.e(TAG, "onSaveInstanceState");
outState.putString("extra_test", "test...");
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.e(TAG, "onRestoreInstanceState");
String test = savedInstanceState.getString("extra_test");
Log.e(TAG, "onRestoreInstanceState: " + test );
}
在onCreate()、onRestoreInstanceState里面都可以获取存储状态,建议在onRestoreInstanceState里面,因为只要调用onRestoreInstanceState,代表savedInstanceState必定有值,在onCreate里面需要判空
四种启动模式:standard、singleTop、singleTask和singleInstance.
singleTop模式,具有栈顶复用功能;
启动singleTask模式的activity,具有clearTop的功能即会清空它之上的栈内的activity;
首次启动singleInstance模式的activity时会创建一个栈!现启动三个launchMode为singleInstance的activity(MainActivity SecondActivity ThirdActivity),运行命令adb shell dumpsys activity activities
获取activity的任务栈:
上图表示三个activity分别在id为34、33、32,名称为”comexamplle.scy.myaplication”的任务栈中!默认情况下,所有activity的任务栈的名称都是应用的包名,区别是它们的id不一样!
如果不使用singleInstance,怎么实现多个任务栈?这就要使用TaskAffinity
属性,它用来标识任务栈的名字。该属性和singleTask启动模式或者allowTaskReparenting属性配合使用。
TaskAffinity与singleTask配合使用,启动的activity在其TaskAffinity指定的任务栈中运行:
<activity
android:name=".SecondActivity"
android:launchMode="singleTask"
android:taskAffinity="new.stack.name"
/>
从MainActivity跳转SecondActivity后,查看任务栈:
可以看到SecondActivity所在的任务栈的名称为“new.stack.name” id为39!
TaskAffinity与allowTaskReparenting配合使用,它的作用主要是activity的迁移,如现有两个应用A和B,A启动了B的activity C(allowTaskReparenting属性为true),按home键回到桌面,然后再点击B,这个时候,不会显示B的MainActivity,而是直接显示C,C从A的任务栈进入了B的任务栈!
IntentFilter中的过滤信息有action、category、data,示例:
<intent-filter>
<action android:name="custom.action" />
<category android:name="custom.d" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
intent-filter>
在代码中隐式调用的时候:
,代码中可以不设置category关于data:data有两部分组成mimeType和URI,前者指媒体类型如imgge/jpeg、videl/*
等,后者包含的数据比较多,其结构如下:
:// :/ [||]
URI示例:
http://www.baidu.com:80/search/info
content://com.example.priject:200/folder/subfolder/etc
data的书写有两种情况,作用是一样的:
...
"text/plain" android:scheme="file"/>
//或
...
"text/plain"/>
"http"/>
"www.baidu.com"/>
如果没有指定URI,默认schema为content或者file,前面的
Intent intent = new Intent();
intent.setAction("custom.action");
intent.addCategory("custom.d");
intent.setDataAndType(Uri.parse("file://abc"), "text/plain");
startActivity(intent);
进程间通信方式有很多如Intent、基于Binder的AIDL和Messager、Socket、ContentProvider等!开启多进程非常简单,只需给四大组件设置android:process
属性即可:
<activity
android:name=".MainActivity"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
intent-filter>
activity>
<activity
android:name=".SecondActivity"
android:process="com.example.scy.myapplication">
activity>
<activity
android:name=".ThirdActivity"
android:process=":third" />
启动界面,运行命令adb shell ps | grep com.example.scy.myapplication
(com.example.scy.myapplication是应用包名)查看当前应用的进程:
u0_a680 27985 661 751316 41944 SyS_epoll_ 00000000 S com.example.scy.myapplication
u0_a680 28023 661 746876 40512 SyS_epoll_ 00000000 S com.example.scy.myapplication.second
u0_a680 28042 661 761216 40672 SyS_epoll_ 00000000 S com.example.scy.myapplication:third
//进程id分别为27985、28023、28042
如果不做处理,应用内多进程会带来如下问题:
SharedPreferences不支持多进程同时操作,不同的进程拥有不同的虚拟机和Application,不同的虚拟机在内存分配上有不同的地址空间,所以多进程不支持通过内存来共享数据!
Serializable是java中的序列化接口,Parcelable是android中的序列化方式,更适合android平台,效率较高;Parcelable主要用在内存序列化上,如果是将对象序列化到存储设备中或则将对象序列化后通过网络传输建议使用Serializable!
Binder结构图如下:
Binder是一种IPC通信方式,是客户端(可以获取binder相关引用)和服务端(创建binder)通信的媒介,当binderService时,服务端返回一个包含Service业务的Binder对象,客户端就可以通过这个对象获取相关服务,这里的服务包括普通服务和基于AIDL的服务。
普通服务与Binder
//服务端 在Service的onBind()方法中返回Binder类型的实例
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
public void methodInService(){
Toast.makeText(getApplicationContext(), "服务的方法", Toast.LENGTH_SHORT).show();
}
/*
* 该类用于在onBind方法执行后返回的对象
* 1、该对象可以对外提供服务里的方法
* 2、该对象也可以直接对外暴露service实例
*/
public class MyBinder extends Binder{
public void getServiceMethod(){
methodInService();
}
public Service getService(){
return MyService.this;
}
}
}
/*
* 客户端 创建ServiceConnection类型实例 当执行到onServiceConnected回调时,可通过
* IBinder实例得到Service相关方法或实例对象,这样可实现client与Service的连接
*/
private MyService.MyBinder myBinder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
//binder是服务里面onBind()方法返回的对象
myBinder = (MyService.MyBinder) binder;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bindservice://开启服务
Intent intent = new Intent(this, MyService.class);
bindService(intent, connection, BIND_AUTO_CREATE);
break;
case R.id.btn1://直接调用服务里方法
if (myBinder != null){
myBinder.getServiceMethod();
}
break;
case R.id.btn2://获取服务的实例
if (myBinder != null){
MyService service = (MyService) myBinder.getService();
service.methodInService();
}
break;
}
}
基于AIDL的服务
Binder主要用在Service中,包括AIDL和Messager,Messager底层其实也是AIDL。这里不是要介绍AIDL的IPC通信方式,只是通过AIDL分析Binder的工作机制!