代码上已经写好了注释, 因时间关系只写了关键部分的注释,如有不理解的可以给我留言, 我会帮你解读的。
//UI类
package com.example.atest_rectui.widget;
import java.util.List;
import com.example.atest_rectui.R;
import com.example.atest_rectui.util.Utils;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.os.Handler.Callback;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
/**
* @author snake
* UI类, 直接在xml文件配置 即可使用
*
*/
public class ClearMemoryView extends TextView implements Callback {
private static final String TAG = ClearMemoryView.class.getSimpleName();
private static final int REFRESHING = 0x01;
private static final int REFRESH_UI = 0x02;
private static final int REFRESH_END = 0x03;
private Context mContext = null;
private Handler mHandler = null;
/** 画圆的画笔 */
private Paint mCircularPaint;
/** 写字体的画笔 */
private Paint mTxtPaint;
private RectF mRectF;
private RectF mRectFrame;
/** View的宽度 */
private int mViewWidth = 0;
/** View的高度 */
private int mViewHeight = 0;
/** 圆的宽度 */
private int mCircularWidth = 0;
/** 当前的进度 */
private int mCurrentProgress = 100;
private int mMax = 100;
private long mMaxValue = 0;
private float mSweepAngle;
private float mTxtSize = 0.0f;
/** ClearAppsIcon的进度 */
private int mProgress = 0;
/** 允许清除apps的标志 */
private boolean mAllowClear = true;
/** 之前的内存 */
private long mBeforeMem = 0l;
private float mIconPadding = 20;
private float paintwidth = 12;
private Paint mCenterPaint;
private Paint mPerentPaint;
public ClearMemoryView(Context context) {
this(context, null);
}
public ClearMemoryView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ClearMemoryView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
mHandler = new Handler(this);
mViewWidth = (int)mContext.getResources().getDimension(R.dimen.dimen_bottom_item_layout);
mViewHeight = (int)mContext.getResources().getDimension(R.dimen.dimen_bottom_item_layout);
initData();
}
private void initData() {
mCircularWidth = (int)(mViewWidth * 0.78f);
Log.d(TAG, "Clear View Circular==" + mCircularWidth + "::CellWidth==" + mViewWidth + ":::getScrollX() = " + getScrollX());
mRectF = new RectF();
mRectFrame = new RectF();
// 初始化画圆形的画笔
mCircularPaint = new Paint();
//设置画布填充模式 , Paint.Style.STROKE表示中间区域是 镂空的
mCircularPaint.setStyle(Paint.Style.STROKE);
//当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式,如圆形样式 Cap.ROUND,或方形样式Cap.SQUARE
mCircularPaint.setStrokeCap(Paint.Cap.ROUND);
//设置绘制时各图形的结合方式,如平滑效果等
mCircularPaint.setStrokeJoin(Paint.Join.ROUND);
//设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
mCircularPaint.setDither(true);
//设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。
mCircularPaint.setAntiAlias(true);
//当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度
mCircularPaint.setStrokeWidth(paintwidth);
mCenterPaint = new Paint();
mCenterPaint.setStyle(Paint.Style.FILL);
mCenterPaint.setDither(true);
mCenterPaint.setAntiAlias(true);
mCenterPaint.setColor(Color.parseColor("#eeeeee"));
// 设置渐变的颜色组,也就是按红、绿、蓝的方式渐变
// int[] colors = new int[]{Color.parseColor("#00EC00"), Color.parseColor("#00BB00"), Color.parseColor("#009100")};
// Shader shader = new SweepGradient(getWidth() / 2, 0, colors, null);
// mCircularPaint.setShader(shader);
// 初始化写文字的画笔
mTxtPaint = new Paint();
mTxtSize = 33;
mTxtPaint.setTextSize(mTxtSize);
mTxtPaint.setAntiAlias(true);
// Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), "fonts/segoemcl.ttf");
// mTxtPaint.setTypeface(typeface);
mTxtPaint.setColor(Color.BLACK);
mPerentPaint = new Paint();
mPerentPaint.setTextSize(22);
mPerentPaint.setAntiAlias(true);
// mPerentPaint.setTypeface(typeface);
mPerentPaint.setColor(Color.BLACK);
// 初始化值
setMaxValue(Utils.getTotalMemory(mContext));
setProgressValue(Utils.getUsedMemory(mContext));
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
// 圆环
float fLeft = mViewWidth - mCircularWidth;
// float fTop = (mViewHeight - mCircularWidth) / 2 + mIconPadding;
float fTop = (mViewHeight - mCircularWidth);
mRectFrame.set(getScrollX() + fLeft-8, fTop-8, getScrollX() + mCircularWidth+8 , mCircularWidth+8);
mCircularPaint.setStrokeWidth(8);
mCircularPaint.setColor(Color.parseColor("#32f9f9f9"));
// mCircularPaint.setColor(Color.parseColor("#00ff00"));
canvas.drawArc(mRectFrame, 275, 360, false, mCircularPaint);
mRectF.set(getScrollX() + fLeft, fTop, getScrollX() + mCircularWidth, mCircularWidth);
mCircularPaint.setStrokeWidth(paintwidth);
mCircularPaint.setColor(Color.parseColor("#757575"));
canvas.drawArc(mRectF, 275, 360, false, mCircularPaint);
mSweepAngle = ((float)mCurrentProgress / mMax )*360;
if(mSweepAngle >= 324) {
// 90% 324
// mCircularPaint.setColor(Color.RED);
mCircularPaint.setColor(Color.parseColor("#91c7c1"));
} else if(mSweepAngle >= 216) {
// 60% 216
// mCircularPaint.setColor(Color.parseColor("#ed610a"));
mCircularPaint.setColor(Color.parseColor("#91c7c1"));
} else {
// mCircularPaint.setColor(Color.GREEN);
mCircularPaint.setColor(Color.parseColor("#91c7c1"));
}
canvas.drawArc(mRectF, 275, mSweepAngle, false, mCircularPaint);
mRectF.set(getScrollX() + fLeft+6, fTop+5, getScrollX() + mCircularWidth -5, mCircularWidth-5);
canvas.drawArc(mRectF, 275, 360, false, mCenterPaint);
// 文字内容
long nPercentage = mCurrentProgress * 100 / mMax;
// String strPercentage = String.format("%d%%", nPercentage);
String strPercentage = String.valueOf(nPercentage);
String percentage = "%";
// 文字的长度
float fTxtLeght = mTxtPaint.measureText(strPercentage);
float fPercentLenght = mPerentPaint.measureText("%");
float fTxtHeight = mTxtPaint.measureText("+");
float nLeft = (mViewWidth - fTxtLeght) / 2;
float nTop = (mCircularWidth + fTxtHeight) / 2 + mIconPadding;
// float nTop = (mViewWidth - fTxtHeight) / 2;
mTxtPaint.setTextSize(33);
canvas.drawText(strPercentage, getScrollX() + nLeft - fPercentLenght/2, nTop, mTxtPaint);
canvas.drawText(percentage, getScrollX() + nLeft + fTxtLeght*3/4 , nTop, mPerentPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(mViewWidth, mViewHeight);
}
/**
* 获取比例值
* @return
*/
public int getProgress() {
return mCurrentProgress;
}
/**
* 当前的比例
* @param progress
*/
public void setProgressValue(long progress) {
if(progress < 0) {
progress = 0;
}
if(progress > mMaxValue) {
progress = mMaxValue;
}
mCurrentProgress = (int)(progress * 100 / mMaxValue);
invalidate();
}
public void setProgress(int progress) {
if(progress < 0) {
progress = 0;
}
if(progress > mMax) {
progress = mMax;
}
mCurrentProgress = progress;
invalidate();
}
/**
* 定义的最大值
* @param max
*/
public void setMax(int max) {
mMax = max;
}
public int getMax() {
return mMax;
}
/**
*
*/
public void setMaxValue(long maxValue) {
mMaxValue = maxValue;
}
/**
* 清除Apps,释放内存
*/
private void clearApps() {
ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> infoList = am.getRunningAppProcesses();
// List<ActivityManager.RunningServiceInfo> serviceInfos = am.getRunningServices(100);
mBeforeMem = Utils.getAvailMemory(mContext);
if (infoList != null) {
for (int i = 0; i < infoList.size(); ++i) {
RunningAppProcessInfo appProcessInfo = infoList.get(i);
// Log.d(TAG, "process name : " + appProcessInfo.processName);
//importance 该进程的重要程度 分为几个级别,数值越低就越重要。
Log.d(TAG, "importance : " + appProcessInfo.importance);
// 一般数值大于RunningAppProcessInfo.IMPORTANCE_SERVICE的进程都长时间没用或者空进程了
// 一般数值大于RunningAppProcessInfo.IMPORTANCE_VISIBLE的进程都是非可见进程,也就是在后台运行着
if (appProcessInfo.importance > RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
String[] pkgList = appProcessInfo.pkgList;
for (int j = 0; j < pkgList.length; ++j) {//pkgList 得到该进程下运行的包名
if("com.sen5.launcher".equals(pkgList[j]) || "com.amlogic.DVBPlayer".equals(pkgList[j])) {
continue;
}
try {
am.killBackgroundProcesses(pkgList[j]);
} catch(SecurityException e) {
Log.e(TAG, "killBackgroundProcesses error==" + e.toString());
}
}
}
}
}
}
/**
* 更新界面的动画
*/
private void refeshUI() {
new Thread(new Runnable() {
@Override
public void run() {
for(; mProgress > -1; mProgress--) {
mHandler.sendEmptyMessage(REFRESH_UI);
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
int nUsedMemory = (int)(Utils.getUsedMemory(mContext) * getMax()
/ Utils.getTotalMemory(mContext));
for(; mProgress <= nUsedMemory; mProgress++) {
mHandler.sendEmptyMessage(REFRESH_UI);
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
nUsedMemory = (int)(Utils.getUsedMemory(mContext) * getMax()
/ Utils.getTotalMemory(mContext));
}
mHandler.sendEmptyMessage(REFRESH_END);
}
}).start();
}
/**
* 开始清除内存
*/
public void startClearApps() {
if(!mAllowClear) {
return;
}
mProgress = getProgress();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
mAllowClear = false;
mHandler.sendEmptyMessage(REFRESHING);
clearApps();
}
}).start();
}
/**
* 刷新内存的现实,一般在应用打开时就得调用
*/
public void refreshIconValue() {
setProgressValue(Utils.getUsedMemory(mContext));
}
@Override
public boolean handleMessage(Message msg) {
// TODO Auto-generated method stub
switch(msg.what) {
case REFRESHING:
refeshUI();
break;
case REFRESH_UI:
setProgress(mProgress);
break;
case REFRESH_END:
mAllowClear = true;
// 清除内存的结果显示
long currentMem = Utils.getAvailMemory(mContext);
Log.d(TAG, "AvailMem===" + currentMem + ":::BeforeMem===" + mBeforeMem);
String strHint = "";
if(currentMem > mBeforeMem) {
String strReleaseMem = mContext.getString(R.string.release_memory);
String strCurrentMem = mContext.getString(R.string.currunt_memory);
strHint = String.format("%s %dM,\n%s %dM", strReleaseMem, (currentMem - mBeforeMem)
, strCurrentMem, currentMem);
} else {
strHint = mContext.getString(R.string.best_memory_status);
}
Toast.makeText(mContext, strHint, Toast.LENGTH_SHORT).show();
break;
default:
break;
}
return false;
}
}
//以下是Main调用类
package com.example.atest_rectui;
import com.example.atest_rectui.widget.ClearMemoryView;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
/**
* @author snake
* 调用类
*/
public class MainActivity extends Activity implements OnClickListener{
private ClearMemoryView mClearMemoryView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mClearMemoryView = (ClearMemoryView)findViewById(R.id.tv_myclearmemory);
mClearMemoryView.setOnClickListener(this);
mClearMemoryView.refreshIconValue();
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.tv_myclearmemory:
mClearMemoryView.startClearApps();
break;
default:
break;
}
}
}
//以下是工具类
package com.example.atest_rectui.util;
import android.app.ActivityManager;
import android.app.ActivityManager.MemoryInfo;
import android.content.Context;
/**
* @author snake
* 工具类
*/
public class Utils {
/**
* 获取可用内存大小
* @param context
* @return
*/
public static long getAvailMemory(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
am.getMemoryInfo(mi);
//return Formatter.formatFileSize(context, mi.availMem);// 将获取的内存大小规格化
return mi.availMem / (1024 * 1024);
}
/**
* 获取已用内存大小
* @param context
* @return
*/
public static long getUsedMemory(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
am.getMemoryInfo(mi);
//return Formatter.formatFileSize(context, mi.availMem);// 将获取的内存大小规格化
return (mi.totalMem - mi.availMem) / (1024 * 1024);
}
/**
* 获取总的内存大小
* @param context
* @return
*/
public static long getTotalMemory(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
am.getMemoryInfo(mi);
return mi.totalMem / (1024 * 1024);
}
}
//资源文件
activity_main.xml文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.atest_rectui.MainActivity" >
<com.example.atest_rectui.widget.ClearMemoryView
android:id="@+id/tv_myclearmemory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:focusable="true"
/>
</RelativeLayout>
dimens.xml 文件
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="dimen_bottom_item_layout">110dp</dimen>
</resources>
strings.xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">atest_rectui</string>
<string name="hello_world">Hello world!</string>
<string name="action_settings">Settings</string>
<string name="release_memory">Release memory for</string>
<string name="currunt_memory">Current memory available is</string>
<string name="best_memory_status">Has been cleaned up to the best</string>
</resources>