activity之相关复习

 

11.Activity几种情况生命周期?
12.ActA与 ActB互相跳转生命周期情况?
21.旋转屏幕Act执行的生命周期方法?
22.Android禁止屏幕旋转 & 旋转屏幕时保持Act内容?

---------

一.activity相关
• Activity的四种启动模式对比;

   Activity之间的通信方式
• Activity与Fragment之间生命周期比较
• 横竖屏切换时Activity生命周期 + Activity上有Dialog时按Home键时生命周期
• Activity各种情况下的生命周期

1.1 两个Activity跳转时必然会执行是哪些方法?
定义A和B。完整顺序: A调用onCreate() -> onStart() -> onResume()。
当A启动B时:
A(onPause() )-> B( onCreate() -> onStart() -> onResume() )-> A(onStop());
当A再次回到前台时:
B(onPause())-> A (调用onRestart()方法 ---> onStart()方法 ---> onResume())-> B (onStop() -> onDestory());
弹出Dialog时,调用onCreate()方法 ---> onStart()方法 ---> onResume()方法。

1.2 前台切换到后台,然后再回到前台,Activity生命周期回调方法。弹出Dialog,生命值周期回调方法。
前台切换到后台:onPause()->onStop()
切回来时分2种情况:
1)如果正常切换回来,会走onRestart()->onStart()->onResume()
2)如果被系统内存紧急被回收了,那么回来会重新走一次生命周期。
    弹出dialog: 如果dialog是自身Activity弹出来的,则不会走生命周期。

1.3.Activity上有Dialog的时候按Home键时的生命周期
和正常的Activity运行时点击Home键时的生存周期,只是我们被AlertDialog这个组件所迷惑。
1.4.横竖屏切换的时候,Activity 各种情况下的生命周期
1)没在清单中为activity配置android:configChanges属性时:
启动:onCreate->onStart->onResume
横竖屏切换后(原来活动会销毁然后再重建): onPause->onStop->onDestroy->onCreate->onStart->onResume
在活动销毁重建的过程还会调用onSaveInstanceState和onRestoreInstanceState来保存和恢复数据
2)清单配置android:configChanges属性(横竖屏切换时不重建活动)时:
启动:onCreate->onStart->onResume
横竖屏切换时活动不重建,但是会回调onConfigurationChanged()
注意由于这里没有发生活动的销毁和重建,所以不调用 onSaveInstanceState() 和 onRestoreInstanceState()。

1.5.activity的四种启动模式
1)标准模式(standard)(默认);
2)栈顶复用模式(singleTop);
3)栈内复用模式(singleTask)FLAG_ACTIVITY_NEW_TASK;
4)单例模式(singleInstance)。
singleTask和Intent.FLAG_ACTIVITY_CLEAR_TOP区别:
1)singleTask会销毁目标Activity之上的Activity并复用已经存在的目标Activity(调用onNewIntent),
2)但Intent.FLAG_ACTIVITY_CLEAR_TOP会连同目标Activity一起销毁,然后重新创建目标Activity。
FLAG_ACTIVITY_CLEAR_TOP所有位于其上层的Activity都要移除。
singleTask是写死在Manifest文件中的,如果觉得太笨重,
singleTask =Intent.FLAG_ACTIVITY_SINGLE_TOP+Intent.FLAG_ACTIVITY_CLEAR_TOP一样的效果。

1.6 Activity状态保存于恢复
1.保存本地实现数据存储
2.保存更多临时的信息,而此信息又没必要写入到持久化的存储中:
重写onSaveInstanceState(Bundle bd) 把保存信息放到Bundle对象里,之后onRestoreInstanceState和onCreate()读取出来。
这有两点注意:
1)onRestoreInstance只有在Bundle不为空时才会回调,而在onCreate()中是通过判空操作判断是否有需要恢复的状态的。
2)在重写onRestoreInstanceState方法时,应先调用super(),这样由系统负责保存的部分才能够恢复。
两个调用时机?
onSaveInstanceState可能在onPause()之前保存,在onPause()和onStop()间保存状态,其它情况不会保存状态。
onRestoreInstanceState()它是在onStart()和onResume()之间被调用的。

一.Activity的生命周期

