Android項目實戰_手機安全衛士系統加速
## 1.本地數據庫自動更新的工作機制
1. 開啟一個服務,定時訪問服務器
2. 進行版本對比,如果最新版本比較高,獲取需要更新的內容
3. 將新內容插入到本地數據庫中
## 2.如何處理橫豎屏切換
1. 指定屏幕朝向
在清單文件對應的Activity中配置android:screenOrientation=”landscape”(橫屏,portrait是豎屏);
2. 設置屏幕旋轉時不重新創建Activity
在清單文件對應的Activity中配置android:configChanges="keyboardHidden|orientation|screenSize",最好這三個都配置,否則不能適配所有機型或sdk版本。
橫豎屏切換時會走Activity的onConfigurationChanged()方法
@Override
public void onConfigurationChanged(Configuration newConfig) {
// 當新設置中,屏幕布局模式為橫排時
if(newConfig.orientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE){
//TODO 某些操作
}else{
//TODO 某些操作
}
super.onConfigurationChanged(newConfig);
}
##3.系統控件的樣式在哪裏定義
1. 找到文件:sdk/platforms/某個版本/data/res/values/styles.xml
2. 搜索關註的控件,如ProgressBar
<style name="Widget.ProgressBar.Horizontal">
//indeterminate不確定
<item name="android:indeterminateOnly">false</item>
//進度條使用的圖片
<item name="android:progressDrawable">@android:drawable/progress_horizontal</item>
//進度不確定的時候使用的圖片,如安裝APK時系統的進度條
<item name="android:indeterminateDrawable">@android:drawable/progress_indeterminate_horizontal</item>
<item name="android:minHeight">20dip</item>
<item name="android:maxHeight">20dip</item>
</style>
##4.Fragment添加到Activity上有哪些步驟?
//獲得管理器
FragmentManager fm = getSupportFragmentManager();
//獲得切換Fragment的幫助類,有add添加、delete刪除、replace替換、hide隱藏、show顯示
FragmentTransaction ft = fm.beginTransaction();
//創建Fragment
CleanCacheFragment f1 = new CleanCacheFragment();
ft.replace(R.id.fl_container, f1);
//提交切換Fragment的事務
ft.commit();
##5.Fragment的生命周期
1. onAttach():Fragment對象跟Activity關聯時
2. onCreate():Fragment對象的初始創建時
3. onCreateView():創建Fragment的View對象時
4. onActivityCreate():所依附的Activity對象已經完成了Activity.onCreate()方法時
5. onStart():界面即將顯示給用戶,當Activity的onStart方法調用時
6. onResume():可以獲取焦點與用戶交互,當Activity的onResume調用時
7. onPause():Activity被遮擋不可獲取焦點調用了onPause時,或者Activity(或其他容器)打開另一個Fragment,當前Fragemnt無法獲取焦點時
8. onStop():Activity不可見調用了onStop()時,或者Activity(或其他容器)打開另一個Fragment當前Fragment不再顯示給用戶時
9. onDestroyView():Fragment中的View對象即將被從當前界面中移除時
10. onDestroy():Fragment對象被銷毀時
11. onDetach():在Fragment對象不再跟它依附的Activity關聯的時候,方法會立即被調用
## 6.緩存
路徑:data/data/包名/cache。用於存放臨時文件,當系統空間不足時會清空該目錄數據
//獲取當前應用的緩存文件夾
context.getCacheDir();
## 7.如何從應用源碼中定位實現邏輯
1. 通過UI上一些字符串進行全局搜索,Ctrl+H 中的 FileSearch
2. 通過string.xml中對應字符串id定位layout布局
3. 通過layout布局中的id,定位代碼中該View的事件邏輯
## 8.如何獲取應用的緩存
1. 經過分析源碼,發現獲取應用的緩存可以使用packageManager.getPackageSizeInfo()方法
2. pm的getPackageSizeInfo()方法為hide,無法直接調用,所以使用反射調用該方法
3. getPackageSizeInfo()需要兩個參數,第一個為包名,第二個為一個回調接口IPackageStatsObserver.Stub這種形式一般為遠程調用系統服務,需要使用aidl,將aidl文件拷貝到本項目中,註意要使用aidl文件中的原始包名
4. 代碼實現,需要權限<uses-permission android:name="android.permission.GET_PACKAGE_SIZE"/>
//1.獲得packageManager對象
PackageManager pm = getPackageManager();
//2.pm的getPackageSizeInfo()方法為hide,使用反射調用
Method[] methods = PackageManager.class.getDeclaredMethods();
for(Method method:methods){
if("getPackageSizeInfo".equals(method.getName())){
try {
//3.第二個參數需要使用aidl創建
method.invoke(pm, "com.hb.testcache",new IPackageStatsObserver.Stub(){
@Override
public void onGetStatsCompleted(PackageStats pStats,
boolean succeeded) throws RemoteException {
long cacheSize = pStats.cacheSize;
System.out.println("緩存大小:"+cacheSize);
}
});
} catch (Exception e) {
e.printStackTrace();
}
return;
}
}
###界面實現步驟:
1. 在onstart方法中開啟子線程獲取每一個應用程序的包名,緩存大小,應用名等信息
2. 在掃描的過程中睡眠50毫秒去顯示進度條的更新
3. 通過handler消息機制來更新textview文本顯示正在掃描的應用程序
4. 掃描完畢更新ui顯示有緩存的應用程序(Linearlayout添加多個textview實現)
註意:應用程序的包名,緩存大小,應用名等最好做成一個業務bean,方便數據傳遞和使用
## 9.如何清除一個應用的緩存
需要應用為系統應用
packageManager.deleteApplicationCacheFiles(String packageName,IPackageDataObserver observer)
權限:要求系統應用
<uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
只能通過打開應用詳細信息界面,讓用戶手動去點擊清除緩存
Intent intent = new Intent("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setData(Uri.parse("package:"+info.packName));
startActivity(intent);
###10.清除全部應用緩存
利用系統漏洞,google忘記把CLEAR\_APP\_CACHE權限聲明為只有系統應用才可以申請的權限
//建議Long.MAX_VALUE。
PackageManager.freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer);
//權限
<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
//模擬一個超級大存儲空間的請求。
//freeStorageAndNotify
Method[] methods = PackageManager.class.getDeclaredMethods();
for(Method method:methods){
if("freeStorageAndNotify".equals(method.getName())){
try {
method.invoke(pm, Long.MAX_VALUE,new IPackageDataObserver.Stub() {
@Override
public void onRemoveCompleted(String packageName, boolean succeeded)
throws RemoteException {
}
});
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
activity:
1 package com.hb.mobilesafe.activities; 2 3 import android.app.Activity; 4 import android.app.FragmentManager; 5 import android.app.FragmentTransaction; 6 import android.os.Bundle; 7 import android.view.View; 8 import android.view.View.OnClickListener; 9 import android.view.Window; 10 import android.widget.FrameLayout; 11 import android.widget.LinearLayout; 12 13 import com.hb.demo_mobilesafe.R; 14 import com.hb.mobilesafe.fragmet.ChacheFramgment; 15 import com.hb.mobilesafe.fragmet.SdcardFramgment; 16 17 public class SysChacheActivity extends Activity implements OnClickListener { 18 private FrameLayout fl_content; 19 private LinearLayout ll_clrea_chache; 20 private LinearLayout ll_clrean_sdcard; 21 22 @Override 23 protected void onCreate(Bundle savedInstanceState) { 24 // TODO Auto-generated method stub 25 super.onCreate(savedInstanceState); 26 requestWindowFeature(Window.FEATURE_NO_TITLE); 27 setContentView(R.layout.activity_syschache); 28 ll_clrean_sdcard=(LinearLayout) findViewById(R.id.ll_clrean_sdcard); 29 ll_clrea_chache=(LinearLayout) findViewById(R.id.ll_clrea_chache); 30 fl_content=(FrameLayout) findViewById(R.id.fl_content); 31 ll_clrea_chache.setOnClickListener(this); 32 ll_clrean_sdcard.setOnClickListener(this); 33 FragmentManager fm = getFragmentManager(); 34 FragmentTransaction ft = fm.beginTransaction(); 35 ft.replace(R.id.fl_content,new ChacheFramgment(SysChacheActivity.this)); 36 ft.commit(); 37 } 38 @Override 39 public void onClick(View v) { 40 FragmentManager fm = getFragmentManager(); 41 FragmentTransaction ft = fm.beginTransaction(); 42 switch (v.getId()) { 43 case R.id.ll_clrea_chache: 44 ft.replace(R.id.fl_content,new ChacheFramgment(SysChacheActivity.this)); 45 46 break; 47 case R.id.ll_clrean_sdcard: 48 49 ft.replace(R.id.fl_content, new SdcardFramgment(SysChacheActivity.this)); 50 51 break; 52 } 53 ft.commit(); 54 } 55 56 }
fragment:
1 package com.hb.mobilesafe.fragmet; 2 3 import java.lang.reflect.Method; 4 import java.util.ArrayList; 5 import java.util.List; 6 7 import android.annotation.SuppressLint; 8 import android.app.Fragment; 9 import android.content.Context; 10 import android.content.pm.IPackageDataObserver; 11 import android.content.pm.IPackageStatsObserver; 12 import android.content.pm.PackageInfo; 13 import android.content.pm.PackageManager; 14 import android.content.pm.PackageStats; 15 import android.graphics.Color; 16 import android.os.Bundle; 17 import android.os.Handler; 18 import android.os.Message; 19 import android.os.RemoteException; 20 import android.os.SystemClock; 21 import android.text.format.Formatter; 22 import android.view.LayoutInflater; 23 import android.view.View; 24 import android.view.View.OnClickListener; 25 import android.view.ViewGroup; 26 import android.widget.Button; 27 import android.widget.LinearLayout; 28 import android.widget.ProgressBar; 29 import android.widget.TextView; 30 31 import com.hb.demo_mobilesafe.R; 32 import com.hb.mobilesafe.bean.AppChacheInfo; 33 34 @SuppressLint("InflateParams") 35 public class ChacheFramgment extends Fragment { 36 37 38 protected static final int CHACHE = 0; 39 private static final int SIZE = 1; 40 private TextView tv_show_name; 41 private LinearLayout ll_show_content; 42 private Button bt_clean; 43 private Context context; 44 private PackageManager pm; 45 private ProgressBar pg_gram; 46 public ChacheFramgment(Context context){ 47 this.context=context; 48 } 49 private Handler handler=new Handler(){ 50 public void handleMessage(android.os.Message msg) { 51 switch (msg.what) { 52 case 0: 53 tv_show_name.setText("掃描完成"); 54 pg_gram.setVisibility(View.GONE); 55 break; 56 57 case SIZE: 58 AppChacheInfo appinfo=(AppChacheInfo)msg.obj; 59 tv_show_name.setText("正在掃描:"+appinfo.getAppName()); 60 TextView textView=new TextView(context); 61 textView.setTextColor(Color.RED); 62 if(appinfo.getAppChaCheSize()>0){ 63 textView.setText(appinfo.getAppName()+":"+Formatter.formatFileSize(context, appinfo.getAppChaCheSize())); 64 ll_show_content.addView(textView, 0); 65 } 66 break; 67 case 3: 68 tv_show_name.setText("清理完成"); 69 ll_show_content.removeAllViews(); 70 break; 71 } 72 }; 73 }; 74 @Override 75 public View onCreateView(LayoutInflater inflater, ViewGroup container, 76 Bundle savedInstanceState) { 77 View view = inflater.inflate(R.layout.fagment_chache, null); 78 tv_show_name = (TextView) view.findViewById(R.id.tv_show_name); 79 ll_show_content = (LinearLayout) view.findViewById(R.id.ll_show_content); 80 bt_clean=(Button) view.findViewById(R.id.bt_clean); 81 pg_gram=(ProgressBar) view.findViewById(R.id.pB_program); 82 bt_clean.setOnClickListener(new OnclikLeanEvent()); 83 pm = context.getPackageManager(); 84 return view; 85 } 86 @Override 87 public void onStart() { 88 super.onStart(); 89 new ThreadRun().start(); 90 91 } 92 /** 93 * 掃描所有APP 94 * @return 95 */ 96 public List<AppChacheInfo> scanApp(){ 97 List<PackageInfo> list = pm.getInstalledPackages(0); 98 List<AppChacheInfo> aInfo=new ArrayList<AppChacheInfo>(); 99 for (PackageInfo mInfo : list) { 100 AppChacheInfo info = new AppChacheInfo(); 101 String packageName = mInfo.packageName; 102 String appName = mInfo.applicationInfo.loadLabel(pm).toString(); 103 info.setAppPacagenName(packageName); 104 info.setAppName(appName); 105 aInfo.add(info); 106 } 107 int i=0; 108 for (AppChacheInfo cInfo : aInfo) { 109 findChache(cInfo.getAppPacagenName(), cInfo); 110 i++; 111 pg_gram.setProgress(i); 112 SystemClock.sleep(200); 113 Message message=new Message(); 114 message.obj=cInfo; 115 message.what=SIZE; 116 handler.sendMessage(message); 117 } 118 119 return aInfo; 120 121 } 122 123 /** 124 * 得到緩存 125 * public abstract void getPackageSizeInfo(String packageName, int userHandle, 126 * IPackageStatsObserver observer); 127 *Stub 存根,負責接收本地方法調用,並將它們賦給各自的具體實現對象 128 */ 129 130 public void findChache(String packageName ,final AppChacheInfo chacheInfo){ 131 try { 132 133 Method method = PackageManager.class.getMethod("getPackageSizeInfo",String.class, IPackageStatsObserver.class); 134 method.invoke(pm, packageName,new IPackageStatsObserver.Stub() { 135 136 @Override 137 public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) 138 throws RemoteException { 139 long size = pStats.cacheSize; 140 chacheInfo.setAppChaCheSize(size); 141 } 142 }); 143 } catch (Exception e) { 144 e.printStackTrace(); 145 } 146 } 147 /** 148 * 149 * @author 清理緩存 150 * class ClearCacheObserver extends IPackageDataObserver.Stub { 151 public void onRemoveCompleted(final String packageName, final boolean succeeded) { 152 final Message msg = mHandler.obtainMessage(CLEAR_CACHE); 153 msg.arg1 = succeeded ? OP_SUCCESSFUL:OP_FAILED; 154 mHandler.sendMessage(msg); 155 } 156 } 157 */ 158 private void clean() { 159 try { 160 Method method = PackageManager.class.getMethod("freeStorageAndNotify", long.class,IPackageDataObserver.class); 161 method.invoke(pm,Long.MAX_VALUE,new IPackageDataObserver.Stub() { 162 163 @Override 164 public void onRemoveCompleted(String packageName, boolean succeeded) 165 throws RemoteException { 166 handler.sendEmptyMessage(3); 167 } 168 }); 169 } catch (Exception e) { 170 // TODO Auto-generated catch block 171 e.printStackTrace(); 172 } 173 } 174 class OnclikLeanEvent implements OnClickListener { 175 176 @Override 177 public void onClick(View v) { 178 clean(); 179 } 180 181 } 182 @Override 183 public void onDestroy() { 184 super.onDestroy(); 185 new ThreadRun().interrupt(); 186 187 } 188 class ThreadRun extends Thread{ 189 @Override 190 public void run() { 191 super.run(); 192 List<AppChacheInfo> app = scanApp(); 193 pg_gram.setMax(app.size()); 194 handler.sendEmptyMessage(0); 195 } 196 } 197 198 199 }
Android項目實戰_手機安全衛士系統加速