Android的widget初入門徑

1.什麼事widget
  widget就是android中的小插件或者控件,像音樂播放器爲我們提供的播放音樂時候在主頁顯示上曲、暫停、下一曲的控件,像天氣APP提供可以顯示天氣的控件等等。Android手機可以長按桌面空白部分就可以看到預覽的各個APP提供的控件,長按控件拖動到你想放的位置就能用啦。android四大組建Activity(活動)、Service(服務)、ContentProvider(數據提供)、BroadcastProvider(廣播)。widget繼承BroadcastProvider(廣播)本質上是一個廣播。

2.widget能幹什麼事
  widget是一個小控件,主要是以控件形式顯示在鎖屏頁面或者系統啓動時候進入的界面(我把他稱爲桌面)。想象一下你聽着歌,當你亮屏時候看到了是歌曲封面和歌詞這就是widget在鎖屏時候用處。

3.怎麼用widget

  3.1首先建一個繼承AppWidgetProvider自己的類MyAppWidgetProvider

public class MyAppWidgetProvider extends AppWidgetProvider {

    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context,intent);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.updateAppWidget(appWidgetIds, views);
    }

    @Override
    public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
        super.onAppWidgetOptionsChanged(context, 
    }

    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        super.onDeleted(context, appWidgetIds);
    }

    @Override
    public void onEnabled(Context context) {
        super.onEnabled(context);
    }

    @Override
    public void onDisabled(Context context) {
        super.onDisabled(context);
    }

    @Override
    public void onRestored(Context context, int[] oldWidgetIds, int[] newWidgetIds) {
        super.onRestored(context, oldWidgetIds, newWidgetIds);
    }
}

  顧名思義就知道這幾個方法幹什麼用的,詳細講解看下面。

3.2在AndroidManifest.xml中註冊我們新建的widget(廣播)

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

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

  標籤就是註冊BroadcastProvider(廣播)的,widget本質是廣播所以要在配置文件中註冊,android:name=“.MyAppWidgetProvider”指的就是我們剛剛建立的類MyAppWidgetProvider。

  

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/widget_layout"
    android:minWidth="300dp"
    android:minHeight="250dp"
    android:updatePeriodMillis="6890000"
    android:previewImage="@drawable/map">
</appwidget-provider>

標籤提供配置widget信息。

android:initialLayout=“”提供我們widget顯示效果,上文配置的widget顯示效果是layout文件夾下面widget_layout.xml文件控制。

android:minWidth控制顯示組件最小寬度

android:minHeight控制widget組件最小高度

android:updatePeriodMillis控制widget更新頻率單位是毫秒

android:previewImage控制長按桌面空白處調出控件添加按鈕時組件顯示的樣子。上文組件顯示的是在drawable文件下面的一張名map.png的圖片

更多具體標籤下屬性設置感興趣可以自行百度。

3.3編寫widget顯示的文件widget_layout.xml

  在layout文件下面新建widget_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
                      android:layout_width="390dp"
                      android:layout_height="177dp"
                      android:layout_gravity="center"
                      android:gravity="center">

        <ImageButton
            android:id="@+id/MapWidgetButton"
            android:layout_width="390dp"
            android:layout_height="177dp"
            android:paddingLeft="37dp"
            android:background="@drawable/map">
        </ImageButton>

</FrameLayout>

  此文件是顯示一個能響應事件的圖片。這之後你的widget就能顯示在安卓桌面上啊。當然只有能顯示而已,但是並不能響應事件,不要急,一口吃不成胖子,前面挖的坑會一一填上。

4.講解MyAppWidgetPrivoder類中各個方法
  4.1方法講解

