RemoteViews的作用和原理

RemoteViews

RemoteView是一種遠程View,可以在其他進程中顯示。RemoteView在安卓中的使用主要有兩種:通知欄和桌面小部件。通知欄主要由NotifycationManager實現,桌面小部件主要由AppWidgetProvider實現,AppWidgetProvide其實是一個廣播。二者都運行在其他進程中,即SystemServer進程中。

通知欄

在開發中可以使用自定義佈局的通知欄時需要使用RemoteView:

 NotificationCompat.Builder builder1 = new NotificationCompat.Builder(this, Notification.CATEGORY_PROMO)
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setTicker("helloWord")
                        .setWhen(System.currentTimeMillis());
                Intent mIntent = new Intent(this, NotifyDetailActivity.class);
                PendingIntent pendingIntent = PendingIntent.getActivity(this, requestCode, mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
                Notification notification = builder1.build();
                RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_define_notify);
                remoteViews.setTextViewText(R.id.tv_title, "nihao");
                remoteViews.setTextViewText(R.id.tv_content, "nihao");
                remoteViews.setOnClickPendingIntent(R.id.open, pendingIntent);
                notification.contentView = remoteViews;
                notification.contentIntent = pendingIntent;
                NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                notificationManager.notify(1, notification);

RemoteView的創建主要由包名和佈局文件決定。

桌面小部件

新建一個類繼承AppWidgetProvider,需要在清單文件中註冊,因爲AppWidget是一個廣播

public class MyAppWidgetProvide extends AppWidgetProvider {

在onReciver中創建一個小部件

  @Override
    public void onReceive(final Context context, Intent intent) {
        super.onReceive(context, intent);
        if (intent.getAction() == CLICK_ACTION) {
            Toast.makeText(context, "click", Toast.LENGTH_SHORT).show();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Bitmap srcbBit = BitmapFactory.decodeResource(context.getResources(), R.mipmap.bg_clear);
                    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
                    for (int i = 0; i < 37; i++) {
                        float degree = (i * 10) % 360;
                        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
                        remoteViews.setImageViewBitmap(R.id.imageView, rotateBitmap(context, srcbBit, degree));
                        Intent mIntent = new Intent();
                        mIntent.setAction(CLICK_ACTION);
                        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, mIntent, 0);
                        remoteViews.setOnClickPendingIntent(R.id.imageView, pendingIntent);
                        appWidgetManager.updateAppWidget(new ComponentName(context, MyAppWidgetProvide.class), remoteViews);
                        SystemClock.sleep(300);
                    }
                }
            }).start();
        }
    }

RemoteView的內部機制

RemoteView沒有提供findViewByid的方法獲取View,但是提供了一系列的set方法例如setTextViewText等方法更新Ui,大部分的set方法是根據反射獲取的。
通知欄和桌面小部件是通過NotifycationManager和AppWidgetManager管理的,這二者又通過Binder和SystemServer中NotifycationManagerService和AppWidgetManagerService通信,這就構成了進程間的通信,但是系統並沒有通過Binder去支持所有的View和View的更新,而是將所有的View的操作放在了一個Action類中,當每次調用setXX方法時RemoteViews就會添加一個對應Action,當View進行更新操作時,就會將Action對象發送到遠程,遠程進程則會調用RemotesView的apply方法進行View的更新,最終View的更新操作則是由Action內部的apply方法控制的。
這裏寫圖片描述

本文參考《安卓開發藝術探索》。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章