#RemoteView 自定义桌面小部件
效果如上图, class AppWidgetProvider extends BroadcastReceiver,不难看出桌面小部件本质上是一个广播,至于为什么是一个广播的形势,我猜…是因为桌面小部件运行在SystemService进程中,通过PendingIntent这种方式传递,避免了自己写IPC通信。
#自定义小部件统共分几步
###1.定义小部件界面
在layout 下创建xml 文件
###2.定义小部件配置信息
通过as自带的创建app widget功能会自动创建该文件,否则需要手动指定,定义小部件刷新,最小宽高等信息
###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;
}
}
###4.在AndroidManifest 中声明小部件
第一个action 作为小部件的标记存在,在安装时系统让系统检测到包含小部件组件
第二个action 用于BrocastReceiver 接受点击事件
###在桌面小部件中使用ListView
同样,为了能够让数据从本地app 传递到 系统服务进程中.引用了RemoteViewsService 作为进程间传递数据的介质,谷歌也提供了一套标准的实现流程
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);
}
}