怎样在Android实现桌面清理内存简单Widget小控件

简介:

怎样在Android实现桌面清理内存简单Widget小控件


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

效果图:



一、UI部分的编写:

參照Google的文档,首先在建立一个类继承AppWidgetProvider

import android.appwidget.AppWidgetProvider;

public class MyWidget extends AppWidgetProvider {
	
}

然后在清单文件里申明它。我们必须注意到,AppWidgetProvider实际上是BroadcastReceiver,所以要注冊成一个receiver,然后另一些其它的东西须要注意:

 <receiver android:name="com.alexchen.widget.MyWidget" >
            <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>
android.appwidget.action.APPWIDGET_UPDATE 表明这个receiver可以接受一个APPWIDGET_UPDATE的广播,并且在这里,仅仅能增加这一个action。


android.appwidget.provider 表明数据类型时widget提供者提供的数据,example_appwidget_info表明这个widget的參数配置文件名称和位置


那么接下来就须要在res文件夹下建立一个xml文件夹。而且在当中建立一个example_appwidget_info.xml的配置文件,Google的文档中给出了演示样例有非常多參数。实际上关键的參数仅仅有以下的4个:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="94dp"
    android:minHeight="72dp"
    android:updatePeriodMillis="86400000"
    android:initialLayout="@layout/example_appwidget">
</appwidget-provider>

当中,minWidthminHeight代表这个widget控件所占领的最小空间,这个空间一般来讲不须要太大,由于太大的话,一个屏幕可能都没办法放下。Google的官方文档的说法是大于4x4的就可能无法显示。

updatePeriodMillis代表数据更新的时间。这里86400000毫秒实际上是24小时,可能最開始看到这个參数会想我是否能将其设的非常小,每一秒刷新非常多次?,实际上对于updatePeriodMillis这个參数而言,即算你设的再小也没用,Google设定widget控件这个參数控制的最短update时间为30分钟,就算将其设置在30分钟以内也会以30分钟的频率来更新数据。

initialLayout參数代表的是本widget空间的布局文件。



那么下一步就是定义出一个相应的布局文件。

我们能够简单的在layout文件夹下建立一个布局文件example_appwidget.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="200dp"
    android:layout_height="80dp"
    android:background="@android:color/white"
    android:gravity="center_vertical"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/tv_widget"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="widget控件測试"
        android:textColor="@android:color/black"
        android:textSize="15sp" />

    <Button
        android:id="@+id/btn_clear"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="清理内存"
        android:textColor="#ff000000" />

</LinearLayout>


在Google的文档中有指出,并不是全部的布局组件都能够在上面的这个布局中生效,有效的组件或布局为:


至此。一个简单的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)怎样实现的问题了。

我们在这里的想法非常easy。比方说每隔三秒钟来刷新一下widget中的数据。Android中定时运行任务的方法有非常多。我们这里使用TimerTimerTask来实现,之后我们须要关心的就是详细怎样实现刷新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;
	}






本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5129287.html,如需转载请自行联系原作者
相关文章
|
4月前
|
存储 前端开发 Java
Android MVVM架构模式下如何避免内存泄漏
Android采用MVVM架构开发项目,如何避免内存泄漏风险?怎样避免内存泄漏?
139 1
|
2月前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
4月前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
123 15
Android 系统缓存扫描与清理方法分析
|
3月前
|
监控 Java Android开发
深入探讨Android系统的内存管理机制
本文将深入分析Android系统的内存管理机制,包括其内存分配、回收策略以及常见的内存泄漏问题。通过对这些方面的详细讨论,读者可以更好地理解Android系统如何高效地管理内存资源,从而提高应用程序的性能和稳定性。
115 16
|
3月前
|
Android开发 开发者
Android性能优化——内存管理的艺术
Android性能优化——内存管理的艺术
|
4月前
|
编解码 Android开发 UED
构建高效Android应用:从内存优化到用户体验
【10月更文挑战第11天】本文探讨了如何通过内存优化和用户体验改进来构建高效的Android应用。介绍了使用弱引用来减少内存占用、懒加载资源以降低启动时内存消耗、利用Kotlin协程进行异步处理以保持UI流畅,以及采用响应式设计适配不同屏幕尺寸等具体技术手段。
66 2
|
5月前
|
Java 测试技术 Android开发
Android性能测试——发现和定位内存泄露和卡顿
本文详细介绍了Android应用性能测试中的内存泄漏与卡顿问题及其解决方案。首先,文章描述了使用MAT工具定位内存泄漏的具体步骤,并通过实例展示了如何分析Histogram图表和Dominator Tree。接着,针对卡顿问题,文章探讨了其产生原因,并提供了多种测试方法,包括GPU呈现模式分析、FPS Meter软件测试、绘制圆点计数法及Android Studio自带的GPU监控功能。最后,文章给出了排查卡顿问题的四个方向,帮助开发者优化应用性能。
308 4
Android性能测试——发现和定位内存泄露和卡顿
|
5月前
|
监控 算法 数据可视化
深入解析Android应用开发中的高效内存管理策略在移动应用开发领域,Android平台因其开放性和灵活性备受开发者青睐。然而,随之而来的是内存管理的复杂性,这对开发者提出了更高的要求。高效的内存管理不仅能够提升应用的性能,还能有效避免因内存泄漏导致的应用崩溃。本文将探讨Android应用开发中的内存管理问题,并提供一系列实用的优化策略,帮助开发者打造更稳定、更高效的应用。
在Android开发中,内存管理是一个绕不开的话题。良好的内存管理机制不仅可以提高应用的运行效率,还能有效预防内存泄漏和过度消耗,从而延长电池寿命并提升用户体验。本文从Android内存管理的基本原理出发,详细讨论了几种常见的内存管理技巧,包括内存泄漏的检测与修复、内存分配与回收的优化方法,以及如何通过合理的编程习惯减少内存开销。通过对这些内容的阐述,旨在为Android开发者提供一套系统化的内存优化指南,助力开发出更加流畅稳定的应用。
113 0
|
6月前
|
编解码 Android开发 UED
【性能狂飙!】揭秘Android应用极速变身秘籍:内存瘦身+用户体验升级,打造丝滑流畅新境界!
【8月更文挑战第12天】构建高效Android应用需全方位优化,尤其重视内存管理和用户体验。通过弱引用降低内存占用,懒加载资源减少启动负担。运用Kotlin协程确保UI流畅不阻塞,响应式设计适配多屏需求。这些策略共同提升了应用性能与用户满意度。
61 1

热门文章

最新文章

  • 1
    如何修复 Android 和 Windows 不支持视频编解码器的问题?
  • 2
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
  • 3
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 4
    【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
  • 5
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
  • 6
    Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
  • 7
    【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
  • 8
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 9
    从零开始掌握进程间通信:管道、信号、消息队列、共享内存大揭秘
  • 10
    Pandas高级数据处理:内存优化