---------------------------------------------------------------------
编译环境:Android 4.0
测试环境:Android 4.2.2模拟器
屏幕分辨率:480*800
作者:疯狂小强
注意:
1.资源採集于网上,如有侵权请及时联系,以便处理。
2.代码仅用于学习交流。请勿商业化。
--------------------------------------------------------------------
先上部分效果图:
“一键清理”是一个桌面图标,点击图标后,显示一个视图。进行清理动画,之后显示清理了几个进程,释放了多少M内存,点击“设置过滤名单”启动另外一个Activity编辑过滤名单。
AndroidManifest.xml例如以下:
<?
xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.tang.demo360" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="19" /> <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/> <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@android:style/Theme.Black.NoTitleBar" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".CleanActivity" android:theme="@style/MTheme"> <intent-filter> <action android:name="android.intent.action.MAIN" /> </intent-filter> </activity> <service android:name=".CleanService"> </service> <activity android:name=".SetWhiteListActivity"></activity> </application> </manifest>
1.创建快捷方式
主界面就是一个button。单击后,会发出一个广播com.android.launcher.action.INSTALL_SHORTCUT创建一个快捷方式,这须要权限
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
图一 图二
private void createShortcut()
{
Intent shortcut = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");
// 快捷方式的名字
String name = getResources().getString(R.string.app_name);
shortcut.putExtra(Intent.EXTRA_SHORTCUT_NAME,name);
//不同意反复创建
shortcut.putExtra("duplicate", false);
Intent shortcutIntent = new Intent();
ComponentName componentName = new ComponentName(getPackageName(), "com.tang.demo360.CleanActivity");
shortcutIntent.setComponent(componentName);
shortcut.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
ShortcutIconResource iconRes=null;
//快捷方式的图标
iconRes = Intent.ShortcutIconResource.fromContext(this, R.drawable.shortcut_process_clear_shortcut_icon);
shortcut.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconRes);
sendBroadcast(shortcut);
Log.i("AAA", "sendBroadcast : INSTALL_SHORTCUT");
}
创建出来的这个快捷方式不是打开图一界面,而是打开图二的。
从createShortcut()方法代码上看
ComponentName componentName = new ComponentName(getPackageName(), "com.tang.demo360.CleanActivity");
shortcutIntent.setComponent(componentName);
打开了com.tang.demo360.CleanActivity这个Activity。但其实仅仅做了这些还不够,我们必须为CleanActivity在manifest中配置Action:
<action android:name="android.intent.action.MAIN" />这两者配合使用就能够直接启动CleanActivity了。
2.确定打开CleanActivity的位置
由效果图我们知道:快捷方式所在的位置不同CleanActivity的位置也是不同的。点击桌面快捷方式启动Activity的时候。我们打“ActivityManager”的logcat会发现例如以下信息:
当中:bnds=[510,282][679,399]好象是个坐标,到Launcher的源代码上一看发现:
public void onClick(View v)
{
........
Object tag = v.getTag();
if (tag instanceof ShortcutInfo) {
// Open shortcut
final Intent intent = ((ShortcutInfo) tag).intent;
int[] pos = new int[2];
v.getLocationOnScreen(pos);
intent.setSourceBounds(new Rect(pos[0], pos[1], pos[0]
+ v.getWidth(), pos[1] + v.getHeight()));
boolean success = startActivitySafely(intent, tag);
......
}
点击快捷方式的时候的确是吧快捷方式的位置放在一个Rect中传出去了。位置得到了接下来就仅仅要把Activity的一些style改一下,然后把这个位置数据用上。就能够得到效果图上面的效果了
<style name="MTheme" parent="@android:style/Theme">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimAmount">0</item>
</style>
android:backgroundDimAmount 调节背景灰度
android:windowIsFloating 悬浮窗体,表示浮在屏幕上的,假设在这里使用了,整个layout就会在 屏幕中心,相当于浮在屏幕上。
Rect rect = getIntent().getSourceBounds();
rootView = new CleanView(this,rect);
setContentView(rootView);
WindowManager.LayoutParams lp = getWindow().getAttributes();
WindowManager windowManager = getWindowManager();
int w = windowManager.getDefaultDisplay().getWidth();
int h = windowManager.getDefaultDisplay().getHeight();
lp.x = lp.x+(rect.left-w/2)+Value.WIDTH/2;
lp.y = lp.y+(rect.top-h/2)+Value.HEIGHT/2;
getWindow().setAttributes(lp);
因为使用悬浮窗后坐标原点也在屏幕中心。和我们所得到的Rect中的參数的左边原点不同,所以须要做位置关系转化
lp.x = lp.x+(rect.left-w/2)+Value.WIDTH/2;
lp.y = lp.y+(rect.top-h/2)+Value.HEIGHT/2;
3.CleanView布局的实现
为了实现效果图上面的效果,将CleanView分成两部分
part1.xml
<?xml version="1.0" encoding="utf-8"?
> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/shortcut_process_clear_cover"> <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/shortcut_process_clear_fg" /> <com.tang.demo360.view.LevelView android:id="@+id/text0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:textColor="#ffffff" android:text="10%" android:background="@drawable/task_killer"/> </RelativeLayout>
part2.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="清理进程0个" />
<TextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="释放内存0M" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="设置过滤名单"
android:background="@drawable/shortcut_process_clear_wlist"/>
</LinearLayout>
再依据快捷方式所处的位置推断先把哪部分增加到父容器中
view = new LinearLayout(context);
view.setOrientation(LinearLayout.HORIZONTAL);
view.setBackgroundResource(R.drawable.shortcut_process_clear_bg);
WindowManager windowManager = (WindowManager)
context.getSystemService(Context.WINDOW_SERVICE);
int screenWidth = windowManager.getDefaultDisplay().getWidth();
if(Value.WIDTH+rect.left+50>screenWidth)
{
view.addView(view2);
view.addView(view1);
}
else
{
view.addView(view1);
view.addView(view2);
}
addView(view);
4.CleanView动画实现
出现方式:由无到有
退出方式:由有到无
清理过程动画:part1.xml ImageView不断旋转。速度由慢变快再变慢最后消失。
水面动画:先由未清理所占内存的百分比高度减少到0然后升至当前所占内存百分比的高度
前三个比較easy不做介绍,对于水面动画,在CleanView中有
public void updateView(Object [] parm)
{
text1.setText("清理进程"+(Integer)parm[0]+"个");
DecimalFormat decimalFormat=new DecimalFormat("0.0");
String temp=decimalFormat.format(parm[1]);
text2.setText("释放内存"+temp+"M");
setLevelAnimation((Integer)parm[2]);
}
public void setLevelAnimation(int level)
{
ClipDrawable clip = (ClipDrawable) text0.getBackground();
text0.setText(level+"%");
clip.setLevel(level*100);
}
有2个方法负责高速更新以便达到动画效果。
水面的背景
<?
xml version="1.0" encoding="utf-8"?> <clip xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/shortcut_process_clear_level" android:clipOrientation="vertical" android:gravity="bottom"> </clip>
使用ClipDrawable代表从其他位图上截取一个图片片段setLevel方法设置截取百分比,我在主线程中使用Timer来高速更新这个数值
timer = new Timer();
timer.schedule(task, 500, 1);
task = new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
if(isDown)
{
level = (level-Value.V)>=0?(level-Value.V):0;
if(level ==0)
{
isDown = false;
}
}
else
{
level = (level+Value.V)<=newlevel?(level+Value.V):newlevel;
}
parm[2] =level/100;
handler.sendEmptyMessage(Value.UPDATE_VIEW);
}
};
这样仅仅要在主线程中接受Value.UPDATE_VIEW这个Message然后调用updateView()方法就能够目的动画效果。
5.我们来杀进程吧
对于这个我在网上查了一些资料写了一个工具类
CleanUtil.java
package com.tang.util;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.util.Log;
public class CleanUtil
{
//关闭当前执行的进程
public Object [] killRunnintAppInfo(Context context)
{
MSaveList mSaveList = new MSaveList(context.getSharedPreferences("demo360", Activity.MODE_PRIVATE));
List<String> list = mSaveList.load();
ActivityManager mActivityManager = (ActivityManager) context.getSystemService(context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> mRunningProcess = mActivityManager.getRunningAppProcesses();
int appSize = getRunningTasksSize(context);
long memory = getUesdMemory(context);
for (ActivityManager.RunningAppProcessInfo amProcess : mRunningProcess)
{
if(amProcess.processName.equals("com.tang.demo360")||amProcess.processName.startsWith("system"))
{
Log.d("AAA", "跳过不杀的进程:" + amProcess.processName);
continue;
}
else
{
if(isInWhiteList(amProcess.processName,list))
{
Log.d("AAA", "跳过不杀的进程:" + amProcess.processName);
}
else
{
mActivityManager.killBackgroundProcesses(amProcess.processName);
Log.d("AAA", "杀掉的进程:"+amProcess.processName);
}
}
}
appSize = Math.abs(appSize -getRunningTasksSize(context));
memory = Math.abs(memory -getUesdMemory(context));
return getRecycleMemoryInfo(context,appSize,memory);
}
//强制关闭进程
private void forceKillApp(ActivityManager am, String packageName)
{
Method forceStopPackage = null;
try
{
forceStopPackage = am.getClass().getDeclaredMethod("forceStopPackage", String.class);
forceStopPackage.setAccessible(true);
forceStopPackage.invoke(am, packageName);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 将要传出去的数据
* 杀了多少进程
* 释放多少M内存
* 当前内存百分比
* @param context
* @param appSize
* @param memory
* @return
*/
private Object [] getRecycleMemoryInfo(Context context,int appSize,long memory) {
Object[] pram=new Object[]{0,0,0};;
if(memory>=0)
{
pram[0] = appSize;
pram[1] = (memory/1024.0);
pram[2] = getUesdMemoryRate(context);
}
return pram;
}
private int getRunningTasksSize(Context context)
{
ActivityManager am = (ActivityManager) context.getSystemService(context.ACTIVITY_SERVICE);
return am.getRunningAppProcesses().size();
}
/**
* 得到设备的全部RAM
* @return 返回全部内存大小。单位:kb
*/
private int getAllMemory() {
String filePath = "/proc/meminfo";
int ram = 0;
FileReader fr = null;
BufferedReader localBufferedReader = null;
try {
fr = new FileReader(filePath);
localBufferedReader = new BufferedReader(fr, 8192);
String line = localBufferedReader.readLine();
int a = line.length() - 3;
int b = line.indexOf(' ');
String str = line.substring(b, a);
while (str.substring(0, 1).equals(" ")) {
str = str.substring(1, str.length());
}
ram = Integer.parseInt(str);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fr.close();
localBufferedReader.close();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
return ram;
}
/**
* 得到设备的可用RAM
* @return 返回全部内存大小,单位:kb
*/
private long getAvailMemory(Context context)
{
ActivityManager am = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
am.getMemoryInfo(mi);
return mi.availMem / 1024;
}
/**
* 得到设备的已用RAM
* @return 返回全部内存大小,单位:kb
*/
private long getUesdMemory(Context context)
{
return getAllMemory() - getAvailMemory(context);
}
public int getUesdMemoryRate(Context context)
{
return (int) (getUesdMemory(context)*100/getAvailMemory(context));
}
/**
* 推断是否在白名单之内
* @param pkg
* @param list
* @return
*/
private boolean isInWhiteList(String pkg,List<String> list)
{
boolean inOrNot = false;
if(list!=null)
{
for(int i=0;i<list.size();i++)
{
if(pkg.equals(list.get(i)))
{
inOrNot = true;
break;
}
}
}
return inOrNot;
}
}
在启动CleanActivity的时候。在onCreate中启动了CleanService,热这个实现了Runnable接口
public class CleanService extends Service implements Runnable
{
.....
@Override
public void run()
{
// TODO Auto-generated method stub
handler.sendEmptyMessage(Value.BEGIN_CLEAN);
Object [] pram = cleanUtil.killRunnintAppInfo(this);
Message message = new Message();
message.obj = pram;
message.what = Value.UPDATE;
handler.sendMessage(message);
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
if(CleanActivity.local!=null)
{
handler = CleanActivity.local.getHandler();
new Thread(this).start();
cleanUtil = new CleanUtil();
}
super.onCreate();
}
....
}
将杀进程的工作放在后台进行。
当然杀进程也是须要权限的:
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
第一部分就这样了。第二部分分析白名单处理
由于技术水平有限,写作水平有限,如果您有任何错误,欢迎丹尼尔修正。
版权声明:本文博主原创文章,博客,未经同意不得转载。