Android項目實戰--手機衛士35--清除程序緩存



最新實戰教程,讓你瞭解Android自動化刷量、作弊與防作弊的那些事,案例:刷友盟統計、批量註冊蘋果帳號




因爲一直忙着工作的事,也很久沒有更新我們這個項目了,今天就給大家講一下那個清除緩存的功能,其實清除緩存是有兩種的,一種是清除手機rom裏面的緩存,一種是清除手機sd卡里面的緩存,我們今天主要講的就是第一種

ps:這裏來一個知識掃盲,就是手機裏面的rom和ram啦,如果已經知道了的,就可以跳過啦,我們去買手機,有時候經常會被那些銷售人員忽悠的,說什麼8G的內存啦,什麼的,其實他這裏面說的極大可能就是你手機裏面rom的大小啦,rom就是read only menory(只讀存儲器)你可以把它當成你電腦上的硬盤,不過它只能讀取而已,ram就是random access menory(隨機存取器)這個就相當於你電腦的內存啦,所以那個銷售人員說的手機內存有多大的時候,我們一定要問清楚啦,不要被人蒙了


好啦,迴歸正題,我們今天講的那個緩存是清除手機rom裏面的緩存,其實也是挺簡單的,只要知道了要怎麼做之後,至於那個清除sd卡里面的緩存的話,這個我到時會給大家說一下是怎樣清理的,具體我就不寫了,好,先來看一下我們要做的效果

     


上的第一個圖就是我們把我們的應用的一些信息給讀取出來了,但那個界面不怎麼好看,大家可以自己優化一下,當我們點擊了要清理緩存的條目時,我們就會進入到系統設置裏面的一個界面,因爲清理rom裏面的緩存是要root才行的,而我們沒有root,那麼就只要藉助系統裏面的功能啦,到時我也會教大家怎樣root手機的

好啦,廢話不多說,我們直接進入代碼階段

首先,我們先新建一個model類用來存放緩存的信息

com.xiaobin.security.domain.CacheInfo

package com.xiaobin.security.domain;

import android.graphics.drawable.Drawable;

public class CacheInfo
{
	private String name;
	private String packageName;
	private Drawable icon;
	//應用大小
	private String codeSize;
	//數據大小
	private String dataSize;
	//緩存大小
	private String cacheSize;
	
	public String getName()
	{
		return name;
	}
	public void setName(String name)
	{
		this.name = name;
	}
	public String getPackageName()
	{
		return packageName;
	}
	public void setPackageName(String packageName)
	{
		this.packageName = packageName;
	}
	public Drawable getIcon()
	{
		return icon;
	}
	public void setIcon(Drawable icon)
	{
		this.icon = icon;
	}
	public String getCodeSize()
	{
		return codeSize;
	}
	public void setCodeSize(String codeSize)
	{
		this.codeSize = codeSize;
	}
	public String getDataSize()
	{
		return dataSize;
	}
	public void setDataSize(String dataSize)
	{
		this.dataSize = dataSize;
	}
	public String getCacheSize()
	{
		return cacheSize;
	}
	public void setCacheSize(String cacheSize)
	{
		this.cacheSize = cacheSize;
	}

}

寫完model類之後呢,我們就要把我們的應用的信息讀取出來啦,比如讀取應用大小啊,緩存大小啊,數據大小啊,這幾個信息,

那麼,怎樣去讀取這些信息呢,其實PackageManagerj裏面有一個私有的方法的,叫getPackageSizeInfo,

所以現在思路清楚啦,我們就是要通過反射來調用這個方法,然後,getPackageSizeInfo這個方法要傳遞一個IPackageStatsObserver.Stub對象的,這個對象我們一看,就知道是一個AIDL的對象啦,所以,我們就要把相應的AIDL文件給放到src目錄下面啦,我們就是在它裏面拿到緩存大小,這 些數據的啦,

