andriod day03

1.Android中的广播主要可以分为两种类型:标准广播和有序广播

    •标准广播(Normal broadcasts)是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息

    •有序广播(Ordered broadcasts)则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递

2.注册广播的方式一般有两种,在代码中注册和在AndroidManifest.xml中注册,其中前者也被称为动态注册,后者也被称为静态注册。

    那么该如何创建一个广播接收器呢?其实只需要新建一个类,让它继承自BroadcastReceiver,并重写父类的onReceive()方法就行了。这样当有广播到来时,onReceive()方法就会得到执行,具体的逻辑就可以在这个方法中处理。

    动态注册的广播接收器可以自由地控制注册与注销,在灵活性方面有很大的优势,但是它也存在着一个缺点,即必须要在程序启动之后才能接收到广播,因为注册的逻辑是写在onCreate()方法中的。那么有没有什么办法可以让程序在未启动的情况下就能接收到广播呢?这就需要使用静态注册的方式了。

    需要注意的是,不要在onReceive()方法中添加过多的逻辑或者进行任何的耗时操作,因为在广播接收器中是不允许开启线程的,当onReceive()方法运行了较长时间而没有结束时,程序就会报错

3.自定义广播

    首先构建出了一个Intent对象,并把要发送的广播的值传入,然后调用了Context的sendBroadcast()方法将广播发送出去。此时发出去的广播就是一条标准广播

    发送有序广播只需要改动一行代码,即将sendBroadcast()方法改成sendOrderedBroadcast()方法,通过android:priority属性给广播接收器设置了优先级,优先级比较高的广播接收器就可以先收到广播;如果在onReceive()方法中调用了abortBroadcast()方法,就表示将这条广播截断,后面的广播接收器将无法再接收到这条广播

4.本地广播。我们发送和接收的广播全部属于系统全局广播,即发出的广播可以被其他任何应用程序接收到,并且我们也可以接收来自于其他任何应用程序的广播。这样就很容易引起安全性的问题,为了能够简单地解决广播的安全性问题,Android引入了一套本地广播机制,使用这个机制发出的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播,这样所有的安全性问题就都不存在了。

    首先是通过LocalBroadcastManager的getInstance()方法得到了它的一个实例,然后在注册广播接收器的时候调用的是LocalBroadcastManager的registerReceiver()方法,在发送广播的时候调用的是LocalBroadcastManager的sendBroadcast()方法,仅此而已。

    另外还有一点需要说明,本地广播是无法通过静态注册的方式来接收的

    最后我们再来盘点一下使用本地广播的几点优势吧。

    •可以明确地知道正在发送的广播不会离开我们的程序,因此不必担心机密数据泄漏。

    •其他的程序无法将广播发送到我们程序的内部,因此不需要担心会有安全漏洞的隐患。

    •发送本地广播比发送系统全局广播将会更加高效。

5.Android系统中主要提供了3种方式用于简单地实现数据持久化功能,即文件存储、SharedPreferences存储以及数据库存储

    文件存储是Android中最基本的一种数据存储方式,它不对存储的内容进行任何的格式化处理,所有数据都是原封不动地保存到文件当中的,因而它比较适合用于存储一些简单的文本数据或二进制数据。其实所用到的核心技术就是Context类中提供的openFileInput()和openFileOutput()方法,之后就是利用Java的各种流来进行读写操作。所有的文件都是默认存储到/data/data//files/目录下的

    SharedPreferences是使用键值对的方式来存储数据的。也就是说,当保存一条数据的时候,需要给这条数据提供一个对应的键,这样在读取数据的时候就可以通过这个键把相应的值取出来。 SharedPreferences文件都是存放在/data/data//shared_prefs/目录下的,并且SharedPreferences文件是使用XML格式来对数据进行管理的。Android中主要提供了3种方法用于得到SharedPreferences对象:

       1.Context类中的getSharedPreferences()方法;此方法接收两个参数,第一个参数用于指定SharedPreferences文件的名称,如果指定的文件不存在则会创建一个,SharedPreferences文件都是存放在/data/data//shared_prefs/目录下的。第二个参数用于指定操作模式,目前只有MODE_PRIVATE这一种模式可选,它是默认的操作模式,和直接传入0效果是相同的,表示只有当前的应用程序才可以对这个SharedPreferences文件进行读写

        2.Activity类中的getPreferences()方法;这个方法和Context中的getSharedPreferences()方法很相似,不过它只接收一个操作模式参数,因为使用这个方法时会自动将当前活动的类名作为SharedPreferences的文件名

        3.PreferenceManager类中的getDefaultSharedPreferences()方法;这是一个静态方法,它接收一个Context参数,并自动使用当前应用程序的包名作为前缀来命名SharedPreferences文件

    得到了SharedPreferences对象之后,就可以开始向SharedPreferences文件中存储数据了,主要可以分为3步实现。

        (1) 调用SharedPreferences对象的edit()方法来获取一个SharedPreferences.Editor对象。

        (2) 向SharedPreferences.Editor对象中添加数据,比如添加一个布尔型数据就使用putBoolean()方法,添加一个字符串则使用putString()方法,以此类推。

        (3) 调用apply()方法将添加的数据提交,从而完成数据存储操作。  