11.两个Activity之间跳转时必然会执行的是哪几个方法?
一般情况下比如说有两个activity,分别叫A,B。
当在A 里面激活B 组件的时候, A会调用onPause()方法,然后B调用onCreate() ,onStart(), onResume()。
如果这个时候B覆盖了A的窗体, A会调用onStop()方法。
如果B是个透明的窗口,或者是对话框的样式, 就不会调用A的onStop()方法。
如果B已经存在于Activity栈中,B就不会调用onCreate()方法。

12.Activity的几种情况的生命周期?

 11.打开APP,进入ActivityA?

ActA --onCreate();
ActA --onStart();
ActA --onResume();

12.ActivityA跳转到ActivityB
ActA: onPause();
ActB: onCreate();
ActB: onStart();
ActB: onResume();
ActA: onStop();

13.ActivityB按back键返回?
ActB: onPause();
ActA: onRestart();
ActA: onStart();
ActA: onResume();
ActB: onStop();
ActB: onDestroy();

14.ActivityA按back键返回
ActA: onPause();
ActA: onStop();
ActA: onDestroy();

1.3 Activity的生命周期全面分析

  用户正常使用情况下的生命周期 & 由于Activity被系统回收或者设备配置改变导致Activity被销毁重建情况下的生命周期。

1.1.1 典型情况下的生命周期分析

Activity的生命周期和启动模式

  1. Activity第一次启动:onCreate->onStart->onResume。
  2. Activity切换到后台( 用户打开新的Activity或者切换到桌面) ,onPause->onStop(如果新Activity采用了透明主题,则当前Activity不会回调onstop)。
  3. Activity从后台到前台,重新可见,onRestart->onStart->onResume。
  4. 用户退出Activity,onPause->onStop->onDestroy。
  5. onStart开始到onStop之前,Activity可见。onResume到onPause之前,Activity可以接受用户交互。
  6. 在新Activity启动之前,栈顶的Activity需要先onPause后,新Activity才能启动。所以不能在onPause执行耗时操作。
  7. onstop中也不可以太耗时,资源回收和释放可以放在onDestroy中。

1.1.2 异常情况下的生命周期分析

1 系统配置变化导致Activity销毁重建

例如Activity处于竖屏状态,如果突然旋转屏幕,由于系统配置发生了改变,Activity就会被销
毁并重新创建。
在异常情况下系统会在onStop之前调用onSaveInstanceState来保存状态。Activity重新创建后,会在onStart之后调用onRestoreInstanceState来恢复之前保存的数据。

保存数据的流程: Activity被意外终止,调用onSaveIntanceState保存数据-> Activity委托Window,Window委托它上面的顶级容器一个ViewGroup( 可能是DecorView) 。然后顶层容器在通知所有子元素来保存数据。

这是一种委托思想,Android中类似的还有:View绘制过程、事件分发等。

系统只在Activity异常终止的时候才会调用 onSaveInstanceState 和onRestoreInstanceState 方法。其他情况不会触发。

2. 资源内存不足导致低优先级的Activity被回收
三种Activity优先级:前台- 可见非前台 -后台,从高到低。
如果一个进程没有四大组件,那么将很快被系统杀死。因此,后台工作最好放入service中。

android:configChanges="orientation" 在manifest中指定 configChanges 在系统配置变化后不重新创建Activity,也不会执行 onSaveInstanceState 和onRestoreInstanceState 方法,而是调用 onConfigurationChnaged 方法。
附:系统配置变化项目

configChanges 一般常用三个选项:

    1. locale 系统语言变化
    2. keyborardHidden 键盘的可访问性发生了变化,比如用户调出了键盘
    3. orientation 屏幕方向变化

14.Android禁止屏幕旋转&旋转屏幕时保持Activity内容?

对android:configChanges属性,一般认为有以下几点:
1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次

2、设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次

3、设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法

但是,自从Android 3.2(API 13),
在设置Activity的android:configChanges="orientation|keyboardHidden"
后,还是一样会重新调用各个生命周期的。因为screen size也开始跟着设备的横竖切换而改变。
所以,在AndroidManifest.xml里设置的MiniSdkVersion和 TargetSdkVersion属性大于等于13的情况下,
如果你想阻止程序在运行时重新加载Activity,除了设置"orientation",你还必须设置"ScreenSize"。
解决方法:
AndroidManifest.xml中设置android:configChanges="orientation|screenSize“

