最近在学习android的appwidget,看了一些文章,决定做一个相册幻灯片来练手,下面写写过程来给大家共享:
- 在项目的res/xml/下建立一个appwidget_info.xml文件,内容如下:
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialLayout="@layout/appwidget" android:minHeight="800dp" android:minWidth="240dp" android:updatePeriodMillis="300000" > </appwidget-provider>
在这里定义appwidget的基本信息,宽度,高度,以及刷新的频率等
- 在layout/下建立appwidget的layout文件
<?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:gravity="center" android:orientation="vertical" android:padding="20dp" > <Button android:id="@+id/button1" android:layout_width="120dp" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="播放图片" /> <ImageView android:id="@+id/imageView1" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#FFFF" android:padding="2dp" android:scaleType="fitXY" android:src="@drawable/p1" /> </LinearLayout>
这个layout比较简单,里面仅仅包含一个button和一个imageview,设置 android:padding="2dp"来让图片有一个简单的边框样式
- 建立MyAppWidgetProvider继承AppWidgetProvider,重写父类的生命周期函数,这里的原理google一下有很多,就不多写了。首先重写onUpdate,这个方法在appwidget第一次加载时会被调用,在这里我们主要使用ContentResolver查询出本机所有图片;接下来新建一个PendingIntent将图片路径的集合封装到其中,最后将pendingIntent设置给button
Intent intent = new Intent("com.jaredluo.appwidget.change"); intent.putExtra("path", pathStrArr); //设置pending,发送广播,注意设置 //PendingIntent.FLAG_UPDATE_CURRENT //否则onRecieve函数中接收不到intent中的数据 PendingIntent pIntent = PendingIntent.getBroadcast(context, 0, intent,PendingIntent.FLAG_UPDATE_CURRENT); for (int j = 0; j < appWidgetIds.length; j++) { //RemoteView是appwidget中很重要的一个类,基本上对appwidget中 //所有控件的操作都要基于RemoteView来操作 RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.appwidget); remoteView.setOnClickPendingIntent(R.id.button1, pIntent); appWidgetManager.updateAppWidget(appWidgetIds[j], remoteView); remoteView = null; }
由于appwidget与主程序处于不同的进程中,所以通讯都需要依靠PendingIntent。
- 接下来在onReceive中接收我们刚才设置给button的广播,首先新开一个线程控制图片的播放,接下来在Handler中为ImageView设置图片源
final RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.appwidget); String path = paths[msg.getData().getInt("i")]; remoteViews.setImageViewBitmap(R.id.imageView1,BitmapUtil.getBitmap(path, 200, 200)); appWidgetManager.updateAppWidget(componentName,remoteViews);
这里需要注意一个问题,我在把图片设置给appwidget时,跑不了几张图片就会出现!!! FAILED BINDER TRANSACTION !!!这个错误,最先以为是图片太大造成的,结果压缩图片也无果;后面在网上搜索一番发现:Binder data size limit is 512K 由于传输图片到appwidget进程中的Binder最大数据量是512k,并且RemoteView也不会每次清理,所以如果每次都使用同一个RemoteView进行传输会因为溢出而报错。最后每次都新建一个RemoteView问题才解决掉。
看看最后的效果,点击播放图片按钮,图片就开始更替:
代码还有很多问题和不完善,接下来有空会继续修改。