zoukankan      html  css  js  c++  java
  • Android基础 Widget

    先来看下效果图. 这是仿三星FM收音机的一个widget.



    1. 首先在widget创建一个布局文件: layout/widget.xml.

    2. 在xml中创建xml/radioinfo.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="50.0dip"
        android:minWidth="300.0dip"
        android:previewImage="@drawable/fm_radio_widget_preview"
        android:resizeMode="vertical" />

    属性解释: android:initialLayout="@layout/widget"   : 指定widget的布局文件

      android:previewImage="@drawable/fm_radio_widget_preview"  指定widget在手机小部件中的缩略图.


    3.  创建一个继承AppWidgetProvider类FMRadioWidgetProvider.java, 并实现onUpdate , onReceive ,这两个函数.

           3.1 AppWidgetProvider解释:  这个类其实是一个广播接收器, 当widget被拖放到桌面的时候会首先调用onUpdate(Context context, AppWidgetManager appWidgetManager,
    int[] appWidgetIds)函数. 所以 , 一般在这个函数中做初始化操作.

    3.2 为按钮添加事件: 

    Intent intent = new Intent(FMRadioService.ACTION_FM_NEXT);
            intent.setClass(context, FMRadioService.class);
            pIntent = PendingIntent.getService(context, 0, intent, 0);
            remoteViews.setOnClickPendingIntent(R.id.ic_arrow_right, pIntent);


     当点击这个这个按钮的时候, 会发送一个Intent并FMRadioService类.  

      这种方式绑定的事件只能适用于单个View.  对于像ListView,  GridView这样的集合的item要绑定事件的话不适用. 这点后面讲到.

    3.3 为组件设置相关属性, 例如给TextView设置文本:

    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
    	remoteViews.setTextViewText(R.id.txt_frequency, String.valueOf(freq));


    最后: 要记得updateWidget一下: AppWidgetManager.getInstance(context).updateAppWidget(appWidgetIds, remoteViews); 一开始我就忘记了update , 导致widget没有显示 任何东西.

    3.4 为GridView/ListView绑定数据集: widget中的FM电台列表是一个GridView. 那么如何为GridView设置数据集呢.

    Intent intent = new Intent(context , FMRadioWidgetService.class);
    	intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    	intent.setData(FMRadioStation.Station.CONTENT_URI);
    	remoteViews.setRemoteAdapter(appWidgetId, R.id.widget_gridView, intent);


    设置数据集需要提供一个远程适配器. 适配器是一个RemoteViewsService类型的对象. 该类实现一个onGetViewFactory(Intent intent)函数:

    public class FMRadioWidgetService extends RemoteViewsService {
    
    		private final String LOGTAG = "FMRadioWidgetService"  ; 
    		private final boolean ISLOG = false ;
    	
    		@Override
    		public RemoteViewsFactory onGetViewFactory(Intent intent) {
    		
    			if(ISLOG)Log.d(LOGTAG , " FMRadioWidgetService::[onGetViewFactory ] intent = "+intent);
    		
    			return new FMRadioRemoteViewsFactory(getApplicationContext() , intent);
    		}
    	
    	}


    FMRadioRemoteViewsFactory才是一个正在的adapter. 该类实现RemoteViewsFactory接口, 并实现了onDataSetChanged() 和 getViewAt(int position)函数,

    此处getViewAt(int position)的实现类似我们传统Adapter的bindView()函数. 然后在onDataSetChanged() 一般会从数据库读取数据.

    @Override
    	public RemoteViews getViewAt(int position) {
    
    		RemoteViews rv = new RemoteViews(mContext.getPackageName() , R.layout.widget_item);
    		...
    		HashMap<String, Object> map = mlistStations.get(position);
    		rv.setTextViewText(R.id.widget_gv_txt_itme, freqStr);
    		...	
    		Intent fillInIntent = new Intent();
    		Bundle extras = new Bundle();
    		
    		extras.putInt(FMRadioAppWidgetProvider.EXTRA_SORT, position);
    		fillInIntent.putExtras(extras);
    		
    		// Make it possible to distinguish the individual on-click
    		// action of a given item
          
    		rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent);
    	
    		return rv;
    	}
    
    
    	@Override
    	public void onDataSetChanged() {
    	
    		queryFMradioStation();
    	
    	}


    在getViewAt()中为GridView的每一个item设置click事件:

    Intent fillInIntent = new Intent();
    Bundle extras = new Bundle();
     
    extras.putInt(FMRadioAppWidgetProvider.EXTRA_SORT, position);
    fillInIntent.putExtras(extras);

    // Make it possible to distinguish the individual on-click
    // action of a given item
          
    rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent);

    而该处的intent要与FMRadioWidgetProvider.java的onUpdate函数中的:

    // Set the action for the intent.
                // When the user touches a particular view, it will have the effect of
               // broadcasting TOAST_ACTION.
    itemClcikIntent.setAction(FMRadioAppWidgetProvider.ACTION_CLICK);
    itemClcikIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
                intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
                PendingIntent itemPendingIntent = PendingIntent.getBroadcast(context, 0, itemClcikIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
               remoteViews.setPendingIntentTemplate(R.id.widget_gridView, itemPendingIntent);

    这两处最终合成一个Intent. 当点击每一个item的时候, 会发送一个ACTION_CLICK的广播, 并且在FMRadioAppWidgetProvide接收广播后, 在onReceive中进行处理.

    整个widget大概基本完成.  

  • 相关阅读:
    React在componentDidMount里面发送请求
    React 术语词汇表
    React里受控与非受控组件
    React和Vue等框架什么时候操作DOM
    【LeetCode】79. Word Search
    【LeetCode】91. Decode Ways
    【LeetCode】80. Remove Duplicates from Sorted Array II (2 solutions)
    【LeetCode】1. Two Sum
    【LeetCode】141. Linked List Cycle (2 solutions)
    【LeetCode】120. Triangle (3 solutions)
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3106682.html
Copyright © 2011-2022 走看看