快捷搜索:

亚洲必赢Android查缺补漏--ContentProvider的使用

2019-11-26 作者:故事寓言   |   浏览(200)
  • ContentProvider:对外提供数据的访问接口。
  • Uri:ContentProvider的唯一标识,外界可根据其访问对应的ContentProvider。
  • ContentResolver
  • 发送广播的Broadcast
  • 接受广播的BroadcastReceiver
  • 传递信息的Intent

ContentProvider (内容提供者)是一种共享型组件,可以为系统内应用于与应用之间提供访问接口。

广播又分为普通广播、有序广播、本地广播和sticky广播。

ContentProvide要想正常工作需要三个关键点:

广播的注册分为静态注册和动态注册:

比如,当应用A想把自己数据暴露出来让别的应用也可以操作的话,就可以在应用A内部创建一个ContentProvider实现相关方法并添加URI,然后在其他应用中(应用B)就可以通过ContentResolver和URI来访问应用A中的ContentProvider了。

四、sticky广播(不建议使用)

sticky广播会一直处于滞留状态,sticky广播被发出后,只要有能够匹配其的新接收器被注册了就可以收到广播,sticky广播通过Context.sendStickyBroadcast()发送。


最后想说的是,本系列文章为博主对Android知识进行再次梳理,查缺补漏的学习过程,一方面是对自己遗忘的东西加以复习重新掌握,另一方面相信在重新学习的过程中定会有巨大的新收获,如果你也有跟我同样的想法,不妨关注我一起学习,互相探讨,共同进步!

参考文献:

  • 《Android开发艺术探索》
  • 《Android开发进阶从小工到专家》

二、调用系统的ContentProvider

除了我们自己创建ContentProvider,Android系统也给我们提供了丰富的ContentProvider接口,这里就以操作系统的联系人为例来说明一下怎使用系统提供的ContentProvider接口。

  • ContactsContract.Contacts.CONTENT_URI:联系人Uri。
  • ContactsContract.CommonDataKinds.Phone.CONTENT_URI:联系人电话号码Uri。

1、查询系统联系人

通过系统联系人的Uri获取系统联系人及手机号码:

public void query() {
    showContact = "";
    // 获取联系人的Cursor集合
    Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
    while (cursor.moveToNext()) {
        // 获取联系人id
        String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
        // 获取联系人姓名
        String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));

        // 获取当前联系人id下的所有电话号码
        Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + id, null, null);
        showContact += "--id="+ id + " | name=" + name + "--n";
        Log.i(TAG, "onCreate: ------id="+ id + " | name=" + name + "------");
        while (phones.moveToNext()) {
            String phone = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
            showContact += "phone = " + phone + "n";
            Log.i(TAG, "onCreate: phone = " + phone);
        }
        phones.close();
    }
    cursor.close();
    tv_show.setText(showContact);
}

查询后log如下:

12-13 17:19:49.490 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=1 | name=张飞------
12-13 17:19:49.490 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 151 1511 1511
12-13 17:19:49.499 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=2 | name=关羽------
12-13 17:19:49.499 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 153 6969 3869
12-13 17:19:49.499 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 135 6497 8664
12-13 17:19:49.499 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 155 5555 5555
12-13 17:19:49.499 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 133 3333 3333
12-13 17:19:49.508 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=3 | name=刘备------
12-13 17:19:49.508 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 156 9637 5648
12-13 17:19:49.508 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 153 7564 8643
12-13 17:19:49.520 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=14 | name=吕布------
12-13 17:19:49.520 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15678909087
12-13 17:19:49.529 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=20 | name=孙权------
12-13 17:19:49.529 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15366669999
12-13 17:19:49.538 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=21 | name=曹操------
12-13 17:19:49.538 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15699788966
12-13 17:19:49.547 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=22 | name=马超------
12-13 17:19:49.547 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15366999966

2、添加系统联系人:

