![Android開發(fā)之做一鍵批量卸載App功能的詳細講解_第1頁](http://file4.renrendoc.com/view/afd859391916848efa98cff9c66baca8/afd859391916848efa98cff9c66baca81.gif)
![Android開發(fā)之做一鍵批量卸載App功能的詳細講解_第2頁](http://file4.renrendoc.com/view/afd859391916848efa98cff9c66baca8/afd859391916848efa98cff9c66baca82.gif)
![Android開發(fā)之做一鍵批量卸載App功能的詳細講解_第3頁](http://file4.renrendoc.com/view/afd859391916848efa98cff9c66baca8/afd859391916848efa98cff9c66baca83.gif)
![Android開發(fā)之做一鍵批量卸載App功能的詳細講解_第4頁](http://file4.renrendoc.com/view/afd859391916848efa98cff9c66baca8/afd859391916848efa98cff9c66baca84.gif)
![Android開發(fā)之做一鍵批量卸載App功能的詳細講解_第5頁](http://file4.renrendoc.com/view/afd859391916848efa98cff9c66baca8/afd859391916848efa98cff9c66baca85.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
Android開發(fā)之做一鍵批量卸載App功能的詳細講解首先準備一部已經(jīng)Root的手機,然后打開\t"/kf/201807/_blank"Android
Studio,下面我們開始快樂的寫代碼吧~首先我們先分析具體的業(yè)務需求:很簡單的一個需求,最主要的功能就是可以卸載App;同時要求可以批量卸載;既然能夠批量卸載,也就是說我們在UI交互上可以批量選擇;能大量展示待卸載的App。好的我們現(xiàn)在一步一步的來:首先我們先解決最主要的需求,卸載App!有兩種方式可以實現(xiàn)App卸載:分為靜默方式和非靜默方式。什么是靜默方式?意思就是說卸載完全是在\t"/kf/201807/_blank"系統(tǒng)后臺進行的,不需要用戶去點擊確認卸載。非靜默方式的意思顯而易見,卸載的時候需要用戶點擊確認,只有用戶確認卸載才會卸載。我們先說非靜默方式卸載:非靜默方式卸載的代碼如下;?123456789publicvoidunstallApp(StringpageName){
IntentuninstallIntent=newIntent();
uninstallIntent.setAction(Intent.ACTION_DELETE);
uninstallIntent.setData(Uri.parse("package:"+pageName));
startActivityForResult(uninstall_intent,1);
}從代碼中我們就可以看出來,這里開啟了一個活動,也就是所謂的應用卸載程序,然后把需要卸載的App包名交給它,它就會把這個App給卸載掉。這是正常的App卸載步驟。開啟這個應用卸載程序活動后,頁面就會跳轉(zhuǎn)到卸載頁面,然后等待用戶點擊確定或者取消,點擊確定就會執(zhí)行卸載程序,點擊取消就會回退到原來的活動。在這里我們使用了startActivityForResult()方法來開啟應用卸載活動,目的是為了卸載完成后在回掉函數(shù)里面可以更新原來的App列表頁面。非靜默方式代碼非常的簡單,也非常容易理解,但是這里有個不足之處,那就是如果我們一次性需要卸載十個APP應用,那么頁面將會跳轉(zhuǎn)十次,同時你也需要點擊十次確定!別忘了我們這里可是要求批量卸載,如果讓用戶去連續(xù)點擊十次確定,這樣會非常影響用戶體驗!所以非靜默方式卸載在這里使用并不是很好,靜默方式是更好的選擇!靜默方式卸載:靜默方式也就是意味著我們需要繞過安卓的界面,在后臺執(zhí)行卸載命令,那么怎么做呢?很顯然,當然是使用命令了!使用命令的方式我們可以繞過安卓界面執(zhí)行。這里有兩種卸載App命令:首先是adb命令:adbuninstall<app包名>還有一個pm命令:pmuninstall<app包名>我們可以看到這兩種命令寫法相同,命令的開頭不同,那么他們具體的差別在什么地方呢?應該用哪一種命令方式?還是兩種命令方式都合適呢?我先不說區(qū)別,我們?nèi)嵉氐臏y試一下,首先我們先用adb命令去卸載。代碼如下:?12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152packagecom.example.uninstallapk;
importandroid.util.Log;
importjava.io.DataOutputStream;
/**
*Createdby王將on2018/7/23.
*/
//adb命令翻譯執(zhí)行類publicclassRootCmd{
/***
*@paramcommand
*@return
*/
publicstaticbooleanexusecmd(Stringcommand){
Processprocess=null;
DataOutputStreamos=null;
try{process=Runtime.getRuntime().exec("su");os=newDataOutputStream(process.getOutputStream());os.writeBytes(command+"\n");os.writeBytes("exit\n");os.flush();Log.e("updateFile","======000==writeSuccess======");process.waitFor();
}catch(Exceptione){Log.e("updateFile","======111=writeError======"+e.toString());returnfalse;
}finally{try{
if(os!=null){
os.close();
}
if(process!=null){
process.destroy();
}}catch(Exceptione){
e.printStackTrace();}
}
returntrue;
}
publicstaticvoidunInstallApk(StringpageName){
exusecmd("adbuninstall"+pageName);
}
}主活動中我們調(diào)用:?1RootCmd.unInstallApk("com.example.tset");把想要卸載的App包名傳進去,運行一下,很快你就發(fā)現(xiàn):整個應用崩潰了,出現(xiàn)了ANR問題,應用無反應。好,我們改為pm命令試一下,結(jié)果發(fā)現(xiàn)成功了!那么現(xiàn)在我們分析一下為什么adb命令會導致出現(xiàn)ANR問題,而pm命令就不會出現(xiàn)錯誤。樂淘棋牌一個命令的下達,肯定會調(diào)用相應的方法去處理,只不過這個調(diào)用過程在系統(tǒng)的內(nèi)部,我們外界是看不到的,只能得到命令執(zhí)行的結(jié)果。就好比我們使用命令去卸載App應用,同樣也是在內(nèi)部調(diào)用了卸載方法,那么具體這個方法是什么?在哪里呢?下面我們就去深入的探討一下。Android系統(tǒng)卸載App應用都是調(diào)用了一個類中方法,不管是非靜默模式還是靜默模式,這個類就是PackageInstaller類。當然Android系統(tǒng)安裝App也同樣是調(diào)用的它里面的方法,這個類功能從它的名字上就可以看出來:打包安裝程序。當然這個類我們在平常的開發(fā)中是用不到的,同樣也是無法調(diào)用的,這個類同樣也是一個底層調(diào)用的類。在這個類中我們可以找到具體的卸載App方法,讓我們看一下\t"/kf/201807/_blank"源碼:?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172/**
*Uninstallthegivenpackage,removingitcompletelyfromthedevice.This
*methodisonlyavailabletothecurrent"installerofrecord"forthe
*package.
*
*@parampackageNameThepackagetouninstall.
*@paramstatusReceiverWheretodelivertheresult.
*/
publicvoiduninstall(@NonNullStringpackageName,@NonNullIntentSenderstatusReceiver){
uninstall(packageName,0/*flags*/,statusReceiver);
}
/**
*Uninstallthegivenpackage,removingitcompletelyfromthedevice.This
*methodisonlyavailabletothecurrent"installerofrecord"forthe
*package.
*
*@parampackageNameThepackagetouninstall.
*@paramflagsFlagsforuninstall.
*@paramstatusReceiverWheretodelivertheresult.
*
*@hide
*/
publicvoiduninstall(@NonNullStringpackageName,@DeleteFlagsintflags,@NonNullIntentSenderstatusReceiver){
uninstall(newVersionedPackage(packageName,PackageManager.VERSION_CODE_HIGHEST),
flags,statusReceiver);
}
/**
*Uninstallthegivenpackagewithaspecificversioncode,removingit
*completelyfromthedevice.Thismethodisonlyavailabletothecurrent
*"installerofrecord"forthepackage.Iftheversioncodeofthepackage
*doesnotmatchtheonepassedintheversionedpackageargumentthis
*methodisano-op.Use{@linkPackageManager#VERSION_CODE_HIGHEST}to
*uninstallthelatestversionofthepackage.
*
*@paramversionedPackageTheversionedpackagetouninstall.
*@paramstatusReceiverWheretodelivertheresult.
*/
publicvoiduninstall(@NonNullVersionedPackageversionedPackage,@NonNullIntentSenderstatusReceiver){
uninstall(versionedPackage,0/*flags*/,statusReceiver);
}
/**
*Uninstallthegivenpackagewithaspecificversioncode,removingit
*completelyfromthedevice.Thismethodisonlyavailabletothecurrent
*"installerofrecord"forthepackage.Iftheversioncodeofthepackage
*doesnotmatchtheonepassedintheversionedpackageargumentthis
*methodisano-op.Use{@linkPackageManager#VERSION_CODE_HIGHEST}to
*uninstallthelatestversionofthepackage.
*
*@paramversionedPackageTheversionedpackagetouninstall.
*@paramflagsFlagsforuninstall.
*@paramstatusReceiverWheretodelivertheresult.
*
*@hide
*/
@RequiresPermission(anyOf={Manifest.permission.DELETE_PACKAGES,Manifest.permission.REQUEST_DELETE_PACKAGES})
publicvoiduninstall(@NonNullVersionedPackageversionedPackage,@DeleteFlagsintflags,@NonNullIntentSenderstatusReceiver){
Preconditions.checkNotNull(versionedPackage,"versionedPackagecannotbenull");
try{mInstaller.uninstall(versionedPackage,mInstallerPackageName,
flags,statusReceiver,mUserId);
}catch(RemoteExceptione){throwe.rethrowFromSystemServer();
}
}這個是PackageInstaller類中的四個uninstall()方法,具體的功能就是卸載App應用。當然這四個方法用于卸載不同狀態(tài)的應用,具體的使用請看官方給出的描述文檔,這里不再具體的做出分析。現(xiàn)在我們知道了卸載App調(diào)用的是PackageInstaller類的uninstall()方法,那么這個和命令的方式有什么關(guān)系呢?我們看一下PackageInstaller類的所處路徑你就明白了,PackageInstaller類的所處路徑為/android/content/pm/PackageInstaller.java,具體在博主這里的完整路徑為:很明顯,在/pm路徑下。pm全稱packagemanager,意思包的管理者,pm命令說白了就是包管理命令,進一步說,只有使用pm命令才會調(diào)用/pm路徑下的底層方法,也就是說才會執(zhí)行包文件的操作。這下你明白為什么使用adb會導致ANR問題了吧,因為程序找不到執(zhí)行方法??!純真棋牌好了,現(xiàn)在我們解決了最重要的需求,靜默卸載App,那么接下來的需求就很簡單實現(xiàn)了,批量卸載,批量選擇,這里直接使用一個循環(huán)不停的執(zhí)行卸載命令就好了。按照這個思路我們開始寫代碼。首先是界面UI部分:?12345678<!--xmlversion="1.0"encoding="utf-8"--><linearlayoutandroid:layout_height="match_parent"android:layout_width="match_parent"android:orientation="vertical"xmlns:android="/apk/res/android">
<scrollviewandroid:layout_height="1dp"android:layout_weight="10"android:layout_width="match_parent">
<linearlayoutandroid:id="@+id/linear1"android:layout_height="wrap_content"android:layout_width="match_parent"android:orientation="vertical">
</linearlayout>
</scrollview><buttonandroid:id="@+id/start_delete"android:layout_height="1dp"android:layout_weight="1"android:layout_width="match_parent"android:text="一鍵卸載"></button></linearlayout>使用ScrollView嵌套一個LinearLayout布局來實現(xiàn)App列表,其中單個的App信息使用動態(tài)加載的形式添加。下面是一個App信息子布局:?123456<!--xmlversion="1.0"encoding="utf-8"--><linearlayoutandroid:layout_height="wrap_content"android:layout_width="match_parent"android:orientation="horizontal"xmlns:android="/apk/res/android">
<checkboxandroid:id="@+id/page_id"android:layout_height="wrap_content"android:layout_width="wrap_content">
<textviewandroid:id="@+id/page_name"android:layout_height="wrap_content"android:layout_width="wrap_content"android:text="應用包名"android:textcolor="#000000"></textview></checkbox></linearlayout>很簡單,兩個控件組成,一個ChexBox控件提供勾選,一個TextView用來展示App的標簽。638棋牌接下來我們就需要寫主活動中的邏輯性操作了:首先貼上我們的MainActivity代碼:?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121publicclassMainActivityextendsAppCompatActivity{
LinearLayoutlinearLayout;
List<integer>pages=newArrayList<>();
List<view>views=newArrayList<>();
ProgressDialogprogressDialog;
List<packageinfo>packageInfos=newArrayList<>();
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
linearLayout=(LinearLayout)findViewById(R.id.linear1);
Buttonbutton=(Button)findViewById(R.id.start_delete);
PackageManagerpackageManager=getPackageManager();
packageInfos=packageManager.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
intid=0;
for(PackageInfopackageInfo:packageInfos){Stringstr=packageInfo.applicationInfo.loadLabel(getPackageManager()).toString();linearLayout.addView(getChoiceView(linearLayout,str,id));id++;
}
button.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){
newDEleteApk().execute();}
});
}
privateViewgetChoiceView(LinearLayoutroot,finalStringpageName,intid){
finalViewview=LayoutInflater.from(this).inflate(R.layout.choice_layout,root,false);
finalCheckBoxcheckBox=(CheckBox)view.findViewById(R.id.page_id);
finalTextViewtextView=(TextView)view.findViewById(R.id.page_name);
view.setTag(id);
checkBox.setTag(view);
checkBox.setOnCheckedChangeListener(newCompoundButton.OnCheckedChangeListener(){@OverridepublicvoidonCheckedChanged(CompoundButtonbuttonView,booleanisChecked){
if(isChecked){
views.add((View)checkBox.getTag());
pages.add((int)view.getTag());
}else{
Viewview1=(View)checkBox.getTag();
views.remove(view1);
pages.remove(getIndexPages((int)view1.getTag()));
}
}
});
textView.setText(pageName);
returnview;
}
publicintgetIndexPages(intid){
intindex=0;
intj=0;
for(inti:pages){if(i==id){
index=j;
break;}j++;
}
returnindex;
}
classDEleteApkextendsAsyncTask{
@Override
protectedvoidonPreExecute(){progressDialog=n
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 乙肝患者購買合同范本
- 2025年度人工智能與制造業(yè)融合項目合同補充協(xié)議示范文本
- 保羅皮爾斯合同范本
- 出賣公司合同范本
- 買房銀行抵押合同范本
- 2025年度海鮮餐飲連鎖門店食材供應合同
- 兔寶寶合同范本
- 上門做飯創(chuàng)業(yè)計劃書國家層面
- 供氣標準合同范本
- 2024年四川省成都市新都區(qū)中考英語一診試卷(含解析)
- 《樹立正確的“三觀”》班會課件
- ISO15614-1 2017 金屬材料焊接工藝規(guī)程及評定(中文版)
- 醫(yī)療器械物價收費申請流程
- “一帶一路”背景下的西安市文化旅游外宣翻譯研究-基于生態(tài)翻譯學理論
- 2024年江蘇省昆山市六校中考聯(lián)考(一模)化學試題
- 國家電網(wǎng)智能化規(guī)劃總報告
- 妊娠紋培訓課件
- 大雁系統(tǒng)研究報告總結(jié)
- 邢臺市橋西區(qū)2024年事業(yè)單位考試《公共基礎(chǔ)知識》全真模擬試題含解析
- 教師述職教研組長述職報告
評論
0/150
提交評論