(2)在manifest.xml文件设置android:configChanges="orientation|keyboardHidden|screenSize"切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法。
需注意的是,在4.0以后的版本需要加上ScreenSize, 不然不会执行onConfigurationChanged方法.
执行顺序:
onCreate
onStart
onResume
onConfigurationChanged();

1.在应用中固定屏幕方向。
 在AndroidManifest.xml的activity中加入:android:screenOrientation=”landscape”属性即可(landscape是横向,portrait是纵向)。

2.随屏幕旋转时,不重新调用onCreate。
当将手机屏幕旋转时,系统会被强制重置启动onCreate方法。
1)修改AndroidManifest.xml。
在activity属性中加入:android:configChanges=”orientation|keyboardHidden| screenSize”
android:configChanges,这个方法主要是负责列出清单,当清单上用户指定的设置改变时,Activity会自己处理这些变化。
orientation,屏幕界面旋转(可能是用户手动旋转的),
【注意:如果你的开发API等级等于或高于13,你还需要设置screenSize,因为screenSize会在屏幕旋转时改变】
keyboardHidden,键盘辅助功能改变;

2)在相对应的Activity中继承重写onConfigurationChanged方法,这个方法将会在我们的应用发生变化时,让我们能随心所谓地进行监听处理。
public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
 if (newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE) {
  // Nothing need to be done here
  } else {
   // Nothing need to be done here
  }
}
如果在两个if中写其他操作,比如setContentView(),那么当旋转屏幕时,就会重新调用新的view,并且需要重新设定view的内容,而当前的view内容没有保存。什么也不写的话,当前view中的内容会随着屏幕转动而转动,不影响操作,这是我想要的结果。

21.旋转屏幕Activity执行的生命周期方法?

很多时候会用到屏幕旋转时需要对一些数据进行保存,例如当横竖屏区切换时要保存先前屏幕的一些数据和状态,那么在旋转屏幕的时候都会调用activity生命周期的哪些方法呢,运行得出了如下结果:
(1)如果销毁当前的Activity,那么就要重写Activity的两个方法
 onSaveInstanceState()保存数据 和 onRestoreInstanceState()还原数据
执行顺序:
onCreate();
onStart();
onResume()
onPause
onSaveInstanceState
onStop
onDestroy

onCreate
onStart
onRestoreInstanceState
onResume

在灭屏时调用的方法
onPause
onSaveInstanceState
onStop

屏幕重新唤醒时调用的方法:
onRestart
onStart
onResume

退出程序时调用的方法:
onPause
onStop
onDestroy  

二.Handle相关:
Handler 工作流程基本包括 Handler、Looper、Message、MessageQueue 。Message 负责消息的搭载,里面有个target用于标记消息,obj用于存放内容,Handler 负责消息的分发和处理。
一般在开发中是怎么使用 Handler 的?
官方不允许在子线程中更新 UI,所以我们经常会把需要更新 UI 的消息直接发给处理器 Handler,通过重写 Handler 的handleMessage()方法进行 UI 的相关操作。
Handle使用中就没什么需要注意的吗?
有,Handler 如果设置为私有变量的话,Android Studio 会报警告,提示可能会造成内存泄漏,这种情况可以通过设置为静态内部类 + 弱引用,或者在onDestroy()方法中调用Handler.removeCallbacksAndMessages(null)即可避免
Handler 整体工作流程浅析分为以下四个步骤:
异步通信准备 => 消息入队 => 消息循环 => 消息处理
A:异步通信准备
I:假定是在主线程创建 Handler,则会直接在主线程中创建处理器对象Looper、消息队列对象MessageQueue和 Handler 对象。
需要注意的是,Looper和MessageQueue均是属于其创建线程的。
II:Looper对象的创建一般通过Looper.prepareMainLooper()和Looper.prepare()两个方法,而创建Looper对象的同时,将会自动创建MessageQueue。
III:创建好MessageQueue后,Looper将自动进入消息循环。此时,Handler自动绑定了主线程的Looper和MessageQueue。
B:消息入队
工作线程通过Handler发送消息Message到消息队列MessageQueue中,消息内容一般是 UI 操作。发送消息一般都是通过Handler.sendMessage(Message msg)和Handler.post(Runnabe r)两个方法来进行的。而入队一般是通过MessageQueue.enqueueeMessage(Message msg,long when)来处理。
C:消息循环
主要分为「消息出队」和「消息分发」两个步骤,Looper会通过循环取出消息队列MessageQueue里面的消息Message,并分发到创建该消息的处理者Handler。如果消息循环过程中,消息队列MessageQueue为空队列的话,则线程阻塞。
D:消息处理
Handler接收到Looper发来的消息,开始进行处理。