public void insert() {
    String name = et_name.getText().toString();
    String phone = et_phone.getText().toString();

    if (TextUtils.isEmpty(name) || TextUtils.isEmpty(phone)) {
        Toast.makeText(getApplicationContext(), "不能为空", Toast.LENGTH_LONG).show();
        return;
    }

    ContentValues values = new ContentValues();

    // 往插入一个空值以便获取id
    Uri rawContactUri = getContentResolver().insert(ContactsContract.RawContacts.CONTENT_URI, values);
    long rawContactId = ContentUris.parseId(rawContactUri);

    // ------插入联系人姓名------
    // 设置id
    values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
    // 设置内容类型
    values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
    // 设置名字
    values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, name);
    // 插入姓名
    getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
    values.clear();

    // ------插入联系人电话------
    values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
    values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
    values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone);
    values.put(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
    getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);

    Toast.makeText(getApplicationContext(), "添加成功", Toast.LENGTH_LONG).show();
    query();
}

在输入框中输入联系人姓名(诸葛亮)及电话号码(13696969696),然后点击添加按钮,log如下:

12-13 17:23:37.577 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=1 | name=张飞------
12-13 17:23:37.577 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 151 1511 1511
12-13 17:23:37.589 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=2 | name=关羽------
12-13 17:23:37.590 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 153 6969 3869
12-13 17:23:37.590 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 135 6497 8664
12-13 17:23:37.590 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 155 5555 5555
12-13 17:23:37.590 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 133 3333 3333
12-13 17:23:37.603 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=3 | name=刘备------
12-13 17:23:37.603 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 156 9637 5648
12-13 17:23:37.603 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 153 7564 8643
12-13 17:23:37.616 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=14 | name=吕布------
12-13 17:23:37.617 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15678909087
12-13 17:23:37.630 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=20 | name=孙权------
12-13 17:23:37.630 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15366669999
12-13 17:23:37.657 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=21 | name=曹操------
12-13 17:23:37.657 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15699788966
12-13 17:23:37.671 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=22 | name=马超------
12-13 17:23:37.671 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15366999966
12-13 17:23:37.712 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=23 | name=诸葛亮------
12-13 17:23:37.712 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 13696969696

可以看到,诸葛亮和电话号码已经被成功添加进去了。

当然,除了以上几个Uri,系统的ContentProvider接口还有很多很多,就不一一举例了,用到时可以查询官方API。


最后想说的是,本系列文章为博主对Android知识进行再次梳理,查缺补漏的学习过程,一方面是对自己遗忘的东西加以复习重新掌握,另一方面相信在重新学习的过程中定会有巨大的新收获,如果你也有跟我同样的想法,不妨关注我一起学习,互相探讨,共同进步!

参考文献:

  • 《Android开发艺术探索》
  • 《Android开发进阶从小工到专家》

很多人都会觉得ContentProvider很难理解,因为很多书上在介绍ContentProvider是后上来就用很复杂的方式来讲解,还结合什么数据库、xml等等之类操作,搞得看起来很复杂,让很多的初学者望而却步,其实我们完全不必害怕。你可以把ContentProvider看做是一个网站,在生活中你想访问一个网站就必须要有一个URL地址,而这里的URI就好比这个URL地址,然后就可以用ContentResolver拿着这个这个URI地址去访问了。

Broadcast 是一种被用于应用内和应用之间传递信息的机制。一个广播可以对应多个接受者。一个完整的广播机制,需要具有以下三个要素:

一、创建自己的ContentProvider

  • 创建ContentProvider。

创建一个自己的ContentProvider也很简单,同四大组件中其他的组件类似,首先继承系统ContentProvider来创建一个类,并实现相关方法:

public class UserInfoProvider extends ContentProvider {

    static final String TAG = UserInfoProvider.class.getSimpleName();

