022.RemoteViews的介紹和使用

RemoteViews表示是一個可以在其他的進程中顯示View結構,由於它在其他進程中顯示,因此,我們刷新這個界面需要通過跨進程通信來實現,而RemoteViews    提供了一組基礎的操作用於更新界面。
    RemoteViews在Android中的使用場景有兩種:通知欄和桌面小部件。

    1.RemoteViews的應用
    RemoteViews在實際開發中,主要用在通知欄和桌面小部件的開發過程中。通知欄就是使用NotificationManager的notify方法來實現在通知欄顯示通知信息。使用NotificationManager我們可以使用默認的效果,也可以使用自定義的佈局(提供一個自定義佈局文件)。桌面小部件可以通過AppWidgetProvider來實現的,AppWidgetProvier本質上是使用廣播來實現的。通知欄和桌面小部件的開發過程中都會用到RemoteViews,它們在更新界面的時候,不能像在Activity那樣,直接拿View的對象來更新View的信息。這是因爲這兩個的界面都是運行在系統的SystemServer進程當中,屬於跨進程。爲了跨進程更新界面,RemoteViews提供了一系列set方法,並且這些方法都在View當中定義過,並且RemoteViews支持的View的類型也是有限制的。
    
    1.1 RemoteViews在通知欄上的應用    
    下面複習一下NotificationManager的使用:
    NotificationManager:通知欄的管理類,負責發通知、清除通知等。NotificationManager是一個系統的Service,獲取NotificationManager的對象需要調用Context的getSystemService()方法,如下:
    NotificationManager nm = ( Notificationmanager )getSystemService( Context.NOTIFICATION_SERVICE ) ;
    
    通過調用NotificationManager的notify方法,可以讓通知顯示出來,notify方法有2個參數,第一個參數是Notification的Id 這個ID是唯一的,當你的ID的通知已經存在就會覆蓋掉之前的,第二個是Notification的對象。下面來介紹一下Notification.

    Notification:是具體的狀態欄通知對象,可以設置icon、文字、提示聲音、震動等參數。

    基本參數爲:
  •     通知圖標 icon
  •     標題和內容 title and expanded message 
  •      點擊執行的跳轉   PendingIntent對象

    可選的設置:
  •     狀態欄頂部提示消息  A ticker-text message 
  •      提示音   An alert sound 
  •      震動       A vibrate setting 
  •      燈光       A flashing LED setting

    
    1.創建一個Notification:
     
   Notification notification = new Notification();
        notification.icon = R.drawable.ic_launcher;
        //通知時在狀態欄顯示的內容
        notification.tickerText = "hello_world";
        //設置通知的顯示時間
        notification.when = System.currentTimeMills();
        //意指點擊這個Notification後,立刻取消自身 
        notification.flags = Notification.FLAG_AUTO_CANCEL;

        //通知的默認參數 DEFAULT_SOUND, DEFAULT_VIBRATE, DEFAULT_LIGHTS.  
        //如果要全部採用默認值, 用 DEFAULT_ALL.  
        //此處採用默認聲音  
        notification.defaults = Notification.DEFAULT_SOUND ; 
        
        Intengt inetent =new Intent( MainActivity.this , TestActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity( MainActivity.this , 0 ,intent , PendingIntent.FLAG_UPDATE_CURRENT);
        notification.setLatestEventInfo( MainActivity.this , "TestTitle","TestMessage", pendingIntent);

        
         PendingIntent.FLAG_UPDATE_CURRENT會更新之前PendingIntent的消息,比如,你推送了消息1,並在其中的Intent中putExtra了一個值“ABC”,在未點擊該消息前,繼續推送第二條消息,並在其中的Intent中putExtra了一個值“CBA”,好了,這時候,如果你單擊消息1或者消息2,你會發現,他倆個的Intent中讀取過來的信息都是“CBA”,就是說,第二個替換了第一個的內容


         上面的代碼,我們就創建了一個通知,之後,我們是用如下代碼:
          nm.notify( 1 , notification);
          就可以彈出一個通知了,這個通知的ID 是1,我們可以通過ID 來找到這個通知,實現更新這個通知的信息,也可以取消這條通知。
    
        2.更新Notification 

          上面我們創建了一條ID爲1 的通知,現在我們需要更新這通知,那麼我們就採用如下:
           
 notification.setLatestEventInfo( MainActivity.this , "TestTitle2","TestMessage",pengdingIntent);
            nm.notify( 1 , notification );


            這樣就能更新通知的內容,如果我們把上面的1,換成2,那麼就會顯示2條通知,因爲ID不一樣,而我們如果不用之前的notification而是新建了一個Notification的對象,只要ID一樣 也是實現更新的效果。

            3.刪除Notification
             刪除Notification很簡單,只需要調用NotificationManager的cancel 方法,傳入ID就可以了
            
            4.Notification其他的設置
            (1)聲音:聲音可以通過使用如下代碼採用系統默認的聲音:
                    notification.defaults = Notification.DEFAULT_SOUND; 
                    如果要使用默認的,那麼就要使用到notification的sound屬性了,
                    也可以使用自定義鈴聲,就需要使用自定義的Uri了
                    比如使用SD卡的鈴聲如下:
                    notification.defaults = Uri.parse("file:///sdcard/notification/ringer.mp3");
                    使用raw目錄的鈴聲如下:
                    notification.defaults =  Uri.parse("android.resource://"+getPackageName()+"/"+R.raw.cat);
                    使用assets目錄下:
                    notification.defaults =  Uri.parse("file:///android_asset/RELATIVEPATH");
                    比如使用系統的鈴聲如下:
                    notification.sound = Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "6");  

                    如果default和sound同時出現,那麼sound設置的會無效。
                    默認情況下,通知的聲音播放一遍就結束,如果需要聲音循環播放,就要在flag上添加參數FLAG_INSISTENT 。這樣生意你回到用戶響應以後才停止,比如下拉狀態欄
                     notification.flags != notification.FLAG_INSISTENT;

             (2)震動:震動
                    如果是使用默認的震動方式,那麼也可以使用default
                    notification.defaults |= Notification.DEFAULT_VIBRATE;
                    
                    當然也可以自己定義震動形式,這個就需要使用Long數組,
                    long[] vibrate = {0,100,200,300};
                    notification.vibrate = vibrate;

                    在上面的Long型數組中,第一個參數是開始振動前的等待時間,第二個是第一次震動的時間,第三個是第二次震動的時間,以此類推,不過沒辦法做到重複震動。

                    同樣,如果有default 那麼就會採用default。
                    使用振動器之前我們需要在清單文件裏面聲明權限:

                 
   <uses-permission android:name="android.permission.VIBRATE"></uses-permission>  


        
                  (4)閃光
                    同樣的閃光也是有默認的,
                    notification.defaults |= Notification.DEFAULT_LIGHTS;
                    自定義:
                    notification.ledARGB = 0xff00ff00;  
                    notification.ledOnMS = 300;  
                    notification.ledOffMS = 1000;  
                    notification.flags |= Notification.FLAG_SHOW_LIGHTS;  
            
                    其中ledARGB 表示燈光顏色、 ledOnMS 亮持續時間、ledOffMS 暗的時間。
                  注意:這邊的顏色跟設備有關,不是所有的顏色都可以,要看具體設備。
            
            4.使用自定義樣式的通知欄
            使用自定義的通知,我們首先要提供一個佈局文件,然後使用RemoteViews來加載這個佈局文件就可以改變通知的樣式,代碼如下:
           
       
      Notification notification = new Notification();
            notification.icon = R.drawable.ic_launcher;
            notification.tickerText = "Test Ticker";
            notification.when = System.currentTimeMillis();
            notification.flags = Notification.FLAG_AUTO_CANCEL;
            Intent intent = new Intent( this , TestActivity.class);
            PendingIntent pengdingIntent = PendingIntent.getActivity( this , 0, intent , PendingIntent.FLAG_UPDATE_CURRENT );
            RemoteViews remoteViews = new RemoteViews( getPackageName(), R.layout.layout_notification);
            remoteViews.setTextViewText( R.id.tvTitle,"testTitle");
            remoteView.setImageViewResource( R.id.ivNotifyIcon,R.drawable.icon1);
            PendingIntent pd  = PendingIntent.getActivity( this , 0 , new Intent( this , TestActivity2.class),PendingIntent.FLAG_UPDATE_CURRENT);
            remoteViews.setOnClickPendingIntent( R.id.btnShowNotify, pd);
            notification.contentView = remoteVIews;
            notification.contentIntent = pengdingIntent;
            NotificationManager nm = ( NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE );
            manager.notify( 2 , notification);

        
            上面就是使用RemoteViews的代碼。RemoteViews提供了多種構造函數,在這邊,我們採用的是使用包名和佈局ID來創建一個RemoteViews。
            從上面的代碼,可以看到,我們在訪問RemoteViews的方法時候,和正常的訪問不一樣,我們並不是通過使用對象的引用來更新RemoteViews中的內容,而是RemoteViews提供了一些封裝過的方法,我們來更新。而如果我們需要在控件上添加點擊事件,可以在setOnClickPendingIntent使用PengdingIntent 實現,而且,RemoteViews也提供了反射機制,使得我們可以通過methodName和一些參數來調用指定ID上的方法(對參數還是有一些限制的)。
             
            5. 其他有用的設置:
             flags:
             Notification.FLAG_INSISTENT; //讓聲音、振動無限循環,直到用戶響應
             Notification.FLAG_AUTO_CANCEL;   //通知被點擊後,自動消失
             Notification.FLAG_NO_CLEAR; //點擊'Clear'時,不清楚該通知(QQ的通知無法清除,就是用的這個)

            
    上面就是RemoteView在Notification上的應用了,我們也回顧了Notification,下面開始學習RemoteViews在桌面小部件上的應用

     1.2 RemoteViews在桌面小部件上的應用

      AppWidgetProvider是Android中提供的用於實現桌面小部件的類,它的本質是一個廣播,也就是BrocastReceiver。所以說,AppWidgetProvider可以直接當成一個BrocastReceiver來使用。下面開始學習桌面小部件的開發步驟。
     1.2.1 定義小部件界面
      首先,我們在res/layout目錄下新建一個佈局文件layout_custom_appwidget.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/ivWidgetImg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_field"
        />

    </LinearLayout>


    1.2.2 定義小部件配置信息
        在res/xml下新建custom_appwidget_provider_info.xml
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
   android:initialLayout="@layout/layout_custom_appwidget"
     android:minWidth="@dimen/appwidget_min_width"
     android:minHeight="@dimen/appwiget_min_height"
     android:updatePeriodMillis="@integer/widget_updatePeriodMillis"
    >
