這篇文章主要介紹了android監(jiān)聽?wèi)?yīng)用是否被卸載的方法,具有一定借鑒價值,需要的朋友可以參考下。如下資料是關(guān)于android實現(xiàn)監(jiān)聽的詳細(xì)步驟內(nèi)容。
讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價值的長期合作伙伴,公司提供的服務(wù)項目有:域名與空間、網(wǎng)絡(luò)空間、營銷軟件、網(wǎng)站建設(shè)、潮南網(wǎng)站維護(hù)、網(wǎng)站推廣。
一 效果演示
打開應(yīng)用效果圖:
圖1
點擊卸載后提示,如下圖:
圖2
然后退出應(yīng)用,卸載程序,會發(fā)現(xiàn)當(dāng)應(yīng)用被卸載以后,會彈出調(diào)用瀏覽器的提示,這里隨便放了一個搜狐瀏覽頁面,在自己的應(yīng)用中應(yīng)該調(diào)用的一般都是調(diào)查頁面。如下圖:
圖3
ok,效果前面已經(jīng)演示了,現(xiàn)在需要討論一下其具體實現(xiàn)了。
首先,通過adb shell進(jìn)入手機(jī),然后第一次進(jìn)入應(yīng)用,像圖1一樣,不點擊按鈕,通過 ps | busybox grep ubuntu 看這個應(yīng)用的進(jìn)程信息,如下圖:
這個時候只有
u0_a108 2953 124 490956 47792 ffffffff 40052a40 S com.example.ubuntuforandroid
2953 這一個進(jìn)程
點擊 卸載后提示 按鈕再次,執(zhí)行剛才執(zhí)行的ps命令,發(fā)現(xiàn)已經(jīng)有兩個進(jìn)程了如下圖:
其實新產(chǎn)生的進(jìn)程是通過程序調(diào)用jni接口
public static native int Reguninstall(String path,String url);
這個接口fork了一個進(jìn)程,而新fork的進(jìn)程負(fù)責(zé)監(jiān)聽本應(yīng)用是否被卸載了
二 源碼分析
java層的代碼如下,很簡單,就是調(diào)用一下jni接口
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initInjectFunction("testfile"); test = (TextView)this.findViewById(R.id.testview); test.setText("點擊卸載后提示按鈕,你的應(yīng)用在卸載以后會調(diào)用瀏覽器,然后調(diào)用你需要的頁面。"); btn = (Button)this.findViewById(R.id.testbtn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub String directory = MainActivity.this.getFilesDir().getAbsolutePath(); String url = "http://www.sohu.com/"; JniExec.Reguninstall(directory,url); test.setText("現(xiàn)在可以退出應(yīng)用,然后卸載應(yīng)用,看看是否有效果"); } }); }
一目了然,不用多言了
現(xiàn)在就分析
package com.example.ubuntuforandroid; public class JniExec { static { System.loadLibrary("uninstall"); } public static native int Reguninstall(String path,String url); }
Reguninstall 這個jni接口里面做了什么事情,能夠達(dá)到監(jiān)聽本身應(yīng)用卸載的效果。
native代碼分析
jint Java_com_example_ubuntuforandroid_JniExec_Reguninstall(JNIEnv* env, jobject thiz, jstring path, jstring url) { LOGI("Java_com_example_ubuntuforandroid_JniExec_Reguninstall"); char *listenpath = (char*) (*env)->GetStringUTFChars(env,path, 0); char *jumpurl = (char*) (*env)->GetStringUTFChars(env,url, 0); LOGI("notify path is %s",listenpath); LOGI("jumpurl is %s",jumpurl); pid_t pid; pid = fork(); if(pid == 0) { //子進(jìn)程 inotify_main(listenpath,jumpurl); } //父進(jìn)程不阻塞調(diào)用 waitpid ok 子進(jìn)程變成了孤兒進(jìn)程,被init進(jìn)程收養(yǎng)了 pid = waitpid(-1,0,1); LOGI("father bye bye"); return 0; }
這個接口里面最關(guān)鍵的是調(diào)用了 inotify_main 這個函數(shù)。如果看這段代碼比較費(fèi)力的話,建議先弄清楚linux 下的fork機(jī)制,搞清楚 孤兒進(jìn)程 僵尸進(jìn)程這些如何產(chǎn)生的情況。
下面看 inotify_main 這個函數(shù)
void inotify_main(char *path,char *url) { struct pollfd poll_list[2]; poll_list[0].fd = inotify_init(); poll_list[0].events = POLLIN; int wd = inotify_add_watch(poll_list[0].fd, path, IN_DELETE | IN_CREATE); if(wd < 0) { fprintf(stderr, "could not add watch for %s, %s\n", path, strerror(errno)); return ; } int retval; while(1) { retval = poll(poll_list,(unsigned long)1,-1); /* retval 總是大于0或為-1,因為我們在阻塞中工作 */ LOGI("retval = %d\n",retval); if(retval < 0) { fprintf(stderr,"poll錯誤: %s/n",strerror(errno)); return; } if((poll_list[0].revents & POLLIN) == POLLIN) { LOGI("poll_list[0].revents&POLLIN\n"); inotify_handle(poll_list[0].fd,url); } } inotify_rm_watch(poll_list[0].fd,wd); }
這個函數(shù),這里面用到了 inotify_init inotify_add_watch inotify_rm_watch 這幾個linux接口,這幾個接口主要的作用就是監(jiān)聽指定的目錄,其配合poll函數(shù),能夠監(jiān)聽目錄下的任何改動,當(dāng)要監(jiān)聽的目錄有任何改動的時候,會觸發(fā)poll函數(shù)的 POLLIN
有可讀數(shù)據(jù)到來事件。
在本應(yīng)用中,監(jiān)聽的是 /data/data/com.example.ubuntuforandroid/files/ 這個目錄,因為在卸載的時候卸載程序會刪除監(jiān)聽目錄的,而fork出來的守護(hù)進(jìn)程當(dāng)發(fā)現(xiàn)自身應(yīng)用的目錄被卸載程序刪除了也就是卸載了,這個時候調(diào)用 inotify_handle
這個函數(shù),然后調(diào)用 am命令啟動瀏覽器,調(diào)用自己需要調(diào)用界面。
當(dāng)然,在調(diào)用am指令以后,記得自身守護(hù)進(jìn)程的使命也完成了,需要exit退出一下。
inotify接口的用處很多,擴(kuò)展一下,也可以用于守護(hù)進(jìn)程,比如A進(jìn)程和B進(jìn)程是共生共死的,這里有一種實現(xiàn)的方式就是 A進(jìn)程用inotify 監(jiān)聽 /proc/B進(jìn)程id目錄,當(dāng)B進(jìn)程結(jié)束的時候,A進(jìn)程就能知道B進(jìn)程不在了,從而結(jié)束自己。
上文描述的就是android監(jiān)聽?wèi)?yīng)用是否被卸載的方法,具體使用情況還需要大家自己動手實驗使用過才能領(lǐng)會。如果想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!