    @Override
    public boolean onCreate() {
        Log.i(TAG, "onCreate: ");
        return false;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {
        Log.i(TAG, "query: ");
        return null;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        Log.i(TAG, "getType: ");
        return null;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
        Log.i(TAG, "insert: ");
        return null;
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {
        Log.i(TAG, "delete: ");
        return 0;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {
        Log.i(TAG, "update: ");
        return 0;
    }
}

然后再 AndroidMainfest.xml 中注册并添加 authorities,这个authorities就是传入到URI中用的,注意要将exported设为true这样外界才能访问到。

<provider
    android:name=".contentprovides.UserInfoProvider"
    android:authorities="cn.codingblock.androidadvancestudy.contentprovides.UserInfoProvider"
    android:exported="true" />

一个基本的ContentProvider创建好了,接下来要做的就是使用ContentResolver来访问它了。

  • 解析Uri

解析Uri使用Uri.parse()来解析,传入对应的参数,参数格式为:
content://authorities/ 对应于上面的UserInfoProvider来说,一个URI为:

Uri uri = Uri.parse("content://cn.codingblock.androidadvancestudy.contentprovides.UserInfoProvider/");
  • 通过Context.getContentResolver()获取ContentResolver对象。

    ContentResolver contentResolver = getContentResolver();
    

    我们另外新建一个工程,暂且叫做TestApp吧,在这个新的工程里面添加一个Activity,在Activity中使用ContentResolver,通过URI来访问上面的(不同应用中)ContentProvider。

public class UserInfoResolverActivity extends AppCompatActivity implements View.OnClickListener {

    private final static String TAG = UserInfoResolverActivity.class.getSimpleName();

    private ContentResolver contentResolver;
    private Uri uri = Uri.parse("content://cn.codingblock.androidadvancestudy.contentprovides.UserInfoProvider/");

    Button btn_insert;
    Button btn_query;
    Button btn_update;
    Button btn_delete;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_info_resolver);
        // 获取ContentResolver对象
        contentResolver = getContentResolver();

        btn_insert = (Button) findViewById(R.id.btn_insert);
        btn_query = (Button) findViewById(R.id.btn_query);
        btn_update = (Button) findViewById(R.id.btn_update);
        btn_delete = (Button) findViewById(R.id.btn_delete);

        btn_insert.setOnClickListener(this);
        btn_query.setOnClickListener(this);
        btn_update.setOnClickListener(this);
        btn_delete.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_insert:
                insert();
                break;

            case R.id.btn_query:
                query();
                break;

            case R.id.btn_update:
                update();
                break;

            case R.id.btn_delete:
                delete();
                break;
        }

    }

    public void insert() {
        Uri tempUri = contentResolver.insert(uri, values);
        Log.i(TAG, "insert: tempUri = " + tempUri);
    }

    public void query() {
        Cursor cursor = contentResolver.query(uri, null, "where", null, null);
        Log.i(TAG, "query: cursor = " + cursor);
    }

    public void update() {
        int n = contentResolver.update(uri, values, "where", null);
        Log.i(TAG, "update: n = " + n);
    }

    public void delete() {
        int n = contentResolver.delete(uri, "where", null);
        Log.i(TAG, "delete: n = " + n);
    }
}

需要注意一点是,这个UserInfoProvider和UserInfoResolverActivity并没有在同一个应用中,UserInfoProvider在AndroidAdvanceStudy这个应用里面,他的进程名是:cn.codingblock.androidadvancestudy。UserInfoResolverActivity在TestApp应用里面,进程名是:cn.codingblock.testapp。

在testApp点击以上的增、查、改、删按钮,log如下:

12-12 15:06:26.846 28104-28118/cn.codingblock.androidadvancestudy I/UserInfoProvider: insert: 
12-12 15:06:28.070 28104-28118/cn.codingblock.androidadvancestudy I/UserInfoProvider: query: 
12-12 15:06:29.733 28104-28118/cn.codingblock.androidadvancestudy I/UserInfoProvider: update: 
12-12 15:06:30.376 28104-28118/cn.codingblock.androidadvancestudy I/UserInfoProvider: delete: 

看,我们是在TestApp应用中做的相关操作,果然可以调用AndroidAdvanceStudy里面的UserInfoProvider。

ContenProvider就是这么简单,当然 ContentProvider 的功能远不止如此,我们也可以结合数据库或者SharePreference等实现更加复杂的对外数据操作。

<receiver android:name=".broadcast.MyBroadcastReceiver">
    <intent-filter>
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

一、普通广播

普通广播通过Context.sendBroadcast()发送,我们没有办法制定Receiver们对于普通广播的接收顺序。理论上所有的接收器(Receiver)接收到广播的顺序不确定,但一般是按照其在AndroidMainfest.xml文件中注册的顺序(不绝对)。
普通广播中,接受者不能将处理结果传递给下一个接收器,也无法终止广播的传播。

如下代码是一个静态注册的广播示例:

public class MyBroadcastReceiver extends BroadcastReceiver {

    String TAG = MyBroadcastReceiver.class.getSimpleName();

    public static final String ACTION = "MY_BROADCAST_RECEIVER";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "接收到广播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
    }
}

然后再AndroidMainfest.xml中注册这个广播:

