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

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

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

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

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

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

时间: 2024-10-12 08:54:04

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

HTML中的form表单有一个关键属性 enctype

HTML中的form表单有一个关键属性 enctype=application/x-www-form-urlencoded 或multipart/form-data. 1.enctype="application/x-www-form-urlencoded"是默认的编码方式,当以这种方式提交数据时,HTTP报文中的内容是: Html代码   <span style="font-size: small;">POST /post_test.php HTTP/

抄360于Launcher浮动窗口的屏幕显示内存使用情况(改进版)

MainActivity例如下列: package cc.cc; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.app.Activity; import android.content.Context; import android.content.Intent; /

安全专家发现GE Multilin SR的一个关键漏洞对全球电网构成严重威胁。

A team of researchers from New York University has found a serious vulnerability in some of GE Multilin SR protection relays that poses a serious threat to power grid. 来自纽约大学的一组研究人员发现一些GE Multilin SR保护继电器存在严重的漏洞,对电网构成严重威胁. The experts will provide fu

一个关键的函数——strcpy的实现

1. strcpy函数的原型是: /*简单的形式,但是这种形式没有考虑内存重叠的情形*/ char* strcpy(char* dst, const char* src) { assert(dst != NULL&&src != NULL); char* ret = dst; while ((*dst++ = *src++) != '\0'); return ret; } 几个注意点:[1]const修饰:[2]空指针检查:[3]返回目标地址 2.假如要考虑dst和src内存重叠的情况,s

jQuery的一个关键函数

jQuery.extend = jQuery.fn.extend = function() { // copy reference to target object var target = arguments[0] || {}, a = 1, al = arguments.length, deep = false; // Handle a deep copy situation //这个IF条件基本上总是false,只有当target对象是布尔类型时才会是真,也就是这段代码好像没有什么作用 i

抄了一个计算字符串个数的程序,一个很简单的代码。但是能看懂,也能掌握使用。原谅我菜,抽出一个小时看几段代码也好

#include<stdio.h> main() { char string[100]; int index,word=1; char blank; gets(string); if(string[0]=='\0') { printf("there is no char!\n"); } else if(string[0]==' ') { printf("first char just is a blank!\n"); } else { for(index

最近一个项目中关于NGUI部分的总结

最近一个项目中关于NGUI部分的总结           在自己最近的一个项目中,软件的界面部分使用了NGUI来进行制作.在制作过程中,遇到了一些问题,也获取了一些经验,总结下来,作为日后的积累. 1.NGUI图集的使用. 此次是第一个自己正儿八经的制作完整图集的项目,感受颇深.在使用NGUI制作界面时,图集的选用是一个关键,因为它直接关系到了drawcall的数量.最好就是自始至终都只使用同一个图集中的元素,这样的话,在界面制作上drawcall的消耗就只会受到Panel的划分以及字体与图集的

一个自然数在1700和1800之间,且被5除余3,被7除余4,被11除余6,求符合条件的数

昨天晚上看了一道逻辑题:一个自然数在1700和1800之间,且被5除余3,被7除余4,被11除余6,求符合条件的数.题目后面写着,有人看了几分钟便给出了答案.我很好奇,此人是如何解答的. 我自己先琢磨了下,拿笔算了半天,最后一个巧合的情况下,得到了答案.此题的一个关键且明显的推论是:能被5除余3的数,肯定最后一位是3或者8.那么接下来怎么推呢?我从网上搜集了答案. 方案1: 这个数被5除余3,则此数个位数为3或8, 设这个数十位为x,则此数可表达为1703+10x,或1708+10x当此数为17

一个疗程找回做女人的自信,享永恒女人味之美

美国科学家在最新一期<癌细胞>杂志上报告说,他们发现了癌细胞在放疗过程中自我保护的机理,据此对放疗方法进 行改进,可使放疗对癌症的治愈率大大提高. 美国杜克大学医学中心的研究人员在报告中说,放疗治愈率低的主要原因是癌细胞在放疗后会产生一种被称为“细胞因 子”的分子.这种分子促使新的血管生成,以取代在放疗中被破坏的血管,为癌细胞供应血液. 为探明该过程中细胞因子的生成,研究人员在实验中监测了接受放疗的老鼠体内一种名为低氧诱导因子-1的分子水平 ,该分子能促使细胞因子的生成.实验结果表明,放疗后,