android消息机制?
消息机制指Handler、Looper、MessageQueue、Message之间如何工作的。
• handler是用来处理消息和接收消息的中间者,handler的创建会伴随着handler中产生looper和MessageQueue,handler依赖于looper,looper依赖于MessageQueue,所以在子线程中使用handler抛出异常是因为子线程中没有初始化looper对象,而主线程中looper是在ActivityThread中已经初始化过了,所以能直接在主线程中能拿到Handler。
• Looper是用来轮询消息,说白了就是通过loop方法实现死循环,有消息的时候,通过MessageQueue.next方法取出message,没有消息的时候,线程处于阻塞的状态。在有消息的时候获取到消息,将消息交给了handler,handler会根据消息中有没有callback,如果有callback会直接callback,否则通过handleMessage处理。
• MessageQueue是一个单链表结构来存储Message,每次通过next方法取出Message消息后,取完之后将message.next给当前的message,再将message.next=null,实际上就是移除当前的message。但是在looper里面每次在next取出message后,放到了message的sPool里面,缓存起来方便使用。
• Message就没什么好说的,主要存储平常经常用的obj和what信息,以及我们不用关心的target和callback等。
这里会问到,一个线程会有几个Looper,几个Handler,以及Looper会存在线程哪里?
一个线程一个Looper,可以有多个Handler,Looper会存在线程的ThreadLocal对象里,该对象是线程的缓存区。
ThreadLocal:它是和线程一一对应的,从Thread类可以看出来,ThreadLocal是作为Thread变量来使用。ThreadLocal只是ThreadLocalMap的一个包装类,实现了get和set方法,而ThreadLocalMap实际是一个由Entry内部类组成的数组,Entry是继承自弱应用,弱引用里面放的就是ThreadLocal当前对象,Entry的value存的是当前线程要存储的对象,value作为Entry的成员变量。 ThreadLocal经常会问到内存泄漏的问题,从上面分析可以发现ThreadLocalMap里面的Entry对象存储的ThreadLocal弱引用,而value直接作为Entry的强引用,因此在用到了ThreadLocal的地方,防止内存泄漏,手动调用remove方法。

三. Activity四种启动模式?
Activity:
是一个负责与用户交互的组件,通过setContentView(View)设置布局文件。
它上面可以显示一些控件也可以监听并处理用户的事件做出响应。

Activity的启动模式指,可以根据实际开发需求为Activity设置对应的启动模式,从而可以避免创建大量重复的Activity等问题。
1)standard
   Activity的默认启动模式,可以不用配置。默认创建一个新的activity实例。因此,在这种模式下可以有多个相同的实例,也允许多个相同Activity叠加。(点back键会依照栈顺序依次退出)
2)singleTop
  singleTop模式下,Activity可以有多个实例,但是不允许多个相同Activity叠加。即如Activity在栈顶的时候,启动相同的Activity,不会创建新的实例,而会调用其onNewIntent()。
3) singleTask
  singleTask表示只有一个实例。在同一个应用程序中启动他时,若Activity不存在,则会在当前task创建一个新的实例。

  若存在,则会把task中在其之上的其它Activity destory掉并调用它的onNewIntent方法。

如果是在别的应用程序中启动它,则会新建一个task,并在该task中启动这个Activity,singleTask允许别的Activity与其在一个task中共存,也就是说,如果我在这个singleTask的实例中再打开新的Activity,这个新的Activity还是会在singleTask的实例的task中。
4) singleInstance
   只有一个实例,并且这个实例独立运行在一个task中,这个task只有这个实例,不允许有别的Activity存在。

Activity中的几种启动模式
每种启动模式在什么场景下使用:
standard:   android默认的Activity启动模式,每启动一个Activity都会实例化一个Activity,并且新创建的Activity在堆栈中会在栈顶。
singleTop: 如果当前要启动的Activity是在栈顶的位置,那么就会复用该Activity,并且不会重走onCreate方法,会直接它的onNewIntent方法。

