RemoteViews在桌面小部件和通知欄的使用

(《Android開發藝術探索》讀書筆記)

什麼是RemoteViews:
它所表示的是一個View結構,可以在其他進程中顯示,也就是可以跨進程更新它的界面。
RemoteViews的應用場景:
通知欄和桌面小部件(都運行在系統的SystemServer進程)。

首先說明桌面小部件的開發步驟:

1、定義小部件界面:
/桌面小部件/res/layout/widget.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/iv_img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher" />

</LinearLayout>

2、定義小部件配置信息:
/桌面小部件/res/xml/appwidget_provider_info.xml

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/widget"
    android:minHeight="84dp"
    android:minWidth="84dp"
    android:updatePeriodMillis="86400000" >

</appwidget-provider>

3、定義小部件的實現類:
/桌面小部件/src/com/example/remoteviews/MyAppWidgetProvider.java

/**
 * 桌面小部件演示
 * @author Administrator
 *
 */
public class MyAppWidgetProvider extends AppWidgetProvider {
    public static final String TAG = "MyAppWidgetProvider";
    public static final String CLICK_ACTION = "com.example.remoteviews";

    public MyAppWidgetProvider() {
        super();
    }

    @Override
    public void onEnabled(Context context) {
        super.onEnabled(context);
        Toast.makeText(context, "第一次添加小部件會調用我", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onDisabled(Context context) {
        super.onDisabled(context);
        Toast.makeText(context, "最後一個小部件已被刪除!", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        super.onDeleted(context, appWidgetIds);
        Toast.makeText(context, "小部件已被刪除!", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onReceive(final Context context, Intent intent) {
        super.onReceive(context, intent);
        Log.i(TAG, "onReceive:action=" + intent.getAction());
        // 這裏判斷自己的action,做自己的事情
        if (intent.getAction().equals(CLICK_ACTION)) {
            Toast.makeText(context, "我在旋轉", Toast.LENGTH_SHORT).show();
            new Thread(new Runnable() {

                @Override
                public void run() {
                    Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
                            R.drawable.ic_launcher);

                    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.iv_img,
                                rotateBitmap(context, bitmap, degree));

                        Intent intent = new Intent();
                        intent.setAction(CLICK_ACTION);
                        PendingIntent pendingIntent = PendingIntent.getBroadcast(
                                context, 0, intent, 0);

                        remoteViews.setOnClickPendingIntent(R.id.iv_img, pendingIntent);
                        appWidgetManager.updateAppWidget(
                                new ComponentName(context, MyAppWidgetProvider.class), remoteViews);
                        SystemClock.sleep(30);
                    }
                }

            }).start();
        }
    }

    /**
     * 每次桌面小部件更新時都調用一次該方法
     */
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        Toast.makeText(context, "每次更新小部件會調用我!", Toast.LENGTH_SHORT).show();

        final int counter = appWidgetIds.length;
        Log.i(TAG, "counter = "+ counter);
        for (int i = 0; i < counter; i++) {
            int appWidgetId = appWidgetIds[i];
            onWidgetUpdate(context, appWidgetManager, appWidgetId);
        }
    }

    /**
     * 桌面小部件更新
     * @param context
     * @param appWidgetManager
     * @param appWidgetId
     */
    private void onWidgetUpdate(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
        Log.i(TAG, "appWidgetId = " + appWidgetId);
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);

        // 桌面小部件單擊事件發送的Intent廣播
        Intent intent = new Intent();
        intent.setAction(CLICK_ACTION);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
        remoteViews.setOnClickPendingIntent(R.id.iv_img, pendingIntent);
        appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
    }

    /**
     * 旋轉
     * @param context
     * @param bitmap
     * @param degree
     * @return
     */
    private Bitmap rotateBitmap(Context context, Bitmap bitmap, float degree) {
        Matrix matrix = new Matrix();
        matrix.reset();
        matrix.setRotate(degree);
        Bitmap tmpBitmap = Bitmap.createBitmap(bitmap, 0, 0,
                bitmap.getWidth(), bitmap.getHeight(),
                matrix, true);
        return tmpBitmap;
    }
}

4、在AndroidManifest.xml中聲明小部件:

        <receiver android:name=".MyAppWidgetProvider" >
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/appwidget_provider_info" />

            <intent-filter>
                <action android:name="com.example.remoteviews" />
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
        </receiver>

第一個action用於識別小部件的單擊行爲;
第二個action作爲小部件的標識必須存在,這是系統的規範。

運行後,在主界面添加桌面小部件,點擊後會發現小部件旋轉一週。
重複添加後就特別壯觀:
這裏寫圖片描述
然後說明RemoteViews在通知欄上的應用:
系統默認的通知:

        Notification notification = new Notification();
        notification.icon = R.drawable.ic_launcher;
        notification.tickerText = "hello world";
        notification.when = System.currentTimeMillis();
        notification.flags = Notification.FLAG_AUTO_CANCEL;

        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        notification.setLatestEventInfo(this, "標題", "內容", pendingIntent);

        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        manager.notify(1, notification);

上述代碼會彈出一個系統默認樣式的通知,點擊後會清除本身。
這裏寫圖片描述
使用RemoteViews實現自定義通知:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <TextView
        android:id="@+id/tv_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        android:textSize="25sp" />

    <ImageView
        android:id="@+id/iv_img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher" />

</LinearLayout>

代碼實現:

        Notification notification = new Notification();
        notification.icon = R.drawable.ic_launcher;
        notification.tickerText = "hello world";
        notification.when = System.currentTimeMillis();
        notification.flags = Notification.FLAG_AUTO_CANCEL;

        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.my_notification);
        remoteViews.setTextViewText(R.id.tv_text, "自定義通知欄");
        remoteViews.setImageViewResource(R.id.iv_img, R.drawable.ic_launcher);

        PendingIntent pendingIntent2 = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        remoteViews.setOnClickPendingIntent(R.id.tv_text, pendingIntent2);
        notification.contentView = remoteViews;
        notification.contentIntent = pendingIntent;

        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        manager.notify(2, notification);

這裏寫圖片描述
RemoteViews所支持的View類型:
Layout: FrameLayout、RelativeLayout、LinearLaout、GridLayout
View: AnalogClock、Button、Chronometer、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView、AdapterViewFlipper、ViewStub。

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