6.内容提供器。虽然文件和SharedPreferences存储中提供了MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE这两种操作模式,用于供给其他的应用程序访问当前应用的数据,但这两种模式在Android 4.2版本中都已被废弃。因为Android官方已经不再推荐使用这种方式来实现跨程序数据共享的功能,而是应该使用更加安全可靠的内容提供器技术。

    内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访数据的安全性。目前,使用内容提供器是Android实现跨程序共享数据的标准方式

7.Android开发团队在Android 6.0系统中引用了运行时权限这个功能。用户不需要在安装软件的时候一次性授权所有申请的权限,而是可以在软件的使用过程中再对某一项权限申请进行授权

8.Android现在将所有的权限归成了两类,一类是普通权限,一类是危险权限。准确地讲,其实还有第三类特殊权限,不过这种权限使用得很少。

危险权限表:https://blog.csdn.net/weixin_42744183/article/details/90438331,如果是属于这张表中的权限,那么就需要进行运行时权限处理,如果不在这张表中,那么只需要在AndroidManifest.xml文件中添加一下权限声明就可以了。

9.服务并不是运行在一个独立的进程当中的,而是依赖于创建服务时所在的应用程序进程。当某个应用程序进程被杀掉时,所有依赖于该进程的服务也会停止运行。实际上服务并不会自动开启线程,所有的代码都是默认运行在主线程当中的。也就是说,我们需要在服务的内部手动创建子线程,并在这里执行具体的任务,否则就有可能出现主线程被阻塞住的情况

10.和许多其他的GUI库一样,Android的UI也是线程不安全的。也就是说,如果想要更新应用程序里的UI元素,则必须在主线程中进行,否则就会出现异常。

11.异步消息处理机制

    Android中的异步消息处理主要由4个部分组成:Message、Handler、MessageQueue和Looper。其中Message和Handler在上一小节中我们已经接触过了,而MessageQueue和Looper对于你来说还是全新的概念,下面我就对这4个部分进行一下简要的介绍。

    1.Message

    Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。上一小节中我们使用到了Message的what字段,除此之外还可以使用arg1和arg2字段来携带一些整型数据,使用obj字段携带一个Object对象。

    2.Handler

    Handler顾名思义也就是处理者的意思,它主要是用于发送和处理消息的。发送消息一般是使用Handler的sendMessage()方法,而发出的消息经过一系列地辗转处理后,最终会传递到Handler的handleMessage()方法中。

    3.MessageQueue

    MessageQueue是消息队列的意思,它主要用于存放所有通过Handler发送的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue对象。

     4.Looper

    Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当发现MessageQueue中存在一条消息,就会将它取出,并传递到Handler的handleMessage()方法中。每个线程中也只会有一个Looper对象

12.runOnUiThread()方法其实就是一个异步消息处理机制的接口封装

13.AsyncTask,为了更加方便我们在子线程中对UI进行操作,Android还提供了另外一些好用的工具,比如AsyncTask,AsyncTask背后的实现原理也是基于异步消息处理机制的.

    AsyncTask是一个抽象类,所以如果我们想使用它,就必须要创建一个子类去继承它。在继承时我们可以为AsyncTask类指定3个泛型参数,这3个参数的用途如下。

    •Params。在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。

    •Progress。后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。

    •Result。当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。

    我们还需要去重写AsyncTask中的几个方法才能完成对任务的定制。经常需要去重写的方法有以下4个。

    1.onPreExecute()

    这个方法会在后台任务开始执行之前调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。

    2.doInBackground(Params...)

    这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。任务一旦完成就可以通过return语句来将任务的执行结果返回,如果AsyncTask的第三个泛型参数指定的是Void,就可以不返回任务执行结果。注意,在这个方法中是不可以进行UI操作的,如果需要更新UI元素,比如说反馈当前任务的执行进度,可以调用publishProgress (Progress...)方法来完成

    3.onProgressUpdate(Progress...)

当在后台任务中调用了publishProgress(Progress...)方法后,onProgressUpdate (Progress...)方法就会很快被调用,该方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新

    4.onPostExecute(Result)

当后台任务执行完毕并通过return语句进行返回时,这个方法就很快会被调用。返回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些UI操作,比如说提醒任务执行的结果,以及关闭掉进度条对话框等

14.onCreate()方法会在服务创建的时候调用,onStartCommand()方法会在每次服务启动的时候调用,onDestroy()方法会在服务销毁的时候调用

15.构建出了一个Intent对象,并调用startService()方法来启动服务,调用stopService()方法来停止服务;startService()和stopService()方法都是定义在Context类中的,所以我们在活动里可以直接调用这两个方法。

16.那服务有没有什么办法让自已停止下来呢?当然可以,只需要在服务的任何一个位置调用stopSelf()方法就能让这个服务停止下来了。

17.根据Android系统的机制,一个服务只要被启动或者被绑定了之后,就会一直处于运行状态,必须要让以上两种条件同时不满足,服务才能被销毁。所以,这种情况下要同时调用stopService()和unbindService()方法,onDestroy()方法才会执行

18.为了可以简单地创建一个异步的、会自动停止的服务,Android专门提供了一个IntentService类.

你可能感兴趣的:(andriod day03)