您的位置:首页 > 其它

[安卓]手机管家(十八)一键 锁屏清理线程以及widget

2015-06-25 17:46 537 查看
有些broadcastReceiver不能在manifest里静态注册(不用运行起来就能收到)

锁屏是不能静态注册的,非常频繁的锁屏,动态注册,绑到service里最好,这样生命周期长



receiver

public class LockScreenReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
System.out.println("LockScreenReceiver.onReceive()");

}


在service里注册

public class ListenLockScreenService extends Service {
private LockScreenReceiver lockScreenReceiver;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
lockScreenReceiver = new LockScreenReceiver();
IntentFilter filter = new IntentFilter("android.intent.action.SCREEN_OFF");
registerReceiver(lockScreenReceiver, filter);
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
if (lockScreenReceiver!=null) {
unregisterReceiver(lockScreenReceiver);
lockScreenReceiver=null;
}
super.onDestroy();
}
}


可以再setting里写一个控制按钮,这里让他在splash里启动,不能忘了service的声明

Intent service = new Intent(this,ListenLockScreenService.class);
startService(service);
}

Handler myHandler = new Handler(){


在日常使用中,可以再锁屏的时候把进程清一遍,其实很实用

ublic class LockScreenReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
System.out.println("LockScreenReceiver.onReceive()");
//kill所有的后台进程
ActivityManager ams = (ActivityManager) context.getSystemService(context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> list =      ams.getRunningAppProcesses();
for (RunningAppProcessInfo runningAppProcessInfo : list) {
ams.killBackgroundProcesses(runningAppProcessInfo.processName);
}
}
}


widgets相当于桌面的功能快捷方式

桌面其实也是一个程序,相当于在一个程序上实现另一个程序的功能

需要一个类继承AppWidgetProvider,但是要声明称一个receiver,实际上他是一个receiver

和之前获得管理员权限类似,这个类里面什么也不做

public class MyAppWidgetProvider extends AppWidgetProvider {

}


声明一下,需要在values下新建一个xml文件夹,其中需有一个xml文件

<receiver android:name="com.example.myappwidget.MyAppWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/example_appwidget_info" />
</receiver>


这个xml文件里面,制定了我们要做出来的widget的相关属相参数,他还要一个layout来显示widget的外观

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="300dp"
android:minHeight="40dp"
android:updatePeriodMillis="0"
android:previewImage="@drawable/ic_launcher"
android:initialLayout="@layout/example_appwidget"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen|keyguard">
</appwidget-provider>


layout 这里面不支持复杂控件,比如edittext,若加上,在拖到桌面时提示有问题

<?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" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="hello widget"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="widget"/>
</LinearLayout>


widget生命周期,是一个receiver

第一次新建时,call到几个函数

onEnAble

onUpdate

第二次拖到别的桌面

onupdate onReceive

第三次 还是和第二次一样

可以想到 onEnabled只在第一次建立的时候调用

删除第三个 ondelete onreceive

删除第二个 ondelete onreceive

删除第一个 ondelete ondisable

最后一次会调用disable

启用widget会有广播,onreceive里面会看广播里附带了什么信息,如果是update,他会先调用update,可以看源码

来实现手机管家的widget项目

新建widget类

public class ProcessManagerWidget extends AppWidgetProvider {

}


然后去manifest注册

<receiver android:name="com.rjl.mobilephonemanager.widget.ProcessManagerWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/example_appwidget_info" />
</receiver>


xml写法

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="300dp"
android:minHeight="40dp"
android:updatePeriodMillis="0"
android:previewImage="@drawable/ic_launcher"
android:initialLayout="@layout/processmanager_appwidget"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen|keyguard">
</appwidget-provider>


新建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="wrap_content"
android:background="@drawable/widget_bg_portrait"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="0.0dip"
android:layout_height="fill_parent"
android:layout_marginLeft="5.0dip"
android:layout_weight="1.0"
android:background="@drawable/widget_bg_portrait_child"
android:gravity="center_vertical"
android:orientation="vertical"
android:paddingBottom="3.0dip"
android:paddingTop="3.0dip" >
<TextView
android:id="@+id/tv_processwidget_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10.0dip"
android:textSize="16sp"
android:text="正在运行的软件:6个"/>
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="1.0dip"
android:layout_marginTop="1.0dip"
android:background="@drawable/widget_bg_portrait_child_divider" />
<TextView
android:text="可用内存:433.37M"
android:id="@+id/tv_processwidget_memory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10.0dip"
android:textSize="16sp"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical" >
<ImageView
android:layout_width="20.0dip"
android:layout_height="20.0dip"
android:src="@drawable/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="手机管家"
android:textColor="#FF0000" />
</LinearLayout>
<Button
android:id="@+id/btn_clear"
android:layout_width="90.0dip"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginTop="5.0dip"
android:background="@drawable/call_locate_green"
android:text="一键清理"
android:textColor="#000000" />
</LinearLayout>
</LinearLayout>