<receiver android:name=".broadcast.MyBroadcastReceiver">
    <intent-filter>
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

接下来在Activity中调用Context.sendBroadcast()发送广播就可以了:

Intent intent = new Intent(MyBroadcastReceiver.ACTION);
intent.putExtra(INTENT_INFO, "我是一个普通广播");
sendBroadcast(intent);

log如下:

12-08 17:29:44.259 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到广播消息:我是一个普通广播
  • 普通广播的接收顺序测试
    我们仿照MyBroadcastReciver创建多个接收器,代码一样:
/**
 * 静态注册的广播接收器2
 * Created by liuwei on 17/12/7.
 */
public class MyBroadcast2Receiver extends BroadcastReceiver {

    String TAG = MyBroadcast2Receiver.class.getSimpleName();

    public static final String ACTION = "MY_BROADCAST_RECEIVER";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "接收到广播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
    }
}
/**
 * 静态注册的广播接收器3
 * Created by liuwei on 17/12/7.
 */
public class MyBroadcast3Receiver extends BroadcastReceiver {...}
/**
 * 静态注册的广播接收器4
 * Created by liuwei on 17/12/7.
 */
public class MyBroadcast4Receiver extends BroadcastReceiver {...}
/**
 * 静态注册的广播接收器5
 * Created by liuwei on 17/12/7.
 */
public class MyBroadcast5Receiver extends BroadcastReceiver {...}
/**
 * 静态注册的广播接收器6
 * Created by liuwei on 17/12/7.
 */
public class MyBroadcast6Receiver extends BroadcastReceiver {...}

然后在AndroidMainfest.xml中为以上广播都注册同一个action

<receiver android:name=".broadcast.MyBroadcastReceiver">
    <intent-filter>
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast6Receiver">
    <intent-filter>
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast2Receiver">
    <intent-filter>
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast3Receiver">
    <intent-filter>
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast4Receiver">
    <intent-filter>
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast5Receiver">
    <intent-filter>
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

点击发送广播,查看log:

12-08 17:29:44.259 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到广播消息:我是一个普通广播
12-08 17:29:44.268 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到广播消息:我是一个普通广播
12-08 17:29:44.271 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到广播消息:我是一个普通广播
12-08 17:29:44.273 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast3Receiver: 接收到广播消息:我是一个普通广播
12-08 17:29:44.277 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast4Receiver: 接收到广播消息:我是一个普通广播
12-08 17:29:44.280 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: 接收到广播消息:我是一个普通广播
  • 静态注册:静态注册的广播是指在AndroidManifest中注册的广播,此种广播在应用安装时就被系统解析,不需要启动应用就可以收到相应的广播。

三、本地广播

以上的广播对于系统来说是全局的,发出广播后,系统内的应用只要注册了相应的接收器就都可以收到广播。如果我们想在本应用发出的广播只在此应用内可以收到,那么可以使用本地广播了。

本地广播由 LocalBroadcastManager 管理,是在 API 21 以后添加的,使用起来也很方便,需要先通过 LocalBroadcastManager.getInstance() 方法获取其单例,剩下的用法与其他广播类似,其主要方法有以下几个:

  • registerReceiver():注册广播接收器。
  • unregisterReceiver():解除广播接收器。
  • sendBroadcast():发送异步广播。
  • sendBroadcastSync():发送同步广播。

使用本地广播时,无需在AndroidMainfest.xml中注册,必须使用 LocalBroadcastManager.getInstance(...).registerReceiver(..)来注册接收器。

我们来写个本地广播的小栗子,首先注册两个本地广播:

LocalBroadcastManager.getInstance(context).registerReceiver(new MyBroadcastReceiver(), new IntentFilter(MyBroadcastReceiver.ACTION));
LocalBroadcastManager.getInstance(context).registerReceiver(new MyBroadcast2Receiver(), new IntentFilter(MyBroadcastReceiver.ACTION));

然后发送本地广播:

intent.putExtra(INTENT_INFO, "我是一个本地广播");
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);

log如下:

12-09 17:20:47.799 15019-15019/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到广播消息:我是一个本地广播
12-09 17:20:47.799 15019-15019/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到广播消息:我是一个本地广播

二、有序广播

在AndroidMainfest.xml中注册广播时通过priority(值越优先级越高)节点为广播添加优先级,然后再用Context.sendOrderedBroadcast()发送,接收者们就会按照优先级顺序依次执行。