如果不在栈顶,就跟standard一样的。如果当前activity已经在前台显示着,突然来了一条推送消息,此时不想让接收推送的消息的activity再次创建,那么此时正好可以用该启动模式,如果之前activity栈中是A-->B-->C如果点击了推动的消息还是A-->B--C,不过此时C是不会再次创建的,而是调用C的onNewIntent。而如果现在activity中栈是A-->C-->B,再次打开推送的消息,此时跟正常的启动C就没啥区别了,当前栈中就是A-->C-->B-->C了。

singleTask: 不管在不在栈顶,在Activity的堆栈中永远保持一个。比如之前activity栈中有A-->B-->C---D,再次打开了B的时候,在B上面的activity都会从activity栈中被移除。

下面的acitivity还是不用管,所以此时栈中是A-->B,一般项目中主页面用到该启动模式。

singleInstance: 比较少,主要是指在该activity永远只在一个单独的栈中。一旦该模式的activity的实例已经存在于某个栈中,任何应用在激活该activity时都会重用该栈中的实例,解决了多个task共享一个activity。其余的基本和上面的singleTask保持一致。

通过配置清单文件和在代码中设置flag:
FLAG_ACTIVITY_CLEAR_TOP:只能单纯地清空栈上面的acivity,而自己会重新被创建一次,如果当前栈中有A-->B-->C这几种情况,重新打开B之后,此时栈会变成了A-->B,但是此时B会被重新创建,不会走B的onNewIntent方法。这就是单独使用FLAG_ACTIVITY_CLEAR_TOP的用处,能清空栈上面的activity,但是自己会重新创建。

如果再加上FLAG_ACTIVITY_SINGLE_TOP此时就不重新创建B了,也就直接走B的onNewIntent。两者结合着使用就相当上面的singleTask模式。

如果只是单独的使用FLAG_ACTIVITY_SINGLE_TOP,同singleTop。
FLAG_ACTIVITY_CLEAR_TOP+FLAG_ACTIVITY_SINGLE_TOP = singleTask,此时要打开的activity不会被重建,只是走onNewIntent方法。
FLAG_ACTIVITY_SINGLE_TOP = singleTop
FLAG_ACTIVITY_NEW_TASK:
• 在相同taskAffinity情况下:启动activity是没有任何作用的。
• 在不同taskAffinity情况下: 如果启动不同栈中的activity已经存在了某一个栈中的activity,那么此时是启动不了该activity的,因为栈中已经存在了该activity;如果栈中不存在该要启动的activity,那么会启动该acvitity,并且将该activity放入该栈中。
FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TOP一起使用,并且要启动的activity的taskAffinity和当前activity的taskAffinity不一样才会和singleTask一样的效果,因为要启动的activity和原先的activity不在同一个taskAffinity中,所以能启动该activity,有点绕,写个简单的公式:

• FLAG_ACTIVITY_NEW_TASK如果启动同一个不同taskAffinity的activity才会有效果。
• FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TOP一起使用,要开启的activity和现在的activity处于同一个taskAffinity,那么效果还是跟没加FLAG_ACTIVITY_NEW_TASK是一样的效果。
• FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TOP启动和现在的activity不是同一个taskAffinity才会和singleTask一样的效果。

FLAG_ACTIVITY_NEW_TASK+FLAG_ACTIVITY_SINGLE_TOP用在当app正在运行点击push消息进到某个activity中的时候,如果当前处于该activity,此时会触发activity的onNewIntent。
FLAG_ACTIVITY_NEW_TASK+FLAG_ACTIVITY_CLEAR_TOP用在app没在运行中,启动主页的activity,然后在相应的activity中做相应的activity跳转。

FLAG_ACTIVITY_CLEAR_TASK:
• 在相同taskAffinity情况下:和FLAG_ACTIVITY_NEW_TASK一起使用,启动activity是没有任何作用的。
• 在不同taskAffinity情况下:和FLAG_ACTIVITY_NEW_TASK一起使用,如果要启动的activity不存在栈中,那么启动该acitivity,并且将该activity放入该栈中,如果该activity已经存在于该栈中,那么会把当前栈中的activity先移除掉,然后再将该activity放入新的栈中。

1.2.1 Activity的LaunchMode

设置启动模式

  1. manifest中 设置下的 android:launchMode 属性。
  2. 启动Activity的 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 。
  3. 两种同时存在时,以第二种为准。第一种方式无法直接为Activity添加FLAG_ACTIVITY_CLEAR_TOP标识,第二种方式无法指定singleInstance模式。
  4. 可以通过命令行 adb shell dumpsys activity 命令查看栈中的Activity信息。 

