如何判斷android的activity是否運行

android對於我們來說是一個複雜的且擁有多種邏輯類別的系統。這對於我們來說是一件好事但是也給我們帶來處理一個相同問題會帶來更多的複雜性。接下來我們會檢查activity是否在你的應用中存在
 

介紹

我們會需要一個持續運行的服務,這個服務會從遠程站點獲取信息或者做類似事情來給我們帶來一些特殊利益。在當時我這個服務獲取到一些信息並傳送到activity中。如果這個activity運行在前端那並沒有什麼問題,然後我們怎麼確定activity運行在前端呢?
這個問題有多重決絕方法,所有的方法都有利有弊。我們將展現所有的處理方法並列出利弊
 

ActivityManager

首先我們關注下ActivityManager(AM)。AM維持了一個運行時任務記錄和最上層任務記錄。也許AM中最後的一個任務就是我們的興趣所在
public boolean isForeground(String PackageName){
  // Get the Activity Manager
  ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
 
  // Get a list of running tasks, we are only interested in the last one,
  // the top most so we give a 1 as parameter so we only get the topmost.
  List< ActivityManager.RunningTaskInfo > task = manager.getRunningTasks(1);
 
  // Get the info we need for comparison.
  ComponentName componentInfo = task.get(0).topActivity;
 
  // Check if it matches our package name.
  if(componentInfo.getPackageName().equals(PackageName)) return true;
     
  // If not then our app is not on the foreground.
  return false;
}
利:你可以直接的得到你需要的信息,但是更準確的說google對於其還有歧義的,google強烈建議你僅在調試模式下使用。
 
利:沒有保存任意類型的變量,只是查看了android的任務棧,所以無論在什麼原因下沒有任何東西會被刪除。
 
弊:獲取最頂層的應用或許不是最完整的解決方案。因爲你的app可能有很多原因造成其不是一個頂端app,但我們依舊會認爲他依然在最頂端並按照此推斷去處理。
 
弊:google文檔明確的指出不要使用這段代碼除了在調試或者管理任務接口時,所以這不是一個可靠的方式並且在未來的android版本也將不可靠
 
弊:你必須在manifest配置中增加GET_TASKS的權限,這或許不是那麼友好吧
 

 

弊:由於我們沒有系統的控制權,所以你將不會知道系統在任何情況下是怎麼處理的,所以你只能假設這一切都運行的非常完好,並且在我們的使用者中這一切在任何情況下都沒有發生。
 

static variable

從代碼層面上,最簡單的方法就是使用靜態變量,靜態變量在現代編碼中被使用的非常多且總是備受爭議,但是我們依舊在很多地方看到並使用。
public class example extends Activity {
    static boolean isActive = false;
     
    @Override
    protected void onStart() {
        super.onStart();
        isActive = true;
    }
     
    @Override
    protected void onStop() {
        super.onStop();
        isActive = false;
    }
}

當activity在屏幕最前端是這樣寫的,如果被其他界面覆蓋了,activity是stop了的,所以也可以寫在onCreate()和onDestory()裏

利:非常簡便的代碼

 
利:很難被用戶或者android自身回收
 
利:你可以有很高的控制權並很容易的按照你的實現將Activity分類,就如同最上層Activity這麼一個分類
 
弊:靜態變量等等其他變量是被關聯到一個類實例的,這就是意味着只有類加載器加載的類被卸載了這些變量纔會被卸載。一般來說只有當應用被殺死後靜態變量纔會一起被殺死。然後android在一般情況下不會銷燬一些老的歷史任務。我們需要注意,如果我們申明一個靜態Activity或者context,且靜態變量存在複雜的引用關係,那麼其不會被銷燬,更可怕的是可能帶來內存泄露問題。所以請確保當你不在需要這些靜態變量時,把他們賦值成null,以讓垃圾回收機制處理。在我們的例子中並不是一個反面例子,我們只是存儲了一個boolean類型的值,這不會帶來內存泄露問題,但是你依然需要清楚靜態變量會帶來什麼,這就是爲什麼網絡上市場出現這類討論的原因。
 
弊:如上的函數並不會一直被調用,所以得不到一個真實的狀態。如果一個app崩潰了,其不會調用onStop()函數。你可以通過定義一個默認的異常處理機制來彌補這個問題,並把狀態設定成false。可能還有更多的情況我們未控制,但也有其他覺得方法。
 
弊:儘管靜態變量在被銷燬後,再次初始化可以被賦予他們的默認值,但這也會在某些情況下帶來不可預料的情況。例如崩潰
 

shared preferences

和靜態變量類似,shared preferences 可以共享其他Activity和service的狀態
public class example extends Activity {
     
    @Override
    protected void onStart() {
        super.onStart();
         
        // Store our shared preference
        SharedPreferences sp = getSharedPreferences("OURINFO", MODE_PRIVATE);
        Editor ed = sp.edit();
        ed.putBoolean("active", true);
        ed.commit();
    }
     
    @Override
    protected void onStop() {
        super.onStop();
         
        // Store our shared preference
        SharedPreferences sp = getSharedPreferences("OURINFO", MODE_PRIVATE);
        Editor ed = sp.edit();
        ed.putBoolean("active", false);
        ed.commit();
         
    }
}

利:shared preferences 不會被android銷燬

 
利:shared preferences 不會被重置成默認值
 
利:你可以有很高的控制權並很容易的按照你的實現將Activity分類,就如同最上層Activity這麼一個分類
 
弊:shared preferences可以被用戶手動清除,這種情況你是無法知道的,這會讓你的系統出問題。
 
弊:如上的函數並不會一直被調用,所以得不到一個真實的狀態。如果一個app崩潰了,其不會調用onStop()函數。你可以通過定義一個默認的異常處理機制來彌補這個問題,並把狀態設定成false。可能還有更多的情況我們未控制,但也有其他覺得方法。
 
 

結論

 
我們更喜歡使用shared preferences。其有最可靠的狀態信息,
可以減少app被銷燬帶來的問題,不需要更多的權限,當我們的Activity在最上層是他給我們更多的決定權,去做一些事情。
 
 

異常處理

 
在上述幾個章節提到的錯誤處理問題,你可以通過創建一個默認的異常處理機制來處理,你可以把這段函數放在onCreate()的最前面


final Thread.UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
 
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread thread, Throwable throwable) {
                // fix our issues for static variables
                isActive = false;  
                 
                // fix our issues for sharedpreferences
                SharedPreferences sp = getSharedPreferences("OURINFO", MODE_PRIVATE);
                Editor ed = sp.edit();
                ed.putBoolean("active", false);
                ed.commit();
                 
                // Handle everthing else
                defaultHandler.uncaughtException(thread, throwable);
            }
        });


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章