Android基础知识(三)|青训营笔记

137 阅读6分钟

这是我参与「第四届青训营 」笔记创作活动的第4天。

4 Broadcast

4.1 Broadcast是什么

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

  • 标准广播(normal broadcasts)是一种完全异步执行的广播,在广播发出之后,所有的BroadcastReceiver几乎会在同一时刻收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,同时也意味着它是无法被截断的。
  • 有序广播(order broadcasts)是一种同步执行的广播,同一时刻只会有一个BroadcastReceiver能够收到这条广播消息,当这个BroadcastReceiver中的逻辑执行完毕后,广播才会继续传播。所以此时的BroadcastReceiver是有先后顺序的,优先级高的BroadcastReceiver就可以先收到广播消息,并且前面的BroadcastReceiver还可以截断正在传递的广播,这样后面的BroadcastReceiver就无法收到广播消息了。

4.2 Broadcast基本用法

4.2.1 静态注册BroadcastReceiver

在AndroidMainfest.xml中注册:

<receiver
    android:name=".AnotherBroadcastReceiver"
    android:enabled="true"
    android:exported="true">
    <!--设置广播接收器的优先级,取整数值,数值大的优先级高-->
    <intent-filter android:priority="100">
        <action android:name="cn.edu.jssvc.wangyu.mybroadcasttest.MY_BROADCAST" />
    </intent-filter>
</receiver>

BroadcastReceiver实现类:

public class AnotherBroadcastReceiver extends BroadcastReceiver {
​
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"我是另外一个广播接收器",Toast.LENGTH_LONG).show();
    }
}

4.2.2 动态注册BroadcastReceiver

BroadcastReceiver实现类:

private class ForceOfflineReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(final Context context, Intent intent) {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle("提示");
        builder.setMessage("你已经被强制下线 请尝试再次登录");
        builder.setCancelable(false);
        builder.setPositiveButton("好的", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                ActivityCollector.finishAll();//销毁所有活动
                Intent intent = new Intent(context,LoginActivity.class);
                context.startActivity(intent);//重新启动LoginActivity
            }
        });
        builder.show();
    }
}

动态注册BroadcastReceiver的主要代码:

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("cn.edu.jssvc.wangyu.wybroadcastbestpractice.FORCE_OFFLINE");
receiver = new ForceOfflineReceiver();
registerReceiver(receiver,intentFilter);

动态注册的广播接收器是需要取消注册的,只需要调用unregisterReceiver()即可

4.2.3 发送广播

  • 发送标准(无序)广播:

    Intent intent = new Intent("cn.edu.jssvc.wangyu.mybroadcasttest.MY_BROADCAST");
    //出于安全考虑,目前自定义广播意图必须设置应用所在包名
    intent.setPackage(getPackageName());
    sendBroadcast(intent);
    
  • 发送无序广播:

    Intent intent = new Intent("cn.edu.jssvc.wangyu.mybroadcasttest.MY_BROADCAST");
    //出于安全考虑,目前自定义广播意图必须设置应用所在包名
    intent.setPackage(getPackageName());
    sendOrderedBroadcast(intent,null);
    

4.3 常用系统广播

  • Intent.ACTION_CONNECTIVITY_CHANGE
  • Intent.ACTION_BATTERY_CHANGED
  • Intent.ACTION_SCREEN_ON
  • Intent.ACTION_SCREEN_OFF
  • Intent.ACTION_PACKAGE_INSTALL
  • Intent.ACTION_BOOT_COMLETED
  • Intent.ACTION_PACKAGE_ADDED
  • Intent.ACTION_PACKAGE_REPLACED
  • Intent.ACTION_PACKAGE_REMOVED

5 ContentProvider

5.1 ContentProvider是什么

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

5.2 创建一个ContentProvider

  1. 在AndroidStudio中,右击包名→New→Other→Content,最后会弹出一个如下窗口:

    ps:Exported属性表示是否允许外部程序访问这个ContentProvider,Enabled属性表示是否启动这个ContentProvider

