---------------------------------------------------------------------
编译环境:Android 4.0
测试环境:Android 4.2.2模拟器
屏幕分辨率:480*800
作者:疯狂小强
注意:
1.资源採集于网上,如有侵权请及时联系,以便处理。
2.代码仅用于学习交流。请勿商业化。
--------------------------------------------------------------------
先上部分效果图:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdGFuZ25lbmd3dQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" height="294" width="184"> |
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdGFuZ25lbmd3dQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" height="296" width="175"> |
“一键清理”是一个桌面图标,点击图标后,显示一个视图。进行清理动画,之后显示清理了几个进程,释放了多少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会发现例如以下信息:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdGFuZ25lbmd3dQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >
当中: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"/>
第一部分就这样了。第二部分分析白名单处理
由于技术水平有限,写作水平有限,如果您有任何错误,欢迎丹尼尔修正。
版权声明:本文博主原创文章,博客,未经同意不得转载。