最新實戰教程,讓你瞭解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