首页 > 代码库 > Android:AppWidget之桌面小电筒

Android:AppWidget之桌面小电筒

     安卓开发中很多控件都是Widget类的,但是我们常说的Widget指的是AppWidget,即一些可以放置在桌面的小部件。

    下面用两个实例来说一下这个AppWidget怎么来用。

实例一:AppWidget的基本使用

①创建一个AppWidget的布局文件appwidget_layout.xml

<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="今晚打老虎" >
    </Button>
</LinearLayout></span>
②在res文件夹下新建一个xml文件夹,然后在里面添加一个xml文件appwidgetprovider_info.xml
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/appwidget_layout"   //指定布局,这个是最重要的
    android:minHeight="72dp"                     //最小高度
    android:minWidth="294dp"                     //最小宽度
    android:updatePeriodMillis="86400000" >      //刷新时间
</appwidget-provider></span>
③新建一个类继承AppWidgetProvider,重写几个重要的方法

<span style="font-size:14px;">package com.example.d_appwidget;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;

public class AppWidget extends AppWidgetProvider {
	@Override
	public void onEnabled(Context context) {      //首次添加AppWidget
		// TODO Auto-generated method stub
		super.onEnabled(context);
		System.out.println("---> onEnabled");
	}

	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager,  //更新AppWidget
			int[] appWidgetIds) {
		// TODO Auto-generated method stub
		super.onUpdate(context, appWidgetManager, appWidgetIds);
		System.out.println("---> onUpdate");
	}

	@Override
	public void onDeleted(Context context, int[] appWidgetIds) {           //删除AppWidget
		// TODO Auto-generated method stub
		super.onDeleted(context, appWidgetIds);
		System.out.println("---> onDeleted");
	}

	@Override
	public void onDisabled(Context context) {                              //删除所有AppWidget
		// TODO Auto-generated method stub
		super.onDisabled(context);
		System.out.println("---> onDisabled");
	}

	@Override
	public void onReceive(Context context, Intent intent) {               //接收到广播,比较重要的方法
		// TODO Auto-generated method stub
		super.onReceive(context, intent);
		System.out.println("---> onReceive");
	}
}
</span>
④在AndoridManifest文件中注册receiver,在application节点中添加

<span style="font-size:14px;"><receiver android:name="AppWidget" >
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" >
        </action>
    </intent-filter>
    <meta-data
        android:name="android.appwidget.provider"
        android:resource="@xml/appwidgetprovider_info" />
</receiver></span>

结果:运行后可以看到窗口小部件中我们自定义的部件



执行添加删除操作,我的理解是:执行不同操作时系统发出不同的广播,然后执行相应的方法,执行完之后系统再次发出特定广播。



实例二:在桌面上来进行手电筒操作,很多手电筒都需要先打开App然后再去开灯关灯,这有点麻烦,所以学了这个AppWidget之后我就写个这个。需要说明的是,程序本身和窗口小部件属于两个进程 ,对控件的使用和在程序本身使用是不同的,这也是最该关注的一点,也就是后面写到的PendingIntent和RemoteViews两个类。前面的步骤和实例一大致相同,主要不同是在继承类中重写的方法。

①新建一个布局文件appwidget_layout.xml

<span style="font-size:14px;"><?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:orientation="vertical" >
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="电筒-开" />
</LinearLayout></span>
②res文件夹下新建一个xml文件夹,新建一个appwidgetprovider_info.xml文件

<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/appwidget_layout" >
</appwidget-provider></span>
③新建一个类继承AppWidgetProvider,重写几个重要的方法

<span style="font-size:14px;">package com.example.e_appwidget_flashlight;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.widget.RemoteViews;

public class AppWidget extends AppWidgetProvider {
	private static final String ACTION_TAG = "leelit.action.flash";     //待发出的广播
	private static boolean flashOn = false;
	private static Camera camera;
	private static Camera.Parameters parameters;

	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager,
			int[] appWidgetIds) {
		// TODO Auto-generated method stub
		super.onUpdate(context, appWidgetManager, appWidgetIds);
		System.out.println("---> onUpdate");
		Intent intent = new Intent(ACTION_TAG);
		PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,  //一定条件下才会触发的意图,这个意图是发出
				intent, 0);                                           //广播      
		RemoteViews remoteViews = new RemoteViews(context.getPackageName(),          //获得AppWidget的所有控件对象
				R.layout.appwidget_layout);
		remoteViews.setOnClickPendingIntent(R.id.button, pendingIntent);  //此处就能点击触发上面意图,绑定为button控件
		appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);      //执行update,第一个参数代表部件ID,通常都是一个
	}

	@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub
		super.onReceive(context, intent);
		if (intent.getAction().equals(ACTION_TAG)) {                      //点击后会发出一个广播,此处就可接收
			RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
					R.layout.appwidget_layout);               //因为要操作AppWidget控件,所以要再次获取                                                                                           //remoteviews和执行相应的步骤
			AppWidgetManager appWidgetManager = AppWidgetManager      
					.getInstance(context);
			ComponentName provider = new ComponentName(context, AppWidget.class);
			flashOn = !flashOn;                                       //打开或关闭电筒
			if (flashOn) {
				turnOnLight();
				remoteViews.setTextViewText(R.id.button, "电筒-关");   //改变控件状态
				appWidgetManager.updateAppWidget(provider, remoteViews);
			} else {
				turnOffLight();
				remoteViews.setTextViewText(R.id.button, "电筒-开");
				appWidgetManager.updateAppWidget(provider, remoteViews);
			}
		}
	}

	private void turnOnLight() {
		camera = Camera.open();
		parameters = camera.getParameters();
		parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
		camera.setParameters(parameters);
		camera.release();   //此处必须释放资源,否则后面关不了手电筒,因为相机资源一直在被占据着
	}

	private void turnOffLight() {
		camera = Camera.open();
		parameters = camera.getParameters();
		parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
		camera.setParameters(parameters);
		camera.release();
	}
}
</span>

④在AndoridManifest文件中注册receiver,在application节点中添加。添加相应权限。

<span style="font-size:14px;"><receiver android:name="com.example.e_appwidget_flashlight.AppWidget" >
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <intent-filter>
        <action android:name="leelit.action.flash" />    <!-- 这个广播是自定义的 -->
    </intent-filter>

    <meta-data
        android:name="android.appwidget.provider"
        android:resource="@xml/appwidgetprovider_info" />  <!-- 资源文件 -->
</receiver></span>

结果:桌面添加一个部件,点击操作就可以打开或关闭手电筒了。

还有其他的一些细节就见上传的Demo吧

AppWidget_FlashLight.rar


小结:四个步骤:①部件布局,②加载布局的xml文件,③继承AppWidgetProvider类,重写方法,④配置AndoridManifest文件




Android:AppWidget之桌面小电筒