如何在Android实现桌面清理内存简单Widget小控件,androidwidget

如何在Android实现桌面清理内存简单Widget小控件,androidwidget
如何在Android实现桌面清理内存简单Widget小控件
我们经常会看到类似于360、金山手机卫士一类的软件会带一个widget小控件,显示在桌面上,上面会显示现有内存大小,然后会带一个按键功能来一键清理内存,杀死后台进程的功能,那么这个功能是如何实现的呢,我们今天也来尝试做一个类似的功能的小控件。
效果图:

  • FrameLayout
  • LinearLayout
  • RelativeLayout
  • GridLayout
    • AnalogClock
    • Button
    • Chronometer
    • ImageButton
    • ImageView
    • ProgressBar
    • TextView
    • ViewFlipper
    • ListView
    • GridView
    • StackView
    • AdapterViewFlipper


    至此,一个简单的widget控件就写好了,我们可以在模拟器上将其拖到桌面上看一看效果:



    二、功能逻辑部分的实现

    大部分的Widget小控件都会需要在特定情况下更新上面显示的数据,那么这个是如何实现的呢,我们经过上面的代码不难发现实际上这个widget控件并没有一个Activity,所以说这个控件的显示实际上不是本应用来实现的,它实际上是桌面这个应用来显示的,所以我们也不可能直接去更新它上面的数据。


    回过头去看看上面我们写的那个receiver,实际上没有实现任何方法。实际上AppWidgetProvider里面有几个比较重要的方法:onReceive、onUpdate、onDisabled、onEnabled

    其中onReceive方法跟大多数广播接收者的onReceive方法一样,但是在这里,onReceive方法的调用并不是我们可以决定的,它依赖于显示该widget控件的Host组件,在这里也就是Android桌面应用,所以我们会发现在不同的手机上,将widget控件拖到桌面上显示的时候onReceive可能调用的次数和先后顺序可能完全不一样,这依赖于Host组件是如何实现的。

    所以在这里onReceive方法对于我们刷新widget数据基本没有什么帮助。


    而onUpdate方法则是由上面所说的updatePeriodMillis参数来控制的,经过上面的分析,我们都知道了,它的最小周期为30分钟。所以我们一般将这个参数设为0即可。那么在这个方法里,我们往往会在其中放置一些启动更新数据服务的功能,因为如果后台的更新数据的Service被意外停止了,那么每30分钟还会被重新启用,不至于一直启动不了了:

    	@Override
    	public void onUpdate(Context context, AppWidgetManager appWidgetManager,
    			int[] appWidgetIds) {
    		super.onUpdate(context, appWidgetManager, appWidgetIds);
    		// System.out.println("onUpdate");
    		//每隔一段时间重新启动服务,防止服务中间被终止了之后没法重启
    		Intent intent = new Intent(context, UpdateWidgetService.class);
    		context.startService(intent);
    	}

    下面是比较重要的两个方法了:onDisabled和onEnabled

    我们知道,widget小控件是可以拖动多个到桌面上的,而onEnabled方法会在第一个widget控件拖到桌面上的时候调用一次,onDisabled会在最后一个widget控件从桌面被删除时调用一次,那么我们需要做的就是在onEnabled这个方法中启用一个刷新widget数据的服务,在onDisabled方法中使用stopService方法来停止这个服务。

    @Override
    	public void onDisabled(Context context) {
    		super.onDisabled(context);
    		System.out.println("onDisabled");
    		//停止数据刷新服务
    		Intent intent = new Intent(context, UpdateWidgetService.class);
    		context.stopService(intent);
    	}
    
    	@Override
    	public void onEnabled(Context context) {
    		super.onEnabled(context);
    		System.out.println("onEnabled");
    		//开启数据刷新服务
    		Intent intent = new Intent(context, UpdateWidgetService.class);
    		context.startService(intent);
    	}

    三、刷新数据的服务

    那么下面的任务就只剩下UpdateWidgetService这个刷新数据的服务(Service)如何实现的问题了。

    我们在这里的想法很简单,比如说每隔三秒钟来刷新一下widget中的数据。Android中定时执行任务的方法有很多,我们这里使用Timer和TimerTask来实现,之后我们需要关心的就是具体如何实现刷新widget中的数据,毕竟这些数据是在桌面应用中显示的。

    并且我们需要用到一个API--AppWidgetManager,它有一个实例方法AppWidgetManager.updateAppWidget(ComponentName provider, RemoteViews views)来实现更新widget数据,我们都知道,如果需要调用另外应用的方法,需要使用远程调用的方法来实现,在这里起到在我们的应用和桌面应用之间的桥梁作用的就是这第二个参数:RemoteViews views,它会将我们设置的数据传送到桌面应用来刷新widget上的数据,我们需要经过下面几步:

    1、定义一个RemoteViews的实例:

    RemoteViews views = new RemoteViews(getPackageName(),R.layout.process_widget);

    2、设置views的内容,也就是刷新其中的数据,这里的方法名会比较奇怪,RemoteViews.setTextViewText(int viewId, CharSequence text)

    其中viewId是在我们前面定义的widget布局文件中的子组件的id,也就是我们要刷新内容的对象,这里就是R.id.tv_test,第二个参数是我们要更新的内容

    3、定义好第一个参数ComponentName provider之后,就可以调用AppWidgetManager.updateAppWidget(ComponentName provider, RemoteViews views)来实现更新数据

    if (timer == null && task == null) {
    	//AppWidgetManager对象,用于更新widget的数据
    	awm = AppWidgetManager.getInstance(this);
    	timer = new Timer();
    	task = new TimerTask() {
    		@Override
    		public void run() {
    			ComponentName provider = new ComponentName(UpdateWidgetService.this, MyWidget.class);
    			//远程view对象,用于在本应用和桌面应用中起传递数据的桥梁作用
    			RemoteViews views = new RemoteViews(getPackageName(),R.layout.example_appwidget);
    			views.setTextViewText(R.id.tv_widget, "想刷新的数据的内容");
    			awm.updateAppWidget(provider, views);
    			System.out.println("====刷新了widget====");
    		}
    	//设置循环时间
    	timer.schedule(task, 0, 3000);
    }


    四、定时刷新可用内存和一键清理内存功能实现

    要实现这个功能,我们需要再上面定时刷新数据服务中将定时刷新的内容改为当前内存所剩余的量,我们这里写一个工具类方法来实现返回内存剩余量;

    另外我们还需要在widget控件的布局文件中添加一个button,并在更新widget数据的服务中,设置这个button的点击事件,但是这里也不像以前的点击事件,同样要应用到RemoteView对象,在这个点击事件中需要发送一个广播,Action为自定义的,我们这里设为:"com.alexchen.mobilesafeexercise.killall",之后,我们需要再写一个广播接收者,来接收这个广播,在onReceive方法中执行杀死后台进程的操作。这里也不能直接使用Intent,由于我们这个意图的Action不是由我们自己执行而是由其他应用程序(桌面应用)执行的,所以需要用到PendingIntent。

    刷新widget数据的服务代码:

    package com.alexchen.widget.service;
    
    import java.util.Timer;
    import java.util.TimerTask;
    
    import android.app.PendingIntent;
    import android.app.Service;
    import android.appwidget.AppWidgetManager;
    import android.content.BroadcastReceiver;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.os.IBinder;
    import android.text.format.Formatter;
    import android.widget.RemoteViews;
    
    import com.alexchen.widget.MyWidget;
    import com.alexchen.widget.R;
    import com.alexchen.widget.utils.SystemInfoUtils;
    
    public class UpdateWidgetService extends Service {
    	private Timer timer;
    	private TimerTask task;
    	private AppWidgetManager awm;
    
    	@Override
    	public IBinder onBind(Intent intent) {
    		return null;
    	}
    
    	@Override
    	public void onCreate() {
    		super.onCreate();
    		startTimer();
    	}
    
    	private void startTimer() {
    		if (timer == null && task == null) {
    			awm = AppWidgetManager.getInstance(this);
    			timer = new Timer();
    			task = new TimerTask() {
    
    				@Override
    				public void run() {
    					ComponentName provider = new ComponentName(
    							UpdateWidgetService.this, MyWidget.class);
    					RemoteViews views = new RemoteViews(getPackageName(),
    							R.layout.example_appwidget);
    					views.setTextViewText(R.id.tv_widget, "dd");
    					views.setTextViewText(R.id.tv_widget,
    							"可用内存:"+ Formatter.formatFileSize(getApplicationContext(),
    								SystemInfoUtils.getAvailableMem(getApplicationContext())));
    					// 自定义一个广播,杀死后台进程的事件
    					Intent intent = new Intent();
    					intent.setAction("com.alexchen.mobilesafeexercise.killall");
    
    					// 描述一个动作,这个动作是由另外一个应用程序执行的
    					PendingIntent pendingIntent = PendingIntent.getBroadcast(
    							getApplicationContext(), 0, intent,
    							PendingIntent.FLAG_UPDATE_CURRENT);
    					views.setOnClickPendingIntent(R.id.btn_clear, pendingIntent);
    					awm.updateAppWidget(provider, views);
    					System.out.println("====刷新了widget====");
    				}
    			};
    			timer.schedule(task, 0, 3000);
    		}
    	}
    	@Override
    	public void onDestroy() {
    		super.onDestroy();
    		stopTimer();
    		unregisterReceiver(offReceiver);
    		unregisterReceiver(onReceiver);
    	}
    
    	private void stopTimer() {
    		if (timer != null && task != null) {
    			timer.cancel();
    			task.cancel();
    			task = null;
    			timer = null;
    		}
    	}
    }
    

    按键清理内存的广播接收者:

    package com.alexchen.widget.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;
    
    public class KillAllReceiver extends BroadcastReceiver {
    
    	@Override
    	public void onReceive(Context context, Intent intent) {
    		System.out.println("自定义的广播消息接收到了...开始清理内存...");
    		ActivityManager am = (ActivityManager) context
    				.getSystemService(Context.ACTIVITY_SERVICE);
    		List<RunningAppProcessInfo> runningAppProcesses = am
    				.getRunningAppProcesses();
    		for (RunningAppProcessInfo info : runningAppProcesses) {
    			am.killBackgroundProcesses(info.processName);
    		}
    	}
    }
    

    获取可用内存的工具类方法:

    /**
    	 * 获取手机可用的剩余内存
    	 * 
    	 * @param context
    	 *            上下文
    	 * @return
    	 */
    	public static long getAvailableMem(Context context) {
    		ActivityManager am = (ActivityManager) context
    				.getSystemService(Context.ACTIVITY_SERVICE);
    		MemoryInfo outInfo = new MemoryInfo();
    		am.getMemoryInfo(outInfo);
    		return outInfo.availMem;
    	}



    问怎把widget(android小插件)装在““手机内存””里好不容易装的widget重启就没了

    可能是你软件问题吧,我这个自己就装在手机内存里面了,我可以发给你呀。。(这个是天气时钟)
     
    小米2s怎在桌面创建清理内存的图标

    嗨!
    在解锁桌面状态,点菜单键,编辑模式,长按最下面一行的内存清理图标,拖至屏幕空白处即可。
    更详细的描述问题有助于网友理解你遇到的麻烦,帮助你更准确的解决问题。谢谢你支持小米手机!
    小米企业平台 [官方认证]

    http://www.bkjia.com/Androidjc/887627.htmlwww.bkjia.comtruehttp://www.bkjia.com/Androidjc/887627.htmlTechArticle如何在Android实现桌面清理内存简单Widget小控件,androidwidget 如何在Android实现桌面清理内存简单Widget小控件 我们经常会看到类于360、金山手...

    本文源自: 环亚娱乐

    上一篇:最好的5个Android ORM框架,androidorm

    下一篇:没有了