最近在做一個Android的項目,其包含一個消息推送的后臺服務。由于該服務可能會有重要的信息推送,因此并不希望當APP程序退出、APP程序被一鍵清理、APP被強制停止等用戶操作發(fā)生時,這個后臺服務也隨之被殺死。這個問題也就是所謂的“內(nèi)存永駐”。關(guān)于這個問題,網(wǎng)上有很多說法,如調(diào)用startforehand函數(shù)以提高service的優(yōu)先級、在service中創(chuàng)建一個不能被刪掉的notification(或者產(chǎn)生一個其他的與用戶界面交互的UI控件)、在service的onDestroy函數(shù)中重啟這個服務、修改onstartcommand函數(shù)的返回值等等。這些方法,筆者都一一試過,但都沒有效果。但是,我們可以看到市面上也確實存在一些App在一定的時間后可以自動重啟,說明仍然是存在方法可以完成這項任務的。筆者在網(wǎng)上看到了這篇文章 http:///a/jingxuanboke/2014/0622/354671.html,覺得還是有些道理的。于是照著這個原理去做了。 這篇文章中介紹的方法涉及到Android的JNI編程,主要思想就是通過調(diào)用native函數(shù)創(chuàng)建一個子進程。父子進程相互監(jiān)聽,若子進程死去,父進程妥善處理后重新創(chuàng)建新的子進程;若父進程死去,子進程使用AM命令重啟父進程。這種思想唯一的缺陷就是如何保證父子進程不被同時殺死的情況。子進程能不能被殺死,只能用實驗來證明。 首先筆者按照文章介紹的,整理了代碼,并將相關(guān)代碼植入到自己的項目中。 步驟1)編寫Watcher類。它為上面的Java程序調(diào)用提供必要的接口,聲明需要native語言實現(xiàn)的的具體函數(shù)。native語言主要是指C/C++語言。上層的Java程序只需要創(chuàng)建一個Watcher類并調(diào)用它的createAppMonitor(String userId)函數(shù)即可。
2)編譯上面的文件會在bin/classes 目錄下生成相對應的Watcher.class文件,通過DOs界面進入該bin/classes 目錄下,通過javah命令生成C/C++對應的頭文件。 “javah 包名+類名” 得到以下頭文件:
3)創(chuàng)建JNI文件夾,將得到的頭文件移到該文件夾下,繼續(xù)在該文件夾下創(chuàng)建與上面得到的頭文件同名的C/C++文件,然后實現(xiàn)頭文件中提到的方法。(具體實現(xiàn)太多,這里就不再貼出來了) 4)添加Android.mk文件。這個文件的格式基本是統(tǒng)一的。只需要修改LOCAL_MODULE和LOCAL_SRC_FILES兩處即可。如果你還有添加Log打印函數(shù),還要在這里添加 “LOCAL_LDLIBS := -lm -llog”。 下面一張圖來說明整體的文件結(jié)構(gòu)分布: ![]() 其中com_example_dameonservice_Watcher.c和com_example_dameonservice_Watcher.cpp內(nèi)容相同。process.cpp定義一些輔助類。 實驗結(jié)果: 這當然是大家最關(guān)心的。測試的手機選用的小米,感覺 小米在這一塊的優(yōu)化還是很不錯的,所以用它來試試。最終的測試結(jié)果是:被殺死的服務概率性地可以重啟成功,且失敗的概率更大。通過Log分析,不能重啟的時候是因為子進程也死掉了。截止到筆者寫下這篇文章,還沒有抓住其中的規(guī)律。一鍵清理和子進程的被殺死沒有絕對的對應關(guān)系。而且即使是在App運行的時候,也會發(fā)現(xiàn)子進程會被殺死,然后又被父進程重啟。子進程被殺死是重啟失敗的主要原因。但現(xiàn)在的現(xiàn)象無法確定子進程被殺死的確切原因,有一種可能是被系統(tǒng)殺死了,但這樣的不確定性太大,對效果也不能有很好的保證。 雖然沒有完美解決問題,但至少比前面的辦法強很多,至少它也重啟成功過。這個方法感覺繼續(xù)優(yōu)化一下還是可以做好的。 |
|