public class MyAppWidgetProvider extends AppWidgetProvider {  
    private static final String CLICK_NAME_ACTION = "com.terry.action.widget.click";  
    public static final String TAG = "widget";   
    public static  RemoteViews rv;  
    /**  
     * 更新(Widget的更新與Activity不同,必須藉助於RemoteViews和AppWidgetMananger。)  
     */    
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){    
          Log.i(TAG, "onUpdate");  
          int N = appWidgetIds.length; // 可能啓動了多個Widget,appWidgetIds記錄了這些Widget的ID    
          for(int i=0; i<N; i++){   
              int appWidgetId = appWidgetIds[i];  
              rv = new RemoteViews(context.getPackageName(), R.layout.main);  
              Intent intentClick = new Intent(CLICK_NAME_ACTION);  
              PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,  
                      intentClick, 0);  
              rv.setOnClickPendingIntent(R.id.TextView01, pendingIntent);  
              appWidgetManager.updateAppWidget(appWidgetId, rv);  
          }     
    }    
    /**  
     * 第一個Widget組件啓動時觸發  
     */    
    public void onEnabled(Context context){    
          Log.i(TAG, "onEnabled");    
    }    
    /**  
     * 最後一個Widget組件關閉時觸發  
     */    
    public void onDisabled(Context context){    
          Log.i(TAG, "onDisabled");    
    }    
    /**  
     * 任一Widget組件被刪除時觸發  
     */    
    public void onDeleted(Context context, int[] appWidgetIds){    
          Log.i(TAG, "onDeleted");    
    }    
    /**  
     * 以上函數觸發前會先觸發該函數,一般不需要重寫  
     */    
    public void onReceive(Context context, Intent intent){    
          Log.i(TAG, "onReceive");    
          super.onReceive(context, intent);    
          if (rv == null) {  
              rv = new RemoteViews(context.getPackageName(), R.layout.main);  
          }  
          if (intent.getAction().equals(CLICK_NAME_ACTION)) {  
              rv.setTextViewText(R.id.TextView01, context.getResources()  
                      .getString(R.string.load));  
          }  
          AppWidgetManager appWidgetManger = AppWidgetManager.getInstance(context);  
          int[] appIds = appWidgetManger.getAppWidgetIds(new ComponentName(context, widgetProvider.class));  
          appWidgetManger.updateAppWidget(appIds, rv);  
    }       

  onReceive()方法接受各個方法消息並處理
  onUpdate()當第一個widget創建時執行本方法,widget更新時執行本方法。
   onDeleted()方法,任意一個widget被刪除時候執行此方法
   onEnabled()方法,當第一個widget被創建時候,執行此方法
   onDisabled()方法,當最後一個widget被執行時候執行此方法
  無論怎麼樣onReceive()方法總會執行的,去看下AppWidgetProvider類源代碼,onReceive()更像是個控制中心,根據不同的方法執行結果調用不同方法。比如:當onUpdate()方法被執行會發出一個android.appwidget.action.APPWIDGET_UPDATE的action給onUpdate()接收到action調用相應的方法。所以在自己類MyAppWidgetProvider的onReceive()方法中一定要在方法最後面加上super.onReceive();否則除了onReceive()方法外其他方法都不能執行。

  之前有人問爲什麼不在android中是用spring。spring的最重要之一就是aop解耦,而android已經爲了開發者提供了四大組件,已經解耦。這四大組件是由android系統控制執行時間和順序而不是由開發者,和javaWEB中的servlet一樣是由服務器控制執行。只需要記住四大組件類提供方法的執行順序和功能,如果提供的類不能滿足需求就去繼承重寫你想要的方法。有什麼不懂得去看官方API和源代碼,大部分問題都能解決。

4.2如何獲取視圖並對它操作
  widget本質上是在另一個進程中運行,不能用findViewById()方法獲得widget視圖對象。android爲我們提供了remoteView類來獲取不是本進程視圖對象並對操作。

 RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
        Intent intent = new Intent();                                                           //定義intent
        intent.setAction(ACTION);
        PendingIntent pendingIntentOne = PendingIntent.getBroadcast(context, 0, intent, 0);     //用PendingIntent將Intent包裹起來
        views.setOnClickPendingIntent(R.id.MapWidgetButton, pendingIntentOne);     

  本例中通過RemoteView獲得視圖對象views,創建Intent對象寫入ACTION並用篇PendingIntent包裹Intent,給圖片按鈕添加事件,通過ACTION傳給onRecive()方法,onRecive()接到廣播後執行對應的方法。

世界未亡,死不投降

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