[mobilesafe] 10_widget的点击事件

Android 4.0

widget的点击事件

技术点:
1、开启定时器
// 1、初始化定时器及设置定时任务,开启定时器
timer = new Timer();
timerTask = new TimerTask() {
    @Override
    public void run() {
        System.out.println("定期更新widget里面的数据~~~");
        updateWidgetContent(getApplicationContext(),ProcessAppWidgetProvider.class);
    }
};
// 每隔1秒钟 就执行一次 run方法.
timer.schedule(timerTask, 1000, 1000);
2、 通过 AppWidgetManager 来更新widget中文本数据 
appWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
appWidgetManager.updateAppWidget(provider, views);
3、更新widget中组件的文本和设置widget的点击事件,都是通过发送给桌面来更新
views.setTextViewText(R.id.process_memory"可用内存/总内存:"+availMemSize+"/"+totalMemSize);
views.setOnClickPendingIntent(R.id.btn_clear, pendingIntent);// 组件id,即将要被指定的PendingIntent
4、widget上的一键清理功能
杀死后台进程:通过发送一个自定义的广播事件
// 2-4,通过发送自定义广播,一键清理
Intent intent = new Intent();
intent.setAction("cn.zengfansheng.clearMaster");
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, intent , PendingIntent.FLAG_UPDATE_CURRENT);
// 2-5,远程view中按钮的点击事件
views.setOnClickPendingIntent(R.id.btn_clear, pendingIntent);// 组件id,即将要被指定的PendingIntent
然后定义个广播接收者,接收该事件,然后杀死后台进程
public class KillBackgroundReceiver extends BroadcastReceiver {
    private static final String TAG = "KillBackgroundReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG"KillBackgroundReceiver~~~接收到了自定义的widget一键清理广播事件,清理后台进程,释放内存~~~");
        // 杀死后台进程
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();
        for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses) {
            if (runningAppProcessInfo.processName.equals(context.getPackageName())) {//如果是自己的进程,跳过,清理
                Log.i(TAG"KillBackgroundReceiver~~~是自己的进程,不清理");
                continue;
            }
            activityManager.killBackgroundProcesses(runningAppProcessInfo.processName);
        }
        Toast.makeText(context, "进程清理完毕", 0).show();
        // FIXME : KillBackgroundReceiver应该弹出清理了多个进程,释放出来的多少内存~
    }
}

步骤:
1、由于widget生命周期,至少要每隔半小时才能更新一次,所以不符合我们需求
2、用代码来定时更新界面数据,
3、用一个Service,后台运行,定时器Timer,TimerTask
4、由于是在手机卫士,更新widget的内容,远程view,用AppWidgetManager来实现,
听过发送数据给桌面,桌面来更新widget中的数据。
5、由于是一个Service,所以在widget被onEnabled,开启服务,在onDisabled,停止服务。
6、一键清理功能:通过桌面发送一个自定义的广播事件,杀死后台进程,
7、然后在服务里面,嵌入一个内部的广播接收者,当接收到该广播事件,那么将所有的后台进程给杀死掉
8、在服务内部嵌入有问题:什么问题?所以要将广播接收者,声明在外,用文件配置。

注意:后台服务是不会被杀死的,只会杀死后台进程

核心代码:
a) ProcessAppWidgetProvider.java (用于开启服务和关闭服务)
package cn.zengfansheng.mobilesafe.receiver;
 
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import cn.zengfansheng.mobilesafe.service.UpdateWidgetService;
/**
* 4、桌面widget
* @author hacket
*/

public class ProcessAppWidgetProvider extends AppWidgetProvider {
 
    // 1、widget第一次被创建的时候,执行
    @Override
    public void onEnabled(Context context) {
        super.onEnabled(context);
 
        // 开启widget后台更新数据的服务
        Intent service = new Intent(context, UpdateWidgetService.class);
        context.startService(service);
    }
 