Android使用栈来管理Activity。

  1. standard
    每次启动都会重新创建一个实例,不管这个Activity在栈中是否已经存在。谁启动了这个Activity,那么Activity就运行在启动它的那个Activity所在的栈中。
    用Application去启动Activity时会报错,原因是非Activity的Context没有任务栈。解决办法是为待启动Activity制定FLAG_ACTIVITY_NEW_TASH标志位,这样就会为它创建一个新的任务栈。
  2. singleTop
    如果新Activity位于任务栈的栈顶,那么此Activity不会被重新创建,同时回调 onNewIntent 方法。onCreate和onStart方法不会被执行。
  3. singleTask
    这是一种单实例模式。如果不存在activity所需要的任务栈,则创建一个新任务栈和新Activity实例;如果存在所需要的任务栈,不存在实例,则新创建一个Activity实例;如果存在所需要的任务栈和实例,则不创建,调用onNewIntent方法。同时使该Activity实例之上的所有Activity出栈。
    参考:taskAffinity标识Activity所需要的任务栈
  4. singleIntance
    单实例模式。具有singleTask模式的所有特性,同时具有此模式的Activity只能独自位于一个任务栈中。

假设两个任务栈,前台任务栈为12,后台任务栈为XY。Y的启动模式是singleTask。现在请求Y,整个后台任务栈会被切换到前台。如图所示:

1.2.2 Activity的Flags

这些FLAG可以设定启动模式、可以影响Activity的运行状态。

  • FLAG_ACTIVITY_NEW_TASK
    为Activity指定“singleTask”启动模式。
  • FLAG_ACTIVITY_CLEAR_TOP
    具有此标记位的Activity启动时,同一个任务栈中位于它上面的Activity都要出栈,一般和FLAG_ACTIVITY_NEW_TASK配合使用。
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
    如果设置,新的Activity不会在最近启动的Activity的列表(就是安卓手机里显示最近打开的Activity那个系统级的UI)中保存。等同于在xml中指定android:exludeFromRecents="true"属性。

1.3 IntentFilter的匹配规则

Activity调用方式

  1. 显示调用 明确指定被启动对象的组件信息,包括包名和类名
  2. 隐式调用 不需要明确指定组件信息,需要Intent能够匹配目标组件中的IntentFilter中所设置的过滤信息。

匹配规则

  • IntentFilter中的过滤信息有action、category、data。
  • 只有一个Intent同时匹配action类别、category类别、data类别才能成功启动目标Activity。
  • 一个Activity可以有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可成功启动对应的Activity。

** action**
action是一个字符串,匹配是指与action的字符串完全一样,区分大小写。
一个intent-filter可以有多个aciton,只要Intent中的action能够和任何一个action相同即可成功匹配。
Intent中如果没有指定action,那么匹配失败。

** category**
category是一个字符串。
Intent可以没有category,但是如果你一旦有category,不管有几个,每个都必须与intent-filter中的其中一个category相同。
系统在 startActivity 和 startActivityForResult 的时候,会默认为Intent加上 android.intent.category.DEFAULT 这个category,所以为了我们的activity能够接收隐式调用,就必须在intent-filter中加上 android.intent.category.DEFAULT 这个category。

** data**
data的匹配规则与action一样,如果intent-filter中定义了data,那么Intent中必须要定义可匹配的data。
intent-filter中data的语法:

     <data android:scheme="string"
        android:host="string"
        android:port="string"
        android:path="string"
        android:pathPattern="string"
        android:pathPrefix="string"
        android:mimeType="string"/>

Intent中的data有两部分组成:mimeType和URI。mimeType是指媒体类型,比如
image/jpeg、audio/mpeg4-generic和video/等,可以表示图片、文本、视频等不同的媒
体格式。

URI的结构:

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

实际例子

content://com.example.project:200/folder/subfolder/etc
http://www.baidu.com:80/search/info

scheme:URI的模式,比如http、file、content等,默认值是 file 。
host:URI的主机名
port:URI的端口号
path、pathPattern和pathPrefix:这三个参数描述路径信息。
path、pathPattern可以表示完整的路径信息,其中pathPattern可以包含通配符 * ,表示0个或者多个任意字符。
pathPrefix只表示路径的前缀信息。

