最近在学习android的appwidget,看了一些文章,决定做一个相册幻灯片来练手,下面写写过程来给大家共享:

  1. 在项目的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的基本信息,宽度,高度,以及刷新的频率等

  1. 在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"来让图片有一个简单的边框样式

  1. 建立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。

  1. 接下来在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问题才解决掉。

    看看最后的效果,点击播放图片按钮,图片就开始更替:

android 幻灯片 放映 安卓 幻灯片_android

代码还有很多问题和不完善,接下来有空会继续修改。