    // 2、widget最后一个被移除的时候,执行
    @Override
    public void onDisabled(Context context) {
        super.onDisabled(context);
 
        // 停止widget后台更新数据的服务
        Intent service = new Intent(context, UpdateWidgetService.class);
        context.stopService(service);
    }
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        System.out.println(" ProcessAppWidgetProvider onUpdate~");
    }
 
}
b) UpdateWidgetService.java(widget的数据更新的服务)
package cn.zengfansheng.mobilesafe.service;
import java.util.Timer;
import java.util.TimerTask;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Intent;
import android.os.IBinder;
import android.text.format.Formatter;
import android.widget.RemoteViews;
import cn.zengfansheng.mobilesafe.R;
import cn.zengfansheng.mobilesafe.receiver.ProcessAppWidgetProvider;
import cn.zengfansheng.mobilesafe.utils.SystemInfoUtils;
/**
 * 7、widget桌面上,一键清理内存时更新widget文本显示的后台服务
 * @author hacket
 */
public class UpdateWidgetService extends Service {
    private Timer timer;// 定时器
    private TimerTask timerTask;// 定时器任务
    private AppWidgetManager appWidgetManager;// widget的管理者
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化AppWidgetManager
        appWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
        // 1、初始化定时器及设置定时任务,开启定时器
        timer = new Timer();
        timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("定期更新widget里面的数据~~~");
                updateWidgetContent();
            }
        };
        // 每隔1秒钟 就执行一次 run方法.
        timer.schedule(timerTask, 1000, 1000);
        // 参数1:要执行的任务;参数2:多久执行该timerTask;参数3:多久执行一次
    }
    /**
     * 一、更新widget中的数据
     */
    private void updateWidgetContent( ) {
        // 2、更新widget里面的文本数据
        // 2-1,得到widget
        ComponentName provider = new ComponentName(getApplicationContext(),ProcessAppWidgetProvider.class);
        
        // 2-2,得到远程要更新的view对象
        RemoteViews views = new RemoteViews(getApplicationContext().getPackageName(), R.layout.process_widget);
        // 2-3,远程更新widget中对应id组件中的文本
        views.setTextViewText(R.id.process_count"正在运行的进程:"+SystemInfoUtils.getRunningProcCount(getApplicationContext())+"个");
        String availMemSize = Formatter.formatFileSize(getApplicationContext(),SystemInfoUtils.getAvailableMemory(getApplicationContext()));
        String totalMemSize = Formatter.formatFileSize(getApplicationContext(),SystemInfoUtils.getTotalMemory(getApplicationContext()));
        views.setTextViewText(R.id.process_memory"可用内存/总内存:"+availMemSize+"/"+totalMemSize);
        
        // 2-4,通过发送自定义广播,一键清理
        Intent intent = new Intent();
        intent.setAction("cn.zengfansheng.clearMaster");
        PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, intent , PendingIntent.FLAG_UPDATE_CURRENT);
        // 2-5,远程view中按钮的点击事件
        views.setOnClickPendingIntent(R.id.btn_clear, pendingIntent);// 组件id,即将要被指定的PendingIntent
        appWidgetManager.updateAppWidget(provider, views);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}
c) KillBackgroundReceiver.java 杀死后台进程的widget一键清理
package cn.zengfansheng.mobilesafe.receiver;

import java.util.List;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
/**
 * 5、widget一键清理对应的自定义广播事件接收者
 * @author hacket
 */

public class KillBackgroundReceiver extends BroadcastReceiver {

    private static final String TAG = "KillBackgroundReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "KillBackgroundReceiver~~~接收到了自定义的widget一键清理广播事件,清理后台进程,释放内存~~~");
        // 杀死后台进程
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();
        for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses) {
            if (runningAppProcessInfo.processName.equals(context.getPackageName())) {//如果是自己的进程,跳过,清理
                Log.i(TAG, "KillBackgroundReceiver~~~是自己的进程,不清理");
                continue;
            }
            activityManager.killBackgroundProcesses(runningAppProcessInfo.processName);
        }
        Toast.makeText(context, "进程清理完毕", 0).show();
        // FIXME : KillBackgroundReceiver应该弹出清理了多个进程,释放出来的多少内存~
    }
}

结果: