抄360一个关键的洁净实现(一)

---------------------------------------------------------------------

编译环境: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"/>

第一部分就这样了。第二部分分析白名单处理

由于技术水平有限,写作水平有限,如果您有任何错误,欢迎丹尼尔修正。

版权声明:本文博主原创文章,博客,未经同意不得转载。

原文地址:https://www.cnblogs.com/gcczhongduan/p/4812666.html