image-20220802205803860.png

  1. 在AndroidMainfest.xml中对ContentPrvider声明(使用步骤1方法创建会自动声明):

    <provider
        android:name=".DatabaseProvider"
        android:authorities="com.example.databasetest.provider"
        android:enabled="true"
        android:exported="true"></provider>
    
  2. 对创建的ContentProvider实现类中的方法进行重写

    • onCreate()

      初始化ContentProvider的时候调用。通常会在这里完成对数据库的创建和升级等操作,返回true表示ContentProvider初始化成功,返回false则表示失败。

    • query()

      从ContentProvider中查询数据。uri参数用于确定查询哪张表,projection参数用于确定查询哪些列,selection和selectionArgs参数用于约束查询哪些行,sortOrder参数用于对结果进行排序,查询的结果存放在Cursor对象中返回。

    • insert()

      向ContentProvider中添加一条数据。uri参数用于确定要添加到的表,待添加的数据保存在values参数中。添加完成后,返回一个用于表示这条新记录的URI。

    • update()

      更新ContentProvider中已有的数据。uri参数用于确定更新哪一张表中的数据,新数据保存在values参数中,selection和selectionArgs参数用于约更新哪些行,受影响的行数将作为返回值返回。

    • delete()

      从ContentProvider中删除数据。uri参数用于确定删除哪一张表中的数据,selection和selectionArgs参数用于约束删除哪些行,被删除的行数将作为返回值返回。

    • getType()

      根据传入的内容URI返回相应的MIME类型。

5.3 使用ContentResolver访问ContentProvider中共享的数据

这是对一个的ContentProvider中update()方法的使用示例:

// 更新数据
Uri uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
ContentValues values = new ContentValues();
values.put("name", "A Storm of Swords");
values.put("pages", 1216);
values.put("price", 24.05);
getContentResolver().update(uri, values, null, null);

6 Handler

6.1 Handler是什么

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

6.2 相关的几个概念

  • Message

    Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间传递数据。

  • MessageQueue

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

  • Looper

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

6.3 Handler基本用法

  1. 创建:新建Handler,实现handleMessage(Message)

        // 在UI主线程中创建可以跨线程传递数据的Handler对象,需要将一个MainLooper传递给构造方法
        private Handler handler = new Handler(Looper.getMainLooper()) {
            //实现handleMessage(),接收另一个线程发送来的Message对象
            public void handleMessage(Message msg) {
                // 根据Message的what字段判断消息对象是誰
                switch (msg.what) {
                    case UPDATE_TEXT:
                        // 从Message对象中取得obj字段携带的数据,这个字段是Object类型,可以携带任意类型+
                        String str = (String) msg.obj;
                        // 通过主界面中的TextView显示传递回来的数据
                        textView.setText(str);
                        break;
                    default:
                        break;
                }
            }
        };
    
  2. 构造Message:what/setData()

  3. 发送:子线程调用Handler.sendMessage(Message)发送Message

    new Thread(new Runnable() {
        @Override
        // 实现线程方法run(),这个方法中代码将运行在新开辟的线程中
     public void run() {
            // 创建Message对象
            Message message = new Message();
            // 设置Message对象的what字段值
            message.what = UPDATE_TEXT;
            // 设置Message对象的obj字段值,obj可以保存各种类型的数据
            message.obj = "大家好!我是后台线程产生的字符串!";
            // 调用Handler类对象的sendMessage()方法将数据传递回主线程
            handler.sendMessage(message);//将Message对象发送出去
       }
    }).start();// 调用Thread实例的start()启动线程运行
    
  4. 处理:在Handler的handleMessage(Message msg)主线程更新UI

Handler.png

7 Binder

7.1 Binder是什么

Binder是一种进程间的通信机制,基于开源的OpenBinder实现;OpenBinder起初由Be Inc.开发,后由Plam Inc.接手。从字面上来解释Binder有胶水、粘合剂的意思,顾名思义就是粘合不同的进程,使之实现通信。

7.2 常用IPC方案对比

IPC.png

7.3 Binder基本用法

服务端

  1. 定义一个AIDL文件
  2. 实现描述的接口,编写service
  3. 如果有实体类,需要提供实体类(jar包形式)

客户端

  1. 拿到AIDL文件
  2. 绑定服务,获得接口持有对象

7.4 Binder核心原理

Binder-3.png

三、总结

在之前Androi开发的学习中,学习的知识比较零散,东边一锄头西边一榔头的,经过这次对于Android基础知识的学习,使我对于Android知识体系有了更深的理解,后面还有很多的知识需要去学习,加油!