桌面小控件(Widget)--之清理进程
首先,简单的说一下什么是Widget,Widget是在Android系统界面中添加的小部件。那么在android中有一个系统内置服务来专门管理widget,该服务为AppWidgetManager。
建立widget的步骤如下:
1.建立一个工程,然后写一个类继承AppWidgetProvider并重写onEnabled(), onUpdate(), onDisabled()方法
class TimeWidgetProvider extends AppWigetProvider
{
}
2. AppWigetProvider是一个广播接者。在配置文件中进行配置:
<receiver android:name=".receiver.MyWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider“
android:resource="@xml/appwidget_info" />
</receiver>
3.在res文件夹下建一个xml文件夹,放置一个appwidget_info.xml该文件为widget的界面
在桌上第一个添加该widget时系统会发出一个广播,该广播会被我们定义的TimeWidgetProvider所接收,并执行onEnabled()方法,该widget添加后会发出一个广播,该广播的类型为:
android.appwidget.action.APPWIDGET_UPDATE 会执行onUpdate()方法,当桌面上同类型的Widget的最后一个被删除时会执行onDisabled()方法.
在onUpate()方法中可以更改widget界面上的内容.
效果图如下:
当我们点击一键清理的时候,就会把手机的一些正在运行的进程结束掉,当然用户系统在没有获得root权限之前是不可以结束掉的。
步骤一:
写一个类,继承AppWidgetProvider
package cn.cbd.clean; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.Context; import android.content.Intent; public class CleanWidget extends AppWidgetProvider { private Intent service; @Override public void onDeleted(Context context, int[] appWidgetIds) { super.onDeleted(context, appWidgetIds); } @Override public void onDisabled(Context context) { //停止服务 service = new Intent(context, MyService.class); context.stopService(service); super.onDisabled(context); } @Override public void onEnabled(Context context) { //开启服务 service = new Intent(context, MyService.class); context.startService(service); super.onEnabled(context); } @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // TODO Auto-generated method stub super.onUpdate(context, appWidgetManager, appWidgetIds); } }
AppWidgetProvider也是一个广播接收者,所以我们要在清单文件中对CleanWidget进行配置
<application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <receiver android:name=".CleanWidget" > <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <!-- meta-data 携带数据 传递数据用的 --> <meta-data android:name="android.appwidget.provider" android:resource="@xml/example_appwidget_info" /> </receiver>
在类CleanWidget中我们可以看到,我们在ouEnabled()方法中开启一个服务,在onDisabled()中关闭这个服务,当我们把小控件拖到桌面上的时候,就会先执行onReceive 然后紧接着执行onEnable()方法,当我们把桌面上相同的最后一个控件删除,就会执行onDisabled()方法。
那我们在服务中做哪些事情呢?
package cn.cbd.clean; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import android.app.ActivityManager; import android.app.PendingIntent; import android.app.Service; import android.app.ActivityManager.RunningAppProcessInfo; import android.appwidget.AppWidgetManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.text.format.Formatter; import android.widget.RemoteViews; public class MyService extends Service { private List<String> packageNames; private static final String BUTTON_KILLPROCESS = "cn.cbd.KILLPROCESS"; private Timer timer; @Override public void onCreate() { //新建一个计时器,来不断的×××正在运行程序的个数是否发生改变 timer = new Timer(); timer.schedule(new TimerTask() { public void run() { //新建一个String类型集合,来存放正在运行程序的包名(我们结束进程是需要通过应用程序的包名来结束的)。 packageNames = new ArrayList<String>(); //获取AppWidgetManager控件管理者对象 AppWidgetManager appWidgetManager = AppWidgetManager .getInstance(getApplicationContext()); ActivityManager am = (ActivityManager) getApplicationContext() .getSystemService(Context.ACTIVITY_SERVICE); List<RunningAppProcessInfo> infos = am.getRunningAppProcesses(); for (RunningAppProcessInfo info : infos) { packageNames.add(info.processName); } //对于本应用来说,桌面的控件属于远程View了,所以我们需要一个RemoteViews对象,来管理我们自定义View RemoteViews views = new RemoteViews(getApplicationContext() .getPackageName(), R.layout.memorycleanning); //设置控件上的文字内容 views.setTextViewText(R.id.tv_runningAppNums, "正在运行程序有" + (packageNames.size() + "个")); views.setTextViewText( R.id.tv_availableMemory, "剩余内存" + Formatter.formatFileSize( getApplicationContext(), MemoryUtil .getAvailableMem(getApplicationContext()))); //当我们点击一键清理按钮时发送一个自定义广播,类型为cn.cbd.KILLPROCESS 配置文件中也要进行相应的配置 Intent intent = new Intent(); intent.setAction(BUTTON_KILLPROCESS); PendingIntent pendingIntent = PendingIntent.getBroadcast( getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); //为小控件上的按钮设置点击事件 views.setOnClickPendingIntent(R.id.btn_clean, pendingIntent); ComponentName componentName = new ComponentName( getApplicationContext(), CleanWidget.class); //更新AppAidget 也就是更新桌面控件中的内容 appWidgetManager.updateAppWidget(componentName, views); } }, 0, 10); super.onCreate(); } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { super.onDestroy(); } }
自定义广播在配置文件中的配置情况
<!-- 广播接收者 自定义了一种广播 --> <receiver android:name=".KillProcessBroadcaseReceiver" > <intent-filter> <action android:name="cn.cbd.KILLPROCESS" /> </intent-filter> </receiver>
此时,显然我们要写一个广播接收者,来接收我们这种类型的广播
package cn.cbd.clean; import java.util.ArrayList; import java.util.List; import android.app.ActivityManager; import android.app.ActivityManager.RunningAppProcessInfo; import android.appwidget.AppWidgetManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.text.format.Formatter; import android.widget.RemoteViews; public class KillProcessBroadcaseReceiver extends BroadcastReceiver { private List<String> packageNames; @Override public void onReceive(Context context, Intent intent) { packageNames = new ArrayList<String>(); RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.memorycleanning); AppWidgetManager appWidgetManager = AppWidgetManager .getInstance(context); ActivityManager am = (ActivityManager) context .getSystemService(Context.ACTIVITY_SERVICE); List<RunningAppProcessInfo> infos = am.getRunningAppProcesses(); for (RunningAppProcessInfo info : infos) { packageNames.add(info.processName); } String action = intent.getAction(); if (action.equals("cn.cbd.KILLPROCESS")) { for (String packageName : packageNames) { am.killBackgroundProcesses(packageName); } ComponentName componentName = new ComponentName(context, CleanWidget.class); views.setTextViewText(R.id.tv_runningAppNums, "正在运行程序有" + packageNames.size() + "个"); views.setTextViewText( R.id.tv_availableMemory, "剩余内存" + Formatter.formatFileSize(context, MemoryUtil.getAvailableMem(context))); appWidgetManager.updateAppWidget(componentName, views); } } }
在这个广播中,我们会用到一个工具类,就是获取手机RAM剩余内存大小的。这个类是我们自定义的工具类。
package cn.cbd.clean; import android.app.ActivityManager; import android.app.ActivityManager.MemoryInfo; import android.content.Context; /** * 工具类,用来获取手机剩余内存大小 * @author Administrator * */ public class MemoryUtil { //Formatter.formatFileSize(this,availaleMemory) 格式化 public static long getAvailableMem(Context context) { ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); MemoryInfo outInfo= new MemoryInfo(); am.getMemoryInfo(outInfo); return outInfo.availMem; } }
到此呢,我们这个清理手机进程的小控件已经完成。现在呢,我整理一下这个小项目的思路:
1.得到一个Widget对象(继承AppWidgetProvider)
2.开启一个服务,来更新控件上数据的变化
3.在服务中定义一个广播,当我们点击“一键清理”按钮时,就会发送一个广播。这时候呢,需要我们写一个广播接收者,来接收我们定义的这种类型的广播。
4.在广播中,我们做杀掉进程的操作。