</appwidget-provider>



    上面幾個參數的意義很明確,initialLayout指的是小工具使用的初始化佈局文件,minHeight和minWidth 定義小公舉的最小尺寸,updatePeriodMills定義小工具的自動更新週期,毫秒爲單位,每隔一個週期,小工具的自動更新就會觸發。

    3.定義小部件的實現類
  
  public class MyAppWidgetProvider extends AppWidgetProvider {

    public static final String TAG = "MyAppWidgetProvider";
    public static final String CLICK_ACTION = "com.zhenfei.MyAppWidgetProvider.action";


    public static final int NOTIFY_ID = 80001;

    public MyAppWidgetProvider()
    {
        super();
    }

    @SuppressLint("NewApi")
    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
        Log.e(TAG,   "onReceive: action=" + intent.getAction() );

        if( CLICK_ACTION.endsWith( intent.getAction()))
        {
            NotificationManager notificationManager =(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            Notification.Builder builder = new Notification.Builder(context);
            builder.setTicker( context.getResources().getString(R.string.notify_titker_text));
            builder.setWhen( System.currentTimeMillis() + 1000 );
            builder.setVibrate( new long [] { 0 , 200 , 400 , 600 , 800 } );
            builder.setDefaults( Notification.DEFAULT_SOUND );
            builder.setSmallIcon( R.drawable.ic_field );
            builder.setAutoCancel(true);

            Intent mIntent = new Intent(context ,MainActivity2.class );            
             mIntent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK);
             mIntent.setFlags( Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
            Log.e(TAG, "getPackageName:" + context.getPackageName() );

             PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, mIntent, 0);
            builder.setContentIntent(pendingIntent);

            RemoteViews remoteViews = new RemoteViews( context.getPackageName(),  R.layout.layout_custom_notification);
            remoteViews.setTextViewText(R.id.tvTitle , "有新的信息到了");
            remoteViews.setTextViewText( R.id.tvContent, "你到家了嗎");

            builder.setContent(remoteViews);            
            Notification notification = builder.build();
            notificationManager.notify(NOTIFY_ID, notification);
        }


    }

    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        // TODO Auto-generated method stub
        super.onDeleted(context, appWidgetIds);
    }

    @Override
    public void onDisabled(Context context) {
        // TODO Auto-generated method stub
        super.onDisabled(context);
    }

    @SuppressLint("NewApi")
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {

        Intent intent = new Intent();
        intent.setAction(CLICK_ACTION);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0    , intent, 0 );
        
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.layout_custom_appwidget);
        remoteViews.setOnClickPendingIntent(R.id.ivWidgetImg, pendingIntent);
      
        appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);

    }
 
}

