Android知识点总结(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chaoyangsun/article/details/80582571

Activity生命周期和启动模式

onPause操作里为什么不能做耗时操作

android在onPause里面不应该做耗时操作,因为跳转页面时,先调用当前页面的onPause,再去调用创建,所以这里如果做了耗时操作,就会出现卡顿!当然onStart onResume onStop都不应该做耗时操作,否则会造成页面卡顿!

onSaveInstanceState、onRestoreInstanceState状态存储相关

   @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指定的任务栈中运行:

<!--将SecondActivity做如下设置-->
<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和隐式启动activity

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>

在代码中隐式调用的时候:

  • 必须设置action
  • <intent-filter>里面必须设置<category android:name="android.intent.category.DEFAULT" /> ,代码中可以不设置category
  • 如果<intent-filter>里面设置了data,代码中就必须匹配

关于data:data有两部分组成mimeType和URI,前者指媒体类型如imgge/jpeg、videl/*等,后者包含的数据比较多,其结构如下:

<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]

URI示例:

http://www.baidu.com:80/search/info
content://com.example.priject:200/folder/subfolder/etc
  • scheme指URI的模式,如http、file、content等
  • host指URI的主机名,如www.baidu.com
  • port指URI的端口号
  • path、pathPrefix、pathPattern表示路径信息

data的书写有两种情况,作用是一样的:

<intent-filter>
  ...
   <data android:mimeType="text/plain" android:scheme="file"/>
</intent-filter>
//或
<intent-filter>
  ...
   <data android:mimeType="text/plain"/>
   <data android:scheme="http"/>
   <data android:host="www.baidu.com"/>
</intent-filter>

如果没有指定URI,默认schema为content或者file,前面的<intent-filter>例子,在代码中的匹配设置如下:

Intent intent = new Intent();
intent.setAction("custom.action");
intent.addCategory("custom.d");
intent.setDataAndType(Uri.parse("file://abc"), "text/plain");
startActivity(intent);

IPC相关

进程间通信方式有很多如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分别为279852802328042

如果不做处理,应用内多进程会带来如下问题:

  • 静态成员和单例模式失效
  • 线程同步机制失效
  • SharedPreferences可靠性下降
  • Application会多次创建

SharedPreferences不支持多进程同时操作,不同的进程拥有不同的虚拟机和Application,不同的虚拟机在内存分配上有不同的地址空间,所以多进程不支持通过内存来共享数据!

Serializable和Parcelable的区别

Serializable是java中的序列化接口,Parcelable是android中的序列化方式,更适合android平台,效率较高;Parcelable主要用在内存序列化上,如果是将对象序列化到存储设备中或则将对象序列化后通过网络传输建议使用Serializable!

Binder

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的工作机制!

阅读更多
换一批

没有更多推荐了,返回首页