好啦,說得有點玄,直接上代碼更清晰

	/**
	 * 通過AIDL的方法來獲取到應用的緩存信息,getPackageSizeInfo是PackageManager裏面的一個私有方法來的
	 * 我們通過反射就可以調用到它的了,但是這個方法裏面會傳遞一個IPackageStatsObserver.Stub的對象
	 * 裏面就可能通過AIDL來獲取我們想要的信息了
	 * 
	 * 因爲這樣的調用是異步的,所以當我們完成獲取完這些信息之後,我們就通過handler來發送一個消息
	 * 來通知我們的應用,通過getCacheInfos來獲取到我們的Vector
	 * 
	 * 爲什麼要用Vector呢,因爲下面的方法是異步的,也就是有可能是多線程操作,所以我們就用了線程安全的Vector
	 * 
	 * @param cacheInfo
	 * @param position
	 */
	private void initDataSize(final CacheInfo cacheInfo, final int position)
	{
		try
		{
			Method method = PackageManager.class.getMethod(
					"getPackageSizeInfo", new Class[] { String.class,
							IPackageStatsObserver.class });
			method.invoke(packageManager,
					new Object[] { cacheInfo.getPackageName(),
							new IPackageStatsObserver.Stub()
							{
								@Override
								public void onGetStatsCompleted(
										PackageStats pStats, boolean succeeded)
										throws RemoteException
								{
									System.out.println("onGetStatsCompleted" + position);
									long cacheSize = pStats.cacheSize;
									long codeSize = pStats.codeSize;
									long dataSize = pStats.dataSize;

									cacheInfo.setCacheSize(TextFormater
											.dataSizeFormat(cacheSize));
									cacheInfo.setCodeSize(TextFormater
											.dataSizeFormat(codeSize));
									cacheInfo.setDataSize(TextFormater
											.dataSizeFormat(dataSize));

									cacheInfos.add(cacheInfo);

									if (position == (size - 1))
									{
										// 當完全獲取完信息之後,發送一個成功的消息
										// 1對應的就是CacheClearActivity裏面的FINISH
										handler.sendEmptyMessage(1);
									}
								}
							} });
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

有一點是要注意的,獲取緩存大小這些信息的內部實現是異步的,所以我們用一個vector來存放信息,免得會出來一些特殊的情況


好啦,下面我們把完整的類粘出來,這個類寫得有點複雜,主要是因爲獲取緩存大小這些信息的內部實現是異步的,我們要保證數據的正確性,所以可能就寫得有點難理解

大家如果看不懂這個類的話,就歡迎留言

com.xiaobin.security.engine.CacheInfoProvider

package com.xiaobin.security.engine;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Vector;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageStats;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.RemoteException;

import com.xiaobin.security.domain.CacheInfo;
import com.xiaobin.security.utils.TextFormater;

public class CacheInfoProvider
{
	private Handler handler;
	private PackageManager packageManager;
	private Vector<CacheInfo> cacheInfos;
	private int size = 0;

	public CacheInfoProvider(Handler handler, Context context)
	{
		// 拿到一個包管理器
		packageManager = context.getPackageManager();
		this.handler = handler;
		cacheInfos = new Vector<CacheInfo>();
	}

	public void initCacheInfos()
	{
		// 獲取到所有安裝了的應用程序的信息,包括那些卸載了的,但沒有清除數據的應用程序
		List<PackageInfo> packageInfos = packageManager
				.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
		size = packageInfos.size();
		for (int i = 0; i < size; i++)
		{
			PackageInfo packageInfo = packageInfos.get(i);
			CacheInfo cacheInfo = new CacheInfo();
			// 拿到包名
			String packageName = packageInfo.packageName;
			cacheInfo.setPackageName(packageName);
			// 拿到應用程序的信息
			ApplicationInfo applicationInfo = packageInfo.applicationInfo;
			// 拿到應用程序的程序名
			String name = applicationInfo.loadLabel(packageManager).toString();
			cacheInfo.setName(name);
			// 拿到應用程序的圖標
			Drawable icon = applicationInfo.loadIcon(packageManager);
			cacheInfo.setIcon(icon);

			initDataSize(cacheInfo, i);
		}
	}

	/**
	 * 通過AIDL的方法來獲取到應用的緩存信息,getPackageSizeInfo是PackageManager裏面的一個私有方法來的
	 * 我們通過反射就可以調用到它的了,但是這個方法裏面會傳遞一個IPackageStatsObserver.Stub的對象
	 * 裏面就可能通過AIDL來獲取我們想要的信息了
	 * 
	 * 因爲這樣的調用是異步的,所以當我們完成獲取完這些信息之後,我們就通過handler來發送一個消息
	 * 來通知我們的應用,通過getCacheInfos來獲取到我們的Vector
	 * 
	 * 爲什麼要用Vector呢,因爲下面的方法是異步的,也就是有可能是多線程操作,所以我們就用了線程安全的Vector
	 * 
	 * @param cacheInfo
	 * @param position
	 */
	private void initDataSize(final CacheInfo cacheInfo, final int position)
	{
		try
		{
			Method method = PackageManager.class.getMethod(
					"getPackageSizeInfo", new Class[] { String.class,
							IPackageStatsObserver.class });
			method.invoke(packageManager,
					new Object[] { cacheInfo.getPackageName(),
							new IPackageStatsObserver.Stub()
							{
								@Override
								public void onGetStatsCompleted(
										PackageStats pStats, boolean succeeded)
										throws RemoteException
								{
									System.out.println("onGetStatsCompleted" + position);
									long cacheSize = pStats.cacheSize;
									long codeSize = pStats.codeSize;
									long dataSize = pStats.dataSize;

									cacheInfo.setCacheSize(TextFormater
											.dataSizeFormat(cacheSize));
									cacheInfo.setCodeSize(TextFormater
											.dataSizeFormat(codeSize));
									cacheInfo.setDataSize(TextFormater
											.dataSizeFormat(dataSize));

									cacheInfos.add(cacheInfo);

									if (position == (size - 1))
									{
										// 當完全獲取完信息之後,發送一個成功的消息
										// 1對應的就是CacheClearActivity裏面的FINISH
										handler.sendEmptyMessage(1);
									}
								}
							} });
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	public Vector<CacheInfo> getCacheInfos()
	{
		return cacheInfos;
	}

	public void setCacheInfos(Vector<CacheInfo> cacheInfos)
	{
		this.cacheInfos = cacheInfos;
	}

}

其實主要的思想是這們的,當完全獲取完所有應用的緩存大小這些信息的時候,我們就給activity發送一個消息,然後activity裏面的handler處理這個消息,然後就通過getCacheInfos這個方法,拿到所有已經填充好信息的CacheInfos對象的集合啦,這樣,我們就可以回到activity裏面填充數據啦


上面我已經說過了,如果我們要自己刪除rom的緩存的話,那就是要root權限的,但我們現在沒有,所以,我們就要通過系統設置裏面的一個功能來進行清除啦

				/**
				 * Android2.3打開settings裏面的那個應用的詳細界面
				 * 後來我又查了一個Android4.1的,也是這樣寫的,所有應該是2.3之後,都是這樣寫的了,
				 * 但是這只是猜測,各位有空的可以去下載Android Settings的代碼看一下
				 * 這樣就可以做成多個版本的適配了
				 * <intent-filter> 
				 * <action android:name="android.settings.APPLICATION_DETAILS_SETTINGS" /> 
				 * <category android:name="android.intent.category.DEFAULT" /> 
				 * <data android:scheme="package" /> 
				 * </intent-filter>
				 */
				
				/**
				 * Android2.2打開settings裏面的那個應用的詳細界面
				 * 用這個版本來打開的話,就要加多一句把包名設置進去的
				 * intent.putExtra("pkg", packageName);
				 * <intent-filter> 
				 * <action android:name="android.intent.action.VIEW" /> 
				 * <category android:name="android.intent.category.DEFAULT" /> 
				 * <category android:name="android.intent.category.VOICE_LAUNCH" />
				 * </intent-filter>
				 */
				
				Intent intent = new Intent();
				intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
				intent.addCategory("android.intent.category.DEFAULT");
				intent.setData(Uri.parse("package:" + cacheInfos.get(position).getPackageName()));
				startActivity(intent);

上面的註釋已經很詳細了,我就不多說啦


下面是完整的activity代碼,佈局文件就不放啦,因爲寫得太難看了

com.xiaobin.security.ui.CacheClearActivity

package com.xiaobin.security.ui;

import java.util.Vector;

import android.annotation.SuppressLint;
import android.app.ListActivity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

import com.xiaobin.security.R;
import com.xiaobin.security.domain.CacheInfo;
import com.xiaobin.security.engine.CacheInfoProvider;

public class CacheClearActivity extends ListActivity
{
	private static final int LOADING = 0;
	private static final int FINISH = 1;

	private CacheInfoProvider provider;

	private ListView lv_list;
	private LinearLayout ll_load;

	private Vector<CacheInfo> cacheInfos;

	@SuppressLint("HandlerLeak")
	private Handler handler = new Handler()
	{
		public void handleMessage(Message msg)
		{
			switch (msg.what)
			{
				case LOADING:
					ll_load.setVisibility(View.VISIBLE);
					break;

				case FINISH:
					ll_load.setVisibility(View.INVISIBLE);
					// 當加載完成之後,就調用provider裏面的get方法,
					// 這樣就可以得到一個加載完成後的數據了
					cacheInfos = provider.getCacheInfos();
					lv_list.setAdapter(new CacheAdapter());
					break;

				default:
					break;
			}
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.cache_clear);

		provider = new CacheInfoProvider(handler, this);

		lv_list = getListView();
		ll_load = (LinearLayout) findViewById(R.id.ll_cache_clear_load);
		lv_list.setOnItemClickListener(new OnItemClickListener()
		{
			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id)
			{
				/**
				 * Android2.3打開settings裏面的那個應用的詳細界面
				 * 後來我又查了一個Android4.1的,也是這樣寫的,所有應該是2.3之後,都是這樣寫的了,
				 * 但是這只是猜測,各位有空的可以去下載Android Settings的代碼看一下
				 * 這樣就可以做成多個版本的適配了
				 * <intent-filter> 
				 * <action android:name="android.settings.APPLICATION_DETAILS_SETTINGS" /> 
				 * <category android:name="android.intent.category.DEFAULT" /> 
				 * <data android:scheme="package" /> 
				 * </intent-filter>
				 */
				
				/**
				 * Android2.2打開settings裏面的那個應用的詳細界面
				 * 用這個版本來打開的話,就要加多一句把包名設置進去的
				 * intent.putExtra("pkg", packageName);
				 * <intent-filter> 
				 * <action android:name="android.intent.action.VIEW" /> 
				 * <category android:name="android.intent.category.DEFAULT" /> 
				 * <category android:name="android.intent.category.VOICE_LAUNCH" />
				 * </intent-filter>
				 */
				
				Intent intent = new Intent();
				intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
				intent.addCategory("android.intent.category.DEFAULT");
				intent.setData(Uri.parse("package:" + cacheInfos.get(position).getPackageName()));
				startActivity(intent);
			}
		});

		loadData();
	}
	
	private void loadData()
	{
		ll_load.setVisibility(View.VISIBLE);
		new Thread(new Runnable()
		{
			@Override
			public void run()
			{
				provider.initCacheInfos();
			}
		}).start();
	}

	// =======================================================================

	private class CacheAdapter extends BaseAdapter
	{

		@Override
		public int getCount()
		{
			return cacheInfos.size();
		}

		@Override
		public Object getItem(int position)
		{
			return cacheInfos.get(position);
		}

		@Override
		public long getItemId(int position)
		{
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent)
		{
			View view;
			ViewHolder holder;
			CacheInfo info = cacheInfos.get(position);
			if (convertView == null)
			{
				view = View.inflate(CacheClearActivity.this,
						R.layout.cache_clear_item, null);
				holder = new ViewHolder();
				holder.iv_icon = (ImageView) view
						.findViewById(R.id.iv_cache_icon);
				holder.tv_name = (TextView) view
						.findViewById(R.id.tv_cache_name);
				holder.tv_code = (TextView) view
						.findViewById(R.id.tv_cache_code);
				holder.tv_data = (TextView) view
						.findViewById(R.id.tv_cache_data);
				holder.tv_cache = (TextView) view
						.findViewById(R.id.tv_cache_cache);
				view.setTag(holder);
			}
			else
			{
				view = convertView;
				holder = (ViewHolder) view.getTag();
			}
			holder.iv_icon.setImageDrawable(info.getIcon());
			holder.tv_name.setText(info.getName());
			holder.tv_code.setText("應用大小:" + info.getCodeSize());
			holder.tv_data.setText("數據大小:" + info.getDataSize());
			holder.tv_cache.setText("緩存大小:" + info.getCacheSize());
			return view;
		}

	}

	private class ViewHolder
	{
		ImageView iv_icon;
		TextView tv_name;
		TextView tv_cache;
		TextView tv_code;
		TextView tv_data;

	}

}

好啦,到這裏爲止,我們的清除rom裏面的緩存,就已經是完成的啦,最後,我給大家說一下清除sd卡里面的緩存是怎樣的

大家都知道,我們裝的大部分應用,都會有sd卡里面建一個目錄,然後裝一些應用的信息的,而這些,就是這些應用對應存放緩存的目錄啦,

要清除sd卡里面的緩存,其實就是要有一個數據庫啦,它專門收錄市面上一些常用的應用,在sd卡上建立的目錄名稱,然後再通過這個數據庫,然後對sd卡里面的目錄清除的而已,這個方法是比較的麻煩的,還要有數據庫的支持才行,所以大家可以自己試試


最後,和大家說一下

爲了方便大家的交流,我創建了一個羣,這樣子大家有什麼疑問也可以在羣上交流

羣號是298440981


今天源碼下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章