在AndroidManifest.xml中聲明如下:
 <receiver 
            android:name="com.example.notificationdemo.MyAppWidgetProvider"

            >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
                <action android:name="com.zhenfei.MyAppWidgetProvider.action"/>
            </intent-filter>
            <meta-data 
                android:name="android.appwidget.provider"
                android:resource="@xml/custom_appwidget_provider_info"
                />
        </receiver>


    聲明這個部件類接受兩個廣播,一個是桌面部件更新廣播UPDATE,一個是自定義的按鈕事件廣播。AppWiget主要有:onEnable,onDisabled,onDeleted 和 onReceive這些方法:
  • onEnable : 當該窗口小部件第一次添加到桌面的時候調用這個方法,可以添加多次,但是隻在第一次調用。
  • onUpdate: 小部件被添加的時候或者每次小部件更新都會調用一次該方法,小部件的更新時機由updatePeriodMillis來指定,每個週期小部件都會自動更新一次。
  • onDeleted:每刪除一次桌面小部件就會調用一次。
  • onDisable:當最後一個桌面小部件被刪除的時候調用。
  • onReceive:這個是廣播的內置方法,用於分發事件。

並且爲它指定了meta-data ,這個meta-data 提供了這個部件的佈局。

    上面的代碼實現了一個簡單的桌面小部件,在小部件上面會顯示一個按鈕,點擊以後,這個按鈕就會發送一個廣播,廣播被自己接收,然後我們就會彈出一個通知,點擊通知會進入指定的Activity。桌面小部件在界面更新上都需要使用RemoteViews 不管是小部件的界面初始化還是界面更新都必須依賴它。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章