自定义桌面小部件

《自定义桌面小部件》

#RemoteView 自定义桌面小部件
效果如上图, class AppWidgetProvider extends BroadcastReceiver,不难看出桌面小部件本质上是一个广播,至于为什么是一个广播的形势,我猜…是因为桌面小部件运行在SystemService进程中,通过PendingIntent这种方式传递,避免了自己写IPC通信。

#自定义小部件统共分几步

###1.定义小部件界面

在layout 下创建xml 文件

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/tv_content"
        android:src="@mipmap/ic_launcher"
        android:gravity="center"
        android:textSize="20sp"
        android:layout_width="100dp"
        android:layout_height="100dp" />
</RelativeLayout>

###2.定义小部件配置信息
通过as自带的创建app widget功能会自动创建该文件,否则需要手动指定,定义小部件刷新,最小宽高等信息

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialKeyguardLayout="@layout/new_app_widget"
    android:initialLayout="@layout/new_app_widget"
    android:minHeight="110dp"
    android:minWidth="110dp"
    android:previewImage="@mipmap/ic_launcher"
    android:resizeMode="horizontal|vertical"
    android:updatePeriodMillis="86400000"
    android:configure="com.example.fushuang.activity.MainActivity"
    android:widgetCategory="home_screen" />
  • resizeMode 小部件可伸缩方向
  • minHeight,minWidth 小部件最宽高
  • previewImage 拖动到桌面前的预览图片
  • nitialLayout初始化布局
  • updatePeriodMillis小部件的刷新间隔,单位是秒,默认是一天
  • android:configure 指定小部件添加是的配置页面 配置页面需调用 setResult(RESULT_OK, resultValue);

###3. 继承AppWidgetProvider

public class NewAppWidget extends AppWidgetProvider {

    private static final String fs="com.example.admin.customview.click";

    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                                int appWidgetId) {

        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
        Intent clickIntent = new Intent();

        clickIntent.setAction(fs);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, clickIntent, 0);
        remoteViews.setOnClickPendingIntent(R.id.tv_content,pendingIntent);

        // Instruct the widget manager to update the widget
        appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // There may be multiple widgets active, so update all of them
        for (int appWidgetId : appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId);
        }
    }
    @Override
    public void onEnabled(Context context) {
        // Enter relevant functionality for when the first widget is created
    }

    @Override
    public void onDisabled(Context context) {
        // Enter relevant functionality for when the last widget is disabled
    }

    @Override
    public void onReceive(final Context context, Intent intent) {
        super.onReceive(context, intent);
   
        String action = intent.getAction();
        final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher);
        //判断是否是自定义点击action
        if (action.equals(fs)){
            Toast.makeText(context, "clicked it", Toast.LENGTH_SHORT).show();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    AppWidgetManager manager = AppWidgetManager.getInstance(context);

                    for (int i = 0; i < 37; i++) {
                        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
                        remoteViews.setImageViewBitmap(R.id.tv_content,rotateBitmap(bitmap,i*10));
                        Intent clickIntent = new Intent();
                        clickIntent.setAction(fs);
                        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, clickIntent, 0);
                        remoteViews.setOnClickPendingIntent(R.id.tv_content,pendingIntent);
                        Log.d("8888888", "run: ");
                        manager.updateAppWidget(new ComponentName(context,NewAppWidget.class),remoteViews);

                        SystemClock.sleep(30);

                    }
                }
            }).start();
        }
    }

    private Bitmap rotateBitmap(Bitmap bitmap,float degree) {
        Matrix matrix = new Matrix();
        matrix.reset();
        matrix.setRotate(degree);
        Bitmap bm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);


        return bm;
    }
}
  • onEnabled 当小部件第一次添加到桌面时调用
  • onUpdate 当小部件被添加或者更新时调用
  • onReceive 作为一个广播,当接接受到Intent消息的时候调用

###4.在AndroidManifest 中声明小部件

  <receiver android:name=".NewAppWidget">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                <action android:name="com.example.admin.customview.click" />
            </intent-filter>

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

第一个action 作为小部件的标记存在,在安装时系统让系统检测到包含小部件组件
第二个action 用于BrocastReceiver 接受点击事件

###在桌面小部件中使用ListView
同样,为了能够让数据从本地app 传递到 系统服务进程中.引用了RemoteViewsService 作为进程间传递数据的介质,谷歌也提供了一套标准的实现流程

  1. 自定义Service 继承 RemoteViewsService
  2. 重写onGetViewFactory 返回Factory
  3. 重写Factory 你需要的方法
  4. remoteViews.setRemoteAdapter(R.id.message_list,intent); 通过RemoteView 的setAdapter 实现数据关联,这里的intent 用于传递你需要在Factory 中拿到的信息.下面粘贴一段源码,帮助理解数据传递过程
setRemoteAdapter会通过bindService 的方式启动RemoteService
 @Override
   public IBinder onBind(Intent intent) {
       synchronized (sLock) {
           Intent.FilterComparison fc = new Intent.FilterComparison(intent);
           //通过Intent 的摘要信息作为Key,此处维护了一个Facory 缓存, 如果已经创建,则不需要重新调用Factory 的构造和oncreate方法  
           RemoteViewsFactory factory = null;
           boolean isCreated = false;
           if (!sRemoteViewFactories.containsKey(fc)) {
               factory = onGetViewFactory(intent);
               sRemoteViewFactories.put(fc, factory);
               factory.onCreate();
               isCreated = false;
           } else {
               factory = sRemoteViewFactories.get(fc);
               isCreated = true;
           }
           return new RemoteViewsFactoryAdapter(factory, isCreated);
       }
   }
    原文作者:付爽
    原文地址: https://blog.csdn.net/qq_34306963/article/details/78606224
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