完成交互,类里的方法

首先是onenable,拖到到桌面会调到他,只有第一次创建时会用到

onupdate,我们要让widget的图标上的内容内很快更新,默认是至少半小时,可以去弄一个service

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
//1.不是service而是provider
AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
//3.updateAppWidget的第一个参数应该是component的name
ComponentName provider = new ComponentName(context, ProcessManagerWidget.class);
//4.updateAppWidget的第二个参数
RemoteViews views = new RemoteViews("com.rjl.mobilephonemanager",R.layout.processmanager_appwidget);
//5.通过view找到控件
views.setTextViewText(R.id.tv_processwidget_count, "10个进程");
views.setTextViewText(R.id.tv_processwidget_memory, "400MB RAM");
//2.更新桌面控件
widgetManager.updateAppWidget(provider, views);
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
service manifest里声明

ublic class WidgetUpdateService extends Service {

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}

@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
}

@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}

}


<service  android:name="com.rjl.mobilephonemanager.service.WidgetUpdateService"></service>


让widget启动时启动这个service,放到onenable里

@Override
public void onEnabled(Context context) {
Intent service = new Intent(context, WidgetUpdateService.class);
context.startService(service);
super.onEnabled(context);
}


然后在service的onstart里更新widget,这样相当于是在第一次创建桌面的widget时更新了widget,并且要让他更新快点,用到timer,更新的代码应该在timer里

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
//1.不是service而是provider
widgetManager = AppWidgetManager.getInstance(WidgetUpdateService.this);
//6.动态获取进程数,ram也可以获取
int count =GetProcessInfoUtils.getAllProcess(WidgetUpdateService.this);
long ram = GetProcessInfoUtils.getAvailRam(WidgetUpdateService.this);
//3.updateAppWidget的第一个参数应该是component的name
ComponentName provider = new ComponentName(WidgetUpdateService.this, ProcessManagerWidget.class);
//4.updateAppWidget的第二个参数
views = new RemoteViews("com.rjl.mobilephonemanager",R.layout.processmanager_appwidget);
//5.通过view找到控件
views.setTextViewText(R.id.tv_processwidget_count, count+"个进程");
views.setTextViewText(R.id.tv_processwidget_memory, ram/1024+"MB RAM");
//2.更新桌面控件
widgetManager.updateAppWidget(provider, views);
}
}, 1000, 3000);	//3s更新一次
return super.onStartCommand(intent, flags, startId);
}


当最后一个widget没有了的时候销毁这个service,在ProcessManagerWidget里的ondisable里

@Override
public void onDisabled(Context context) {
// 销毁service
Intent service = new Intent(context, WidgetUpdateService.class);
context.stopService(service);
super.onDisabled(context);
}


处理点击事件

pending,在点击时页面不跳转,只发出一个自定义的广播,然后有一个接收者

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//注册下面的广播接收者,自定义的action
IntentFilter fileFilter = new IntentFilter("com.rjl.widget.update");
registerReceiver(new MyWidgetBroadcastReceiver(), fileFilter);

//1.不是service而是provider
widgetManager = AppWidgetManager.getInstance(WidgetUpdateService.this);
//3.updateAppWidget的第一个参数应该是component的name
provider = new ComponentName(WidgetUpdateService.this, ProcessManagerWidget.class);
//4.updateAppWidget的第二个参数
views = new RemoteViews("com.rjl.mobilephonemanager",R.layout.processmanager_appwidget);

timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
//6.动态获取进程数,ram也可以获取
int count =GetProcessInfoUtils.getAllProcess(WidgetUpdateService.this);
long ram = GetProcessInfoUtils.getAvailRam(WidgetUpdateService.this);
//5.通过view找到控件
views.setTextViewText(R.id.tv_processwidget_count, count+"个进程");
views.setTextViewText(R.id.tv_processwidget_memory, ram/1024+"MB RAM");
//2.更新桌面控件
widgetManager.updateAppWidget(provider, views);
}
}, 1000, 3000);	//3s更新一次

Intent myintent = new Intent("com.rjl.widget.update");
//widget的广播机制,经常需要pending,也就是说不是立即执行,需要去点击后助兴
//点击后还在当前页面,只发出一个广播,所以是getBroadcast,然后需要一个广播接收者
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 100, myintent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.btn_clear, pendingIntent);

return super.onStartCommand(intent, flags, startId);
}
class MyWidgetBroadcastReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//此处应该去将后台应用杀掉,然后在更新count显示的数字
views.setTextViewText(R.id.tv_processwidget_count, "当前时间"+ System.currentTimeMillis());
widgetManager.updateAppWidget(provider, views);
}
}


这样子就可以随时清理线程了,而不用等半小时更新一次
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: