0%

理解 RemoteViews(三):RemoteViews 的意义

1. RemoteViews 的应用场景

  • 传统的应用场景:通知栏桌面小部件
  • 实际开发需求:现在有两个应用,一个应用需要能够更新另一个应用中的某个界面
    • AIDL: 如果对界面的更新比较频繁,此时会有效率问题,同时 AIDL 接口可能会很复杂
    • RemoteViews: 没有 AIDL 的性能问题,但缺点是仅支持常见的 View,不支持自定义 View

2. Demo: 实现一个模拟的通知栏效果并实现跨进程的 UI 更新

  • 需求

    • 有 2 个 Activity 分别运行在不同的进程中,一个名字叫 A,一个名字叫 B。其中 A 扮演着模拟通知栏的角色,而 B 则可以不停地发送通知栏消息
    • 修改 A 的 process 属性使其运行在单独的进程中,这样 A 和 B 就构成了多进程通信。在 B 中创建 RemoteViews 对象,然后通知 A 显示这个 RemoteViews 对象
    • 可以像系统一样采用 Binder 来实现,这里简单起见采用广播。B 每发送一次模拟通知,就会发送一个特定的广播,然后 A 接收到广播后就开始显示 B 中定义的 RemoteViews 对象
  • 实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // B 的实现
    RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_simulated_notification);
    remoteViews.setTextViewText(R.id.msg, "msg from process: " + Process.myPid());
    remoteViews.setImageViewResource(R.id.icon, R.drawable.icon1);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, DemoActivity_1.class), PendingIntent.FLAG_UPDATE_CURRENT);
    PendingIntent openActivity2PendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, DemoActivity_2.class), PendingIntent.FLAG_UPDATE_CURRENT);
    remoteViews.setOnClickPendingIntent(R.id.item_holder, pendingIntent);
    remoteViews.setOnClickPendingIntent(R.id.open_activity2, openActivity2PendingIntent);
    Intent intent = new Intent(MyConstants.REMOTE_ACTION);
    intent.putExtra(MyConstants.EXTRA_REMOTE_VIEWS, remoteViews);
    sendBroadcast(intent);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    // A 的实现
    public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";

    private LinearLayout mRemoteViewsContent;

    private BroadcastReceiver mRemoteViewsReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
    RemoteViews remoteViews = intent.getParcelableExtra(MyConstatns.EXTRA_REMOTE_VIEWS);
    if (remoteViews != null) {
    updateUI(remoteViews);
    }
    }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initView();
    }

    private void initView() {
    mRemoteViewsContent = (LinearLayout) findViewById(R.id.remote_views_content);
    IntentFilter filter = new IntentFilter(MyConstants.REMOTE_ACTION);
    registerReceiver(mRemoteViewsReceiver, filter);
    }

    private void updateUI(RemoteViews remoteViews) {
    // 会有资源 id 不一致的问题
    // View view = remoteViews.apply(this, mRemoteViewsContent); // 加载布局文件并执行更新操作
    // 解决 id 不一致问题:通过资源名称来加载布局文件
    int layoutId = getResources().getIdentifier("layout_simulated_notification", "layout", getPackagename());
    View view = getLayoutInflater().inflate(layoutId, mRemoteViewsContent, false);
    remoteViews.reapply(this, view);

    mRemoteViewContent.addView(view); // 将得到的 View 添加到 A 的布局中
    }

    @Override
    protected void onDestroy() {
    unregisterReceiver(mRemoteViewsReceiver);
    super.onDestroy();
    }
    }
-------------------- 本文结束感谢您的阅读 --------------------