过滤规则的uri为空时,有默认值content和file,因此intent设置uri的scheme部分必须为content或file。
Intent指定data时,必须调用 setDataAndType 方法, setData 和 setType 会清除另一方的值。
对于service和BroadcastReceiver也是同样的匹配规则,不过对于service最好使用显式调用。

隐式调用需注意

    • 当通过隐式调用启动Activity时,没找到对应的Activity系统就会抛出 android.content.ActivityNotFoundException 异常,所以需要判断是否有Activity能够匹配我们的隐式Intent。

    • 采用 PackageManager 的 resloveActivity 方法或Intent 的 resloveActivity 方法
      public abstract List<ResolveInfo> queryIntentActivityies(Intent intent,int flags);
      public abstract ResolveInfo resloveActivity(Intent intent,int flags);

      以上的第二个参数使用 MATCH_DEFAULT_ONLY ,这个标志位的含义是仅仅匹配那些在
      intent-filter中声明了 android.intent.category.DEFAULT 这个category的Activity。因为如果把不含这个category的Activity匹配出来了,由于不含DEFAULT这个category的Activity是无法接受隐式Intent的从而导致startActivity失败。

    • 下面的action和category用来表明这是一个入口Activity,并且会出现在系统的应用列表中,二者缺一不可。
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />

4. IntentService
IntentService是google在原生的Service基础上通过创建子线程的Service。也就是说IntentService是专门为android开发者提供的能在service内部实现耗时操作的service。我们可以通过重写onHandleIntent方法实现耗时操作的回调处理,而且IntentService在耗时操作完成后,会主动销毁自己,IntentService可以通过多次启动来完成多个任务,而IntentService只会被创建一次,每次启动的时候只会触发onStart方法。内部是实现了Handler异步处理耗时操作的过程,一般多用在Service中需要处理耗时操作的功能。
IntentService:
IntentService是Service的子类,比普通的Service增加了额外的功能。IntentService会创建独立的worker线程来处理所有的Intent请求;会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程的问题;所有请求处理完成后,IntentService会自动停止,开发者无需手动调用stopSelf()方法停止Service;
提问:为什么IntentService中能实现耗时操作?
• 在onCreate中,通过HandlerThread来开启一条线程,而HandlerThread线程中会跟我们平常用的Handler不太一样,在run方法中创建了looper对象,所以HandlerThread能让IntentService在子线程中使用handler达到耗时操作。

简述System.exit(0) 、onDestory()、Activity.finish()三者的区别?
1)System.exit(0) 是你正常结束程序,kill 掉当前进程,针对的是整个Application
2)onDestory()方法是Activity生命周期的最后一步,资源空间等就被回收了。当重新进入此Activity的时候,必须重新创建,执行onCreate()方法.
3)Activity.finish()当你调用此方法的时候,系统只是将最上面的Activity移出了栈,并没有及时的调用onDestory()方法,也就是占用的资源没有被及时释放。

5.HandlerThread
HandlerThread本身也是Thread,只是在Thread基础上封装上了Handler的载体,并且在run方法中创建了looper对象,这也是为什么在IntentService中能在HandlerThread中直接用handler的原因。而我们知道一个线程是可以有多个handler,所以用HandlerThread更加方便我们不用关心Handler的创建,一般用在多线程中直接处理任务。

二.BraodcastReceiver:(待补充)
使用了设计模式中的观察者模式:基于消息的发布/订阅事件模型。
注册的方式分为两种:静态注册、动态注册

一.ContentProvider:(待补充)
外界可以通过ContentResolver接口来访问ContentProvider(内容提供者)中的数据。Uri 通用资源标志符(Universal Resource Identifier)Uri代表要操作的数据,Android中可用的每种资源 - 图像、视频片段等都可以用Uri来表示。ContentProvider共享数据是通过定义一个对外开放的统一的接口来实现的。然而,应用程序并不直接调用这些方法,而是使用一个 ContentResolver 对象,调用它的方法作为替代。ContentResolver可以与任意内容提供者进行会话,与其合作来对所有相关交互通讯进行管理。当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver类来完成,要获取ContentResolver对象,可以使用Context提供的getContentResolver()方法。

posted on 2018-06-18 21:02  左手指月  阅读(322)  评论(0编辑  收藏  举报