編輯:關於Android編程
上篇文章中我們分析了Activity的onSaveInstanceState方法執行時機,知道了Activity在一般情況下,若只是執行onPause方法則不會執行onSaveInstanceState方法,而一旦執行了onStop方法就會執行onSaveInstanceState方法,這篇文章中同樣的我們分析一下Actvity(當然不只是Activity,同樣包含Servier,ContentProvider,Application等)的另一個內部方法:onLowMemory。該方法主要用於當前系統可用內存比較低的時候回調使用。
這裡簡單介紹一下Android系統的內存分配機制。Android系統中一個個的App都是一個個不同的應用進程,擁有各自的JVM與運行時,每個App的進程可使用的內存大小都是固定的,當系統中App打開數量過多時,就會使Android系統的可用內存降低,對於當前正在使用的App而言,可能還需要繼續申請系統內存,而我們的剩余系統內存已經不足以被當前App所申請了,這時候系統會自動的清理那些後台進程,進而釋放出可用內存用於前台進程的使用,當然這裡系統清理後台進程的算法不是我們討論的重點。這裡我們只是大概的分析Android系統回調Activity的onLowMemory方法的流程。
通過前面關於Activity的啟動流程分析我們知道ActivityManagerService是整個Android系統的管理中樞,負責Activity,Servier等四大組件的啟動與銷毀等工作,同樣的對於應用進程的管理工作也是在ActivityMaangerServier中完成的,我們知道android系統中有兩個比較重要的進程Zygote進程和SystemServer進程,其中Zygote進程是整個Android系統的根進程,其他所有的進程都是通過Zygote進程fork出來的。而SystemServer進程則用於運行各種服務,為其他的應用進程提供各種功能接口等,在前面我們分析過SystemServer進程的啟動流程,其中在SystemServer的startBootService方法中我們調用了:
// Set up the Application instance for the system process and get started.
mActivityManagerService.setSystemProcess();
方法,看其注釋說明,說的是為System進程初始化Application實例,這裡我們可以看一下該方法的具體實現:
public void setSystemProcess() {
try {
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
ServiceManager.addService("meminfo", new MemBinder(this));
ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
ServiceManager.addService("dbinfo", new DbBinder(this));
if (MONITOR_CPU_USAGE) {
ServiceManager.addService("cpuinfo", new CpuBinder(this));
}
ServiceManager.addService("permission", new PermissionController(this));
ServiceManager.addService("processinfo", new ProcessInfoService(this));
ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
"android", STOCK_PM_FLAGS);
mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
synchronized (this) {
ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
app.persistent = true;
app.pid = MY_PID;
app.maxAdj = ProcessList.SYSTEM_ADJ;
app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.put(app.pid, app);
}
updateLruProcessLocked(app, false, null);
updateOomAdjLocked();
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(
"Unable to find android system package", e);
}
}
這裡簡單介紹一下ServierManager是一個管理服務的服務,而其addServier方法就是注冊各種服務(服務注冊到JNI層,具體的關於是如何注冊到JNI層的這裡暫不做過多的解釋)。可以發現在方法體中我們注冊了名稱為:memInfo的服務MemBinder,MemBinder是一個Binder類型的服務,主要用於檢測系統內存情況,這裡可以看一下其具體的實現邏輯:
static class MemBinder extends Binder {
ActivityManagerService mActivityManagerService;
MemBinder(ActivityManagerService activityManagerService) {
mActivityManagerService = activityManagerService;
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mActivityManagerService.checkCallingPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump meminfo from from pid="
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ " without permission " + android.Manifest.permission.DUMP);
return;
}
mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false, null);
}
}
查看源碼,我們可以發現MemBinder類繼承於Binder類也就是說其實一個Binder類型的服務,並且有一個成員方法dump,該方法主要用於執行shell命令,當系統可用內存比較低的時候就會執行了該方法,然後回調到ActivityManagerService中的killAllBackground方法,下面我們重點看一下killAllBackground方法的具體實現:
@Override
public void killAllBackgroundProcesses() {
...
doLowMemReportIfNeededLocked(null);
...
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
可以看到這個方法體中會執行doLowMemReportIfNeededLocked方法,該方法是做什麼的呢?我們繼續看一下doLowMemReportIfNeededLoced方法的實現:
final void doLowMemReportIfNeededLocked(ProcessRecord dyingProc) {
...
scheduleAppGcsLocked();
...
}
好吧,在這個方法中我們又調用了scheduleAppGcsLocked方法,這樣我們就繼續看一下scheduleAppGcsLocked方法的實現邏輯:
/**
* Schedule the execution of all pending app GCs.
*/
final void scheduleAppGcsLocked() {
mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
if (mProcessesToGc.size() > 0) {
// Schedule a GC for the time to the next process.
ProcessRecord proc = mProcessesToGc.get(0);
Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
long when = proc.lastRequestedGc + GC_MIN_INTERVAL;
long now = SystemClock.uptimeMillis();
if (when < (now+GC_TIMEOUT)) {
when = now + GC_TIMEOUT;
}
mHandler.sendMessageAtTime(msg, when);
}
}
可以發現這裡執行的邏輯就是通過mHandler發送一個msg.what為GC_BACKGROUND_PROCESSES_MSG的異步消息,這樣消息體最終會被mHandler的handleMessage方法所執行,繼續看一下mHandler的handleMessage方法的執行邏輯:
case GC_BACKGROUND_PROCESSES_MSG: {
synchronized (ActivityManagerService.this) {
performAppGcsIfAppropriateLocked();
}
} break;
在mHandler的handleMessage方法中,首先會判斷msg的what是否為GC_BACKGROUND_PROCESSES_MSG,然後會執行performAppGcsIfAppropriateLocked方法,這樣我們繼續看一下performAppGcsIfAppropriateLocked方法的實現:
/**
* If all looks good, perform GCs on all processes waiting for them.
*/
final void performAppGcsIfAppropriateLocked() {
if (canGcNowLocked()) {
performAppGcsLocked();
return;
}
// Still not idle, wait some more.
scheduleAppGcsLocked();
}
可以發現這裡首先判斷是否能夠執行gc操作,若不能繼續執行上面的scheduleAppGcsLocked方法,然後繼續執行發送異步消息的邏輯,直到變量canGcNowLocked為true,並執行performAppGcsLocked方法,然後return掉,這樣我們繼續跟蹤代碼,看一下performAppGcsLocked方法的執行邏輯:
/**
* Perform GCs on all processes that are waiting for it, but only
* if things are idle.
*/
final void performAppGcsLocked() {
final int N = mProcessesToGc.size();
if (N <= 0) {
return;
}
if (canGcNowLocked()) {
while (mProcessesToGc.size() > 0) {
ProcessRecord proc = mProcessesToGc.remove(0);
if (proc.curRawAdj > ProcessList.PERCEPTIBLE_APP_ADJ || proc.reportLowMemory) {
if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
<= SystemClock.uptimeMillis()) {
// To avoid spamming the system, we will GC processes one
// at a time, waiting a few seconds between each.
performAppGcLocked(proc);
scheduleAppGcsLocked();
return;
} else {
// It hasn't been long enough since we last GCed this
// process... put it in the list to wait for its time.
addProcessToGcListLocked(proc);
break;
}
}
}
scheduleAppGcsLocked();
}
}
可以發現該方法經過一系列的邏輯判斷之後會執行performAppGcLocked方法,我們繼續看一下該方法的實現:
/**
* Ask a given process to GC right now.
*/
final void performAppGcLocked(ProcessRecord app) {
try {
app.lastRequestedGc = SystemClock.uptimeMillis();
if (app.thread != null) {
if (app.reportLowMemory) {
app.reportLowMemory = false;
app.thread.scheduleLowMemory();
} else {
app.thread.processInBackground();
}
}
} catch (Exception e) {
// whatever.
}
}
可以發現最終執行的是app.thread.scheduleLowMemory方法,而這裡的app.thread是ActivityThread.ApplicationThread對象,所以這裡最終是通過Binder進程間通訊,執行的是ActivityThread.ApplicationThread的scheduleLowMemory方法,好吧讓我們看一下ActivityThread.ApplicationThread的scheduleLowMemory
方法的實現邏輯…
@Override
public void scheduleLowMemory() {
sendMessage(H.LOW_MEMORY, null);
}
在ActivityThread中的scheduleLowMemory方法中並沒有執行額外邏輯,而是直接調用了sendMessage方法,繼續跟蹤方法的執行:
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
if (DEBUG_MESSAGES) Slog.v(
TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
+ ": " + arg1 + " / " + obj);
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
可以發現在sendMessage方法中最終通過一個Handler類型的mH成員變量發送一個異步消息,這樣異步消息最終會被mH的handleMessage方法執行。。。。,經過查看源代碼我們知道在mH的handleMessage方法中最終調用的是handleLowMemory方法:
final void handleLowMemory() {
ArrayList callbacks = collectComponentCallbacks(true, null);
final int N = callbacks.size();
for (int i=0; i
可以發現這裡通過遍歷ComponentCallbacks2並執行了其onLowMemory方法,那麼這裡的ComponentCallBacks2是什麼呢?這裡我們查看一下collectComponentCallbacks方法的實現邏輯。
ArrayList collectComponentCallbacks(
boolean allActivities, Configuration newConfig) {
ArrayList callbacks
= new ArrayList();
synchronized (mResourcesManager) {
final int NAPP = mAllApplications.size();
for (int i=0; i
可以發現該方法最終返回類型為ArrayList類型的callBacks而我們的callBacks中保存的是我們應用進程中的Activity,Service,Provider已經Application等。咦?Activity,Service,Provider,Application都是ComponentCallBacks2類型的麼?我們看一看一下具體的定義:
Actvity的類定義:
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback
Service的類定義:
public abstract class Service extends ContextWrapper implements ComponentCallbacks2
ContentProvider的類定義:
public abstract class ContentProvider implements ComponentCallbacks2
Application的類定義:
public class Application extends ContextWrapper implements ComponentCallbacks2
可以發現其都是繼承與ComponentCalbacks2,所以其都可以被當做是ComponentCallbacks2類型的變量。而同樣是四大組件的BroadcastReceiver,我們可以下其類定義:
public abstract class BroadcastReceiver
可以看到其並未繼承與ComponentCallbacks2,所以並未執行,所以通過這樣的分析,我們知道了,最終應用程序中的Activity,Servier,ContentProvider,Application的onLowMemory方法會被執行。而由於我們是在系統內存緊張的時候會執行killAllBackground方法進而通過層層條用執行Activity、Service、ContentProvider、Application的onLowMemory方法,所以我們可以在這些組件的onLowMemory方法中執行了一些清理資源的操作,釋放一些內存,盡量保證自身的應用進程不被殺死。
總結:
系統在JNI層會時時檢測內存變量,當內存過低時會通過kiilbackground的方法清理後台進程。
經過層層的調用過程最終會執行Activity、Service、ContentProvider、Application的onLowMemory方法。
可以在組件的onLowMemory方法中執行一些清理資源的操作,釋放內存防止進程被殺死。
最近總是有人來和我說我以前寫的一個小app無法正常獲取數據~Android簡易版天氣預報app 今天就又運行了下來查找問題,發現或許是接口有限制吧,不能在多台手機使用同個
Makefile是什麼?makefile的作用:1、工程文件組織,編譯成復雜的程序2、安裝及卸載我們的程序Makefile使用示例在/home/username/make
Android提供了強大的事件處理機制,主要包括兩大類:1,基於監聽的事件處理機制:主要做法是為Android界面組件綁定特定的事件監聽器2,基於回調的事件處理機制:主要
英文詞典是手機中經常使用的應用。因此,在本文將結合Android來討論如何實現一個Android版的英文詞典。實現英文詞典的方法很多。在本文使用了SQLite數據庫來保存