• 第三篇 功能实现(2) (Android学习笔记)


    第三篇 功能实现(2)

    Activity的四种启动模式

    Activity的启动模式四种,分别是standardsingleTopsingleTasksingleInstance

    AndroidManifest.xml中,可以通过<activity>标签的android:launchMode属性设置启动模式。

    (1)standard:每次激活Activity, 使用方法startActivity(Intent intent),都创建Activity实例,并放入任务栈;

    (2)singleTop:如果某个Activity自己激活自己,即任务栈栈顶就是该Activity,则不需要创建,其余情况都要创建Activity实例;

    (3)singleTask:如果要激活的那个Activity在任务栈中存在该实例,则不需要创建,只需要把此Activity放入栈顶,并把该Activity以上的Activity实例都pop

    (4)singleInstance:如果应用1的任务栈中创建了MainActivity实例,如果应用2也要激活MainActivity,则不需要创建,两应用共享该Activity实例;

     

     

    Intent

    Intent是Android中比较重要的组件,常用来启动一个新的Activity或者Service、广播某个事件,以及在Android组件之间传递数据。通过Intent来启动新的Activity或者Service通常有两种方法,一种是显示启动,另一种是隐式启动。

     

    Intent和IntentFilterAndroid和一种消息通信机制, 可以让系统的组件之间进行通信。

     

    Intent的构成:

    详见: http://www.programgo.com/article/44625050521/

    Intent的使用分为二个方面:

    ① 发出Intent,② 接收Intent, 用官方的说法就是Intent Resolving

    Intent分为两类:

    1. 显式Intent--需要在Intent明确指定目标组件,也就是在Intent中明确写明目标组件的名称(Component name),需要指定完整的包名和类名。因为对于本程序以外的其他应用程序,你很难知道它的组件名字,所以显式的Intent通常用于应用程序内部通信,更确切的说,显示Intent是用于应用程序内部启动组件,通常是ActivityService。还没有见用显式Intent来给BroadcastReceiver发送广播的。 (例如,当用户在Login Activity点击submit按钮时,用Explicit Intent载入(launchDashboard Activity(仪表盘Activity)

    例如,登入Twitter以后,显示的Activity如下:

     

    2. 隐式Intent--也就是不在Intent指定目标组件,在Intent中不能含有目标的名字。系统是根据其他的信息,比如DataTypeCategory去寻找目标组件。

    隐式Intent通常用于与应用程序外部的组件进行通信。应用程序级别的组件复用也主要是靠隐式Intent来完成的。而IntentFilter也是只有隐式Intent才用的着,显式Intent都是直接把Intent传递给目标组件,根本不会理会组件的IntentFilter(例如,用Implicit Intent触发(invoke)拨号键(Dialer key-pad)

     

    IntentFilter(意图过滤器)是用来解析隐式意图(Implicit Intent)的,也就是说告诉系统你的组件(Activity, Service, BroadcastReceiver)能够处理哪个/哪些隐式的Intent. 因此, 我们必须给activitiesservices,或 broadcast receivers设置一个或者多个intent过滤器(一个过滤器中包含 一个Intent object 中的三个属性 action—动作、data—数据, 包括URI和数据类型, 以及catrgory—类别 。一个隐式意图必须要通过这三项测试才能传递到 包含该过滤器的组件中)每个过滤器描述了组件的一种能力,它过滤掉不想要的intent,留下想要的。具体过程如下:

     

     

    一个intent过滤器是一个IntentFilter类的实例。

    因为Android系统在启动一个组件之前必须知道它的能力,

    但是intent过滤器通常不在java代码中设置,而是在应用程序的清单文件(AndroidManifest.xml)中以<intent-filter>元素设置,一个Activity或其它组件可以配置多个<intent-filter>

    具体来说,在 Android AndroidManifest.xml 配置文件中可以通过 节点 为一个 Activity 指定其 Intent Filter,以便告诉系统该 Activity 可以响应什么类型的 Intent

    但有一个例外,广播接收者的过滤器通过调用Context.registerReceiver()动态地注册,它直接创建一个IntentFilter对象。

    另外,当对其他app程序开放组件和服务的时候也需要配置Intent Filter(意图过滤器)。

     

     

    例如:当用户点击PDF文件的时候,Android系统就会通过设定好的意图过滤器,进行匹配测试。找到能够打开PDF文件的APP程序。

     

    Implicit intent的不安全性

    使用隐式intent进行广播会造成数据泄露、拒绝服务、钓鱼等安全问题.

    Android 5.0之后google出于安全的角度禁止了隐式声明Intent来启动Service.也禁止使用Intent filter.

    否则会抛出异常.

     

    Activity的跳转

     

    Service的生命周末

     

     

    Android Service Methods

     

    ●程序(program), 进程(process), 线程(thread)

    Java 语言的优势之一就是线程处理较为简单。

    一般操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序被称为一个进程,当一个程序运行时,内部可能包含多个顺序执行流,每个顺序执行流就是一个线程

    1) 程序 指令 + 数据的 byte 序列,如: qq.exe

    2) 进程 正在运行的程序, 是程序劢态的执行过程(运行于内存中)

    3) 线程 在进程内部,并发运行的过程(Java 中的方法可以看做线程)

    4) 并发 进程是并发运行的,OS 将时间划分为很多时间片段(时间片),尽可能均匀分配给正在运行的程序,微观上迚程走走停停,宏观上都在运行,这种都运行的现象叨并发,但不是绝对意义上的"同时发生"

    程序是指令、数据及其组织形式的描述.

    在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;

    在当代面向线程设计的计算机结构中,进程是线程的容器。

    首先我们对进程作一明确定义:所谓进程是由正文段(text)、用户数据段(user segment)以及系统数据段(system segment)共同组成的一个执行环境。

     程序只是一个普通文件,是一个机器代码指令和数据的集合,这些指令和数据存储在磁盘上的一个可执行映象(Executable Image)中,所以,程序是一个静态的实体。

     

    ●如何理解一个程序可以对应多个进程,一个进程也可以对应多个程序?

    一个程序可以对应多个进程----例如, 一个程序可以重复运行,开几个窗口:

     

    一个进程可以对应多个程序----例如, qtcore4.dllqtgui4.dll等是各种Qt程序执行必备的动态链接库文件.

    这就如同的车和路的关系,

    要去一个地方,可以有多条路;

    而一条路也可到达多个地方.

     

    ●进程 & 线程

    线程与进程的区别归纳:

    a.地址空间和其它资源:进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。

    b.通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。

    c.调度和切换:线程上下文切换比进程上下文切换要快得多。

    d.在多线程OS中,进程不是一个可执行的实体。

     

    操作系统的设计,因此可以归结为三点:

    1)以多进程形式,允许多个任务同时运行;

    2)以多线程形式,允许单个任务分成不同的部分运行;

    3)提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源。

     

    Service既不是进程也不是线程,它们之间的关系如下:

    Service和Thread之间没有任何关系, 之所以有不少人会把它们联系起来,主要就是因为Service的后台概念。

    注:Service等组件服务的ThreadUI Thread

    服务于Service等组件的ThreadBG Thread

    △如果采用ThreadPool(线程池)技术来实现异步加载,UI ThreadBG Threads)是平行的。

    如果采用AsyncTask(异步任务)来实现异步加载,BG Threads)从属于UI Thread

    Thread与Service不具备可比性。

    1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。

    2). Service:Service android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreateonStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有!

     

    Activity ComponentActivity Object的区别

     

     

    Android-ServiceThread的区别

    1.服务不是单一的进程。服务没有自己的进程,应用程序可以不同,服务运行在相同的进程中。

    2.服务不是线程。可以在线程中工作。

    . 在应用中,如果是长时间的在后台运行,而且不需要交互的情况下,使用服务。

    . 同样是在后台运行,不需要交互的情况下,如果只是完成某个任务,之后就不需要运行,而且可能是多个任务,或者如果任务占用CPU时间多,资源大的情况下,要使用线程。

    Servie是系统的组件,它由系统进程托管(servicemanager;它们之间的通信类似于clientserver,是一种轻量级的ipc通信,这种通信的载体是binder,它是在linux层交换信息的一种ipc

    Thread由本应用程序托管

    1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。

    2). Service:Service android的一种机制,当它运行的时候如果是Local Service,那么对应的Service 是运行在主进程的 main 线程上的。如:onCreateonStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。

    • 仔细体会下面这段话:

      Service是运行在主线程(UI线程)里的(其它三个Android组件也运行在主线程里),也就是说如果你在Service里编写了非常耗时的代码,程序必定会出现ANR的。

      你可能会惊呼,这不是坑爹么!?那我要Service又有何用呢?其实大家不要把后台和子线程联系在一起就行了,这是两个完全不同的概念。Android后台的运行是完全不依赖UI的,即使Activity被销毁,或者程序被关闭(例如微信关闭后仍然可以收到消息)只要进程还在,Service就可以继续运行。比如说一些应用程序,始终需要与服务器之间始终保持着心跳连接,就可以使用Service来实现。你可能又会问,前面不是刚刚验证过Service是运行在主线程里的么?在这里应用程序与服务器之间始终保持着心跳连接,难道就不会阻塞主线程的运行吗?当然会,但是我们可以在Service中再创建一个子线程,然后在这里去处理耗时逻辑就没问题了。

      额,既然在Service里也要创建一个子线程,那为什么不直接在Activity里创建这个子线程呢?这是因为Activity很难对Thread进行控制,Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的ServiceBinder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。

    补充说明:

    Android 中ServiceBroadcastreceiver都是运行在ui线程中,,如果在他们中执行耗时操作,若果操作持续的时间超过android平台的约定,那么Android平台会认为该程序出现异常,从而抛出ANR异常。

    解决方法就是在ServiceBroadcastReceiver里面创建一个子线程, 那为什么不在Activity里面创建这个子线程呢?

    因为Actvity 是可见的, GC进行回收时,优先级很低,很容易被系统回收掉, service的优先级很高。能够保证在后台长期运行.

    另外,按照设计上模块化的思路,也还是模块独立的好,这符合低耦合的原则.

    如果有多个Activity调用使用到同一个Service,难道还要在每个activity里面都写一遍Service?

    总之, 四大组件在主线程中要保持平行关系:

     

     

    Main Thread & Background Thread

    在一个Android 程序开始运行的时候,会单独启动一个Process。默认的情况下,所有这个程序中的Activity或者Service都会跑在这个Process

     

    An Android application, generally, has only one process, but there can be many threads in a process. Among all those threads, there is a main thread, called UI thread.

    : 一个Android 程序一般情况下只有一个process,但一个process下却可以有许多个Thread。这些线程中, 其中一个叫主线程/UI线程。

     

    ※ 例如, 一般来说, 不能在Android系统里同时开两个QQ, 但是可以借助LBE双开大师等类似的工具完成这件事.

     

    Android消息处理机制(HandlerLooperMessageQueueMessage)

     

    总结一下流程为:

    1. 在主线程中创建一个Handler对象,并重写handleMessage()方法。

    2. 在子线程中需要进行UI操作时, 创建一个消息Message对象,并通过Handler.sendMessage()把这条消息发送出去;之后这条消息会被添加到MessageQueue(消息队列)中等待被处理。

    3. UI线程通过Looper从消息队列中取出Handler发过来的这个消息,此时,UI线程会回调Handler类的handleMessage()方法,也就是将取得的Message发回给HandlerhandleMessage()方法中。

    由于Handler是在主线程中创建的,所以handleMessage()方法也会在主线程中运行,这样就可以放心进行UI操作了。

    Handler在负责发送处理消息,通过它可以实现其它线程与Main线程之间的消息通讯。

    • 为什么要Handker这么做? 因为所有与UI相关的操作, 必须保该证在UI线程中进行更新, Android上新开的线程如想更新UI,需要重新跳到主线程中才能操作.
    • 实现后台线程与UI线程的交互, 可借助:

    1、Handler

    2、Activity.runOnUIThread(Runnable)

    3、View.Post(Runnable)

    4、View.PostDelayed(Runnabe,long)

    5、AsyncTask

    详见: http://blog.csdn.net/yony2011/article/details/11952735

    Looper负责管理线程的消息队列和消息循环。

    Message是线程间通讯的消息载体。

    两个码头之间运输货物,Message充当集装箱的功能,里面可以存放任何你想要传递的消息。

    Message类负责线程之间的消息传递, Intent类负责Activity之间的消息传递.

    1. MessageQueue是消息队列,先进先出,它的作用是保存有待线程处理的消息。

     

    四者之间的关系是:

    1. Non-UI线程中调用Handler类的sendMessage()方法(参数是Message类的对象),
    2. 将需要UI线程处理的事件添加到UI线程MessageQueue中,
    3. UI线程通过Looper从消息队列中取出Handler发过来的这个消息,此时,UI线程会回调Handler类的handleMessage()方法。

     

    上面都是主线程中只有一个Handler 的情况, 下面是两个Handler的情况:

    可以看到,一个线程可以有多个Handler,但是只能有一个Looper

    Android 在进程的入口函数 ActivityThread.main()中,调用 Looper.prepareMainLooper,为应用的主线程创建Looper,然后调用Looper.loop()就启动了进程的消息循环,然后就可以处理消息了。

     

    自动实现增加Looper的方法是使用HandlerThread

     

    AsyncTaskHandler两种异步方式的实现和区别比较

    1 AsyncTask实现的原理,和适用的优缺点

    AsyncTask是android提供的轻量级的异步类, 可以直接继承AsyncTask,在类中实现异步操作, 并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.

    使用的优点:

    简单,快捷

    过程可控

    使用的缺点:

    在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.

     

    2 Handler异步实现的原理和适用的优缺点

    Handler 异步实现时,涉及到 Handler, Looper, Message,Thread四个对象,实现异步的流程是主线程启动Thread(子线程)àthread(子线程)运行并生成Message-àLooper获取Message并传递给HandleràHandler逐个获取Looper中的Message,并进行UI变更。

     

    使用的优点:

    结构清晰,功能定义明确

    对于多个后台任务时,简单,清晰

     

    使用的缺点:

    在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)

    Android平台很多应用使用的都是AsyncTask,而并非ThreadHandler去更新UI, 也推荐大家使用AsyncTask代替Thread+Handler的方式,不仅调用上更为简单,经过实测更可靠一些,GoogleBrowser中大量 使用了异步任务作为处理耗时的I/O操作,比如下载文件、读写数据库等等,它们在本质上都离不开消息,但是AsyncTask相比ThreadHandler更为可靠,更易于维护,但AsyncTask缺点也是有的比如一旦线程开启即dobackground方法执行后无法给线程发送消息,仅能 通过预先设置好的标记来控制逻辑,当然可以通过线程的挂起等待标志位的改变来通讯,对于某些应用ThreadHandler以及Looper可能更灵 活。

     

     

     

    ●几个概念

    UI thread = Main thread

    background thread(BG thread= NON-UI thread=worker thread

     

    ●同步 & 异步

    同步执行(synchronous execution)是指程序按指令顺序从头到尾依次执行, 无论中间某个操作耗费多少时间, 如果不执行完, 程序都不会继续往下进行.

     

    异步执行(asynchronous execution)就是把一些操作, 特别是耗时间的操作安排到后台去运行, 主程序可以继续做前台的事情, 防止卡在某一步失去响应.

     

    Android & 线程

    当一个程序第一次启动时,Android会同时启动一个对应的主线程,主线程主要负责控制UI页面的显示、更新、交互等,如:用户的按键事件、用户触摸屏幕的事件等,并把相关的时间分发到对应的组件进行处理,这个主线程也叫UI线程

    Android的UI线程的响应时间是有限的(只有这样用户才会觉得操作比较流畅),当UI线程长时间得不到响应时程序会报出ANR(Application Not Responding)异常。

    为了能在处理耗时较长的业务、而又要兼顾UI,解决方法是将耗时任务放入子线程处理。例如把网络请求、数据库操作、复杂计算等逻辑都封装到单独的子线程。

    ※异步加载(Asynchronous Loading

    在加载大量数据的时候,经常会用到异步加载,所谓异步加载,就是把耗时的工作放到子线程里执行,当数据加载完毕的时候再到主线程进行UI刷新。在数据量非常大的情况下我们通常会使用两种技术来进行异步加载,一是通过AsyncTask来实现(更简单),另一种方式则是通过ThreadPool来实现。

     

    How does a AsyncTask work?

    AsyncTask is a wrapper(包装类), and is designed to be a helper class around threads and handlers, which is used to do some computation in background and publish the result on the UI thread.

    ※ 由于Handler需要和主线程交互,而Handler又是内置于AsnycTask中的,所以,AsyncTask的创建必须在主线程。

    1. onPreExcute() :这个方法会在后台任务执行前调用,用于进行UI界面上的一些初始化操作,比如去显示"正在加载"字样

     

    2. doInBackground(Params) : 这个方法里面的代码将会在子线程中运行,处理耗时任务的代码应该写在这个方法里面。任务完成后将会把任务结果返回,如果第三个参数指定的是Void则不会返回。但是这个方法是不能执行UI更新操作的。

     

    3.onProgressUpdate(Progress.) :如果在后台任务中调用了publishProgress()方法,这个方法将会被调用。这个方法可以更新UI进程,可以用来更新进度条之类的。

     

    4.onPostExcute (Result) :当后台任务执行完成后,这个方法会被调用,可以接受返回的数据,利用书库来进行UI更新,比如显示操作结果,关闭进度条等等。

     

    Step

    Thread

    Description

    onPreExecute

    UI

    This is the first step of execution of an AsyncTask and invoked on the UI thread. Normally it will be used to set up the task e.g. to instantiate variables.

    doInBackground

    Background

    Immediately after onPreExecute this method will be invoked on the background thread. The background computation that can take a long time should be performed in this method. The computation's result will be passed back to the last step. It is possible to call the publishProgress() method from this step, e.g. to make a update of the current state of the UI, which will be done by the onProgressUpdate() method.

    onProgressUpdate

    UI

    This method is used to display any form of progress on the UI thread during the execution of background computation. For instance, it can be used to animate a progress bar or write logs on the text file.

    onPostExecute

    UI

    This is the last step of the execution and invoked on the UI thread after the background computation has finished. The result of the background computation is passed to this step as a parameter.

     

    ●有关主线程的详解

    All of your application components (Activities, Services, ContentProviders, BroadcastReceivers) are created in UI thread, and any system calls to those components are performed in UI thread.

    汉:所有的app应用组件创建与UI线程,并且任何对这些组件的系统调用(system calls)都在UI线程上实现。

     

    An single Android app havs only one UI thread for all Activities.

    汉:一个Android应用只有一个Uithread。

     

    • 如果同时开几个app, 会不会有多个主线程?

    会有几个主线程, 但是它们分别属于不同的进程(processes).

     

    Consider that there can be only one main thread and that the main thread is the only one that can interact with the screen in any capacity.

    汉:只可以存在一个UI线程, 即多个子窗口共用一个主线程; 发送到各子窗口的消息由内核来调度。

     

    在开发Android应用时, 必须遵循单线程模型的原则:

    一个程序第一次启动时,Android会同时启动一个对应的 主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线 程。

    在单线程模型中, 始终要记住两条法则:

    ① 不要阻塞UI线程;

    ② 确保只在UI线程中访问Android UI工具包

     

    ※ 线程安全就是多线程访问数据时,采用了加锁机制;当一个线程访问某数据时,进行保护,其它线程不能进行访问直到该线程读取完,其它线程才可使用。不会出现数据不一致或者数据污染。

    线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据

     

    ※ 什么说android UI操作不是线程安全的?

    更新UI只能是主线程的工作,子线程更新UI是线程不安全的(注意,子线程更新UI是可行的,但不安全),所以android里非主线程操作主UI就会报错。为什么呢?因为子线程可能会有多个,多个线程同时操作一个控件可能会有冲突发生,所以Android就限定了只有主线程可以操作UI子线程想操作UI,可以,你告诉主线程,让主线程来更新 (注意有例外, SurfaceViewandroid 里唯一一个可以在子线程更新的控件)

     

    图示:

     

    • 主线程实际上是一个死循环,不断的循环处理系统以及其他子线程发来的消息。主线程的绑定是在DecorView初始化的时候,也就是生命周期的onResume()之后。
    • DecorView为整个Window界面的最顶层View

     

    Handler的定义

    简单来说,Handler这个类的功能是管理某个线程(也可能是进程)的消息队列(MessageQueue),比如让Handler处理主线程的消息队列,这样就可以将一些耗时任务放到其他线程之中,待任务完成之后就往主线程的消息队列中添加一个消息,这样HandlerCallback,即handleMessage就会被调用。但是Handler并不是线程安全的,因此官方文档中建议将Handler作为一个静态内部类。

     

    所以Handler的功能是处理消息,耗时任务放在其他线程。

     

    解释:① 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件, 进行事件分发, 比如说, 你要是点击一个 Button Android会分发事件到Button上,来响应你的操作。 如果此时需要一个耗时的操作,例如: 联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象,如果5秒钟还没有完成的话,会收到Android系统的一个错误提示"强制关闭"

    ② 这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,Android主线程是线程不安全的, 也就是说,更新UI只能在主线程中更新,子线程中更新UI是危险的。 这个时候,可以在主线程中创建一个或多个Handler 它与子线程可以通过Message对象来传递数据, 这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据) , 把这些消息放入主线程队列中,配合主线程进行更新UI

     

    Handler一定要在主线程实例化吗?

    不一定。

    情况1:

    要刷新UI

    Handler要用到主线程的looper。那么在主线程 Handler handler = new Handler();

    如果在其他线程,也要满足这个功能的话,要Handler handler = new Handler(Looper.getMainLooper());

    情况2 :

    不用刷新ui,只是处理消息。

    当前线程如果是主线程的话,Handler handler = new Handler();

    不是主线程的话,Looper.prepare(); Handler handler = new Handler();Looper.loop();

    或者Handler handler = new Handler(Looper.getMainLooper());

     

    Broadcast & BroadcastReceiver

    通常广播发送方就是调用Context.sendBroadcast()的程序,而广播接收者就是继承BroadcastReceiver的程序;

    通常广播发送方都是通过隐式意图,这样才能发送给多人。

    创建BroadcastReceiver

     

    ●广播的原理

    广播(Broadcast是一种运用在应用程序之间传递消息的机制。

    广播接收者(BroadcastReceiver是用来过滤、接收并响应广播的一类组件。

    广播接收者可以监听系统中的广播消息,在不同组件之间进行通信

    Java的本地系统服务SystemServer当中存在服务ActivityManagerService,

    它主要是用来创建Android应用程序组件(activity)、服务(service)、广播接收器(broadcast receiver)等工作,并全权管理他们的生命周期,是Android平台核心服务之一。

     

    ActivityManagerService也是一个广播的注册中心

    当客户端发送一条注册请求registerReceiver时,这个注册请求就会注册到这个注册中心中,并指明该广播的接收信息的类型;

    同样,当客户端发送一条发送请求sendBroadcast的时候,会先将请求发送到这个ActivityManagerService中心去,

    其会现在已经注册的消息中根据消息类型寻找匹配的消息并返回给广播的接受者,然后继续后续处理。

     

     

    Broadcastreceiver

    BroadcastReceiver本质上就是一种全局的监听器(global listener)。

    特点:

    1.BroadcastReceiver用于接收程序所发出的Broadcast Intent,与应用程序启动ActivityService相同;

    2.当应用程序发出一个Broadcast Intent之后,所有匹配该IntentBroadcastReceiver都有可能被启动;

    广播可以分为:

    1. 无序广播(普通广播)

    发送至每一个已经注册(订阅)的广播接收器,无法被终止。

    无序广播是一种完全异步执行的广播,在广播发出去后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息。

    当发送的是无序广播时,广播接收器之间是没有先后顺序的。

    典型代表:开机启动广播

     

     

    2. 有序广播

    有序广播则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够接收到这条消息。

    当发送有序广播时,广播接收器是有先后顺序的,并且可以被拦截

    典型代表:车载中的发送消息,例如1号车(最高指挥车)下达消息给2号车,2号车接受到消息之后,根据命令将消息详细化发给3号车(不一定是一个量车,有的车优先级可以相同)

    <receiver android:name=".One">
    																			

    
    															<intent-filter android:priority="900">
    																				

    
    															<action android:name="abc"/>
    																				

    
    															</intent-filter>
    																

    
    															</receiver>
    																

         <receiver android:name=".Two">
    																				

    
    															<intent-filter android:priority="1000">
    																				

    
    															<action android:name="abc"/>
    																				

    
    															</intent-filter>
    																

    
    															</receiver>
    																

    
    															<receiver android:name=".There">
    																				

    
    															<intent-filter android:priority="800">
    																				

    
    															<action android:name="abc"/>
    																				

    
    															</intent-filter>
    																

    
    															</receiver>

    priority值越大其优先权越大。如果在接收者类中onReceive方法中,使用abortBroadcast();即终止广播,后面的广播不会在继续。

     

     

    ※ 形象解释:

    举个例子,开学典礼上,校领导在讲台讲话,他发出的声音大家都能听到,没有固定的谁先谁后,这个就类似"无序广播"。在来个比喻,期末考试成绩下来了,班主任叫同学一个一个或一组一组同学去他办公室谈话,谈完一批在进下一批,这个先后是由优先级决定,这个就类似"有序广播"。 总结就是:有序广播是优先级高的接收者先接收,并且这个接收者可以处理广播信息,也可以停止广播的传递。而无序广播是没有接收先后概念的,也不能中途处理信息或停止。

    广播接收器 -- 广播接收器订阅广播后可以接收广播

    注册广播有两种方式,常驻型广播与非常驻型广播。

    1、注册常驻型广播(静态广播)

        常驻型广播是当应用程序关闭后,如果接收到其他应用程序发出的广播,那么该程序会自动重新启动。常驻型广播在清单文件中注册。

    典型代表:很多开机启动的APP,都是接收开机启动广播带起服务的。

    <receiver android:name="cn.itcast.MyBroadcastReceiver">
    <intent-filter android:priority="20">
    <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
    </intent-filter>
    </receiver>

     

    2、注册非常驻型广播(动态广播)

        非常驻型广播依赖于注册广播的组件的生命周期,例如,在Activity中注册广播接收者,当Activity销毁后广播也随之被移除。这种广播事件在代码中注册。

    典型代表:彻底关闭微信(不在后台运行),用户无法接受消息。

        MyBroadCastReceiver receiver = new MyBroadCastReceiver();

        String action = "android.provider.Telephony.SMS_RECEIVED";

        IntentFilter intentFilter = new IntentFilter(action);

        registerReceiver(receiver, intentFilter);

     

        非常驻型广播可以在onDestory()方法中解除广播,具体代码如下:

        unregisterReceiver(receiver);

     

    broadcastreceiver & intent (应用较少)

     

    Android四大组件的比较

     

    Android 四大组件关系图

  • 相关阅读:
    CREATE VIEW
    CREATE USER
    安全层次
    PHP json_decode 函数解析 json 结果为 NULL 的解决方法
    Java实现 LeetCode 7整数反转
    Java实现 LeetCode 6 Z字形变换
    Java实现 LeetCode 6 Z字形变换
    Java实现 LeetCode 6 Z字形变换
    Java实现 LeetCode 5 最长回文子串
    Java实现 LeetCode 5 最长回文子串
  • 原文地址:https://www.cnblogs.com/ArrozZhu/p/8383819.html
Copyright © 2020-2023  润新知