有序广播的接收者和给下一个接收者传递数据,并且接收者在收到广播之后可以抛弃广播,使广播不再向后传递。

为上面6个接收器添加优先级:

<receiver android:name=".broadcast.MyBroadcastReceiver">
    <intent-filter android:priority="1">
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast6Receiver">
    <intent-filter android:priority="6">
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast2Receiver">
    <intent-filter android:priority="2">
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast3Receiver">
    <intent-filter android:priority="3">
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast4Receiver">
    <intent-filter android:priority="4">
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcast5Receiver">
    <intent-filter android:priority="5">
        <action android:name="MY_BROADCAST_RECEIVER" />
    </intent-filter>
</receiver>

然后通过sendOrderedBroadcast发送广播观察log:

intent = new Intent(MyBroadcastReceiver.ACTION);
intent.putExtra(INTENT_INFO, "我是一个有序广播");
sendOrderedBroadcast(intent, null);

log如下:

12-08 18:17:26.455 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到广播消息:我是一个有序广播
12-08 18:17:26.462 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: 接收到广播消息:我是一个有序广播
12-08 18:17:26.464 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast4Receiver: 接收到广播消息:我是一个有序广播
12-08 18:17:26.465 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast3Receiver: 接收到广播消息:我是一个有序广播
12-08 18:17:26.466 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到广播消息:我是一个有序广播
12-08 18:17:26.467 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到广播消息:我是一个有序广播
  • abortBroadcast()抛弃广播:
    普通的广播是没有办法抛弃的,否则会抛出RuntimeException的异常。

只有有序广播才可以通过此方法抛弃。我们在MyBroadcast6Receiver中添加abortBroadcast()方法:

public class MyBroadcast6Receiver extends BroadcastReceiver {

    String TAG = MyBroadcast6Receiver.class.getSimpleName();

    public static final String ACTION = "MY_BROADCAST_RECEIVER";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "接收到广播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
        abortBroadcast();
        Log.i(TAG, "丢弃广播");
    }
}

然后点击发送有序广播,log如下:

12-08 18:34:27.989 1329-1329/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到广播消息:我是一个有序广播
12-08 18:34:27.989 1329-1329/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 丢弃广播

可以看到广播已经被丢弃了。

  • setResult()传递给下一个接收者结果。
  • getResult()接收上一个接收者的结果。

在MyBroadcast6Receiver中添加setResult方法,在MyBroadcast5Receiver添加getResult方法:

public class MyBroadcast6Receiver extends BroadcastReceiver {

    String TAG = MyBroadcast6Receiver.class.getSimpleName();

    public static final String ACTION = "MY_BROADCAST_RECEIVER";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "接收到广播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
//        abortBroadcast();
//        Log.i(TAG, "丢弃广播");
        setResult(006, "我是老6传来的消息", null);
    }
}
public class MyBroadcast5Receiver extends BroadcastReceiver {

    String TAG = MyBroadcast5Receiver.class.getSimpleName();

    public static final String ACTION = "MY_BROADCAST_RECEIVER";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "接收到广播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
        String data = getResultData();
        Log.i(TAG, "data=" + data);
    }
}

log如下:

12-08 18:40:01.415 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到广播消息:我是一个有序广播
12-08 18:40:01.434 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: 接收到广播消息:我是一个有序广播
12-08 18:40:01.434 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: data=我是老6传来的消息
12-08 18:40:01.440 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast4Receiver: 接收到广播消息:我是一个有序广播
12-08 18:40:01.442 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast3Receiver: 接收到广播消息:我是一个有序广播
12-08 18:40:01.445 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到广播消息:我是一个有序广播
12-08 18:40:01.447 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到广播消息:我是一个有序广播
  • 动态注册:通过Context.registerReceiver()来实现,不需要时要通过Context.unRegisterReceiver()解除广播,此种广播必须应用启动后才能注册并接收广播。

    // 动态注册广播接收器
    registerReceiver(new DynamicBroadcastReceiver(), new IntentFilter(MyBroadcastReceiver.ACTION));
    

本文由亚洲必赢官方登录发布于故事寓言,转载请注明出处:亚洲必赢Android查缺补漏--ContentProvider的使用

关键词: