判斷Android程序前後臺切換的幾種方法

Android在前後臺切換時,我們可能需要做一些處理:發送

通知欄消息,提示APP在後臺運行;或者我們需要暫停程序裏的

某些線程,或者讓線程池的執行時間降低,以保證較高的內存,

而避免被回收。那麼我們有幾種方式可以來判斷呢?

思路1:在一個service裏,使用一個線程,通過
ActivityManager.RunningAppProcessInfo輪詢檢測。

public class AppService extends Service implements Runnable{

    public static boolean isOnBackground = true;
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();

        new Thread(this).start();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // TODO Auto-generated method stub
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void run() {
        while(true){
            boolean isOnBackgroundNew = DeviceUtils.isRunningOnBackground(this);
            Log.d("appstatus", "app is on background ? " + (isOnBackgroundNew ?"yes":"no"));

            if(isOnBackgroundNew != isOnBackground){
                //檢測到前後臺狀態不一致,做一些處理
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    public static boolean isRunningOnBackground(Context context){

        ActivityManager acm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        if(acm != null){
            List<RunningAppProcessInfo> runApps = acm.getRunningAppProcesses();
            if(runApps != null && !runApps.isEmpty()){
                for(RunningAppProcessInfo app : runApps){
                    if(app.processName.equals(context.getPackageName())){
                        if(app.importance == RunningAppProcessInfo.IMPORTANCE_BACKGROUND){
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }
}

缺點:需要創建service,以及線程,暫用大量CPU時間;切換至後臺運行時會有延遲。


思路2:實現一個BaseActivity,然後讓我們應用程序的Activity都繼承自BaseActivity,子類繼承BaseActivity非私屬性和方法,通過BaseActivity的onStart()和onStop()方法中進行判斷應用程序是否進入到後臺並且是否從後臺返回到了前臺。這裏我曾經遇到一個坑,先來看看我的第一個版本實現吧。

public class BaseActivity extends Activity {

    public static boolean isBackground; //全局變量

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_base);
    }

    @Override
    protected void onStart() {
        if (isBackground) {
            //app 從後臺喚醒,進入前臺
            isBackground = false;
            Log.i("ACTIVITY", "程序從後臺喚醒");
        }
        super.onStart();
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    protected void onStop() {
        if (isAppOnForeground()) {
            //app 進入後臺
            isBackground = true;//記錄當前已經進入後臺
            Log.i("ACTIVITY", "程序進入後臺");
        }
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    /**
     * APP是否處於前臺喚醒狀態
     *
     * @return
     */
    public boolean isAppOnForeground() {
        ActivityManager activityManager = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
        String packageName = getApplicationContext().getPackageName();
        List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager
                .getRunningAppProcesses();
        if (appProcesses == null)
            return false;

        for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
            // The name of the process that this object is associated with.
            if (appProcess.processName.equals(packageName)
                    && appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                return true;
            }
        }

        return false;
    }
}

isAppOnForeground()在不同的Android系統上返回值不同。我的想法是美好的,可是實際卻是一個坑。當我點擊home時,onStop也被調用了,可以isAppOnForeground()卻返回false,系統還沒更新狀態嗎?這可能要去深究源代碼才清楚了。後來,就有了以下改進版。

public class BaseActivity extends Activity {

    public static int activityActive; //全局變量,表示當前在前臺的activity數量
    public static boolean isBackground ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_base);
    }

    @Override
    protected void onStart() {
        //app 從後臺喚醒,進入前臺
        activityActive++;
        isBackground = false;
        Log.i("ACTIVITY", "程序從後臺喚醒");

        super.onStart();
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    protected void onStop() {
        activityActive--;
        if (activityActive == 0) {
            //app 進入後臺
            isBackground = true;//記錄當前已經進入後臺
            Log.i("ACTIVITY", "程序進入後臺");
        }
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

這個方法是不是很簡單 ! ^_^

思路3:其實跟第二種改進版是一樣的,只不過放在Application中實現了,感覺還是第二種方法簡單哈。

public class TheApplication extends Application {

    private int mFinalCount;

    @Override
    public void onCreate() {
        super.onCreate();
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {

            }

            @Override
            public void onActivityStarted(Activity activity) {
                mFinalCount++;
                //如果mFinalCount ==1,說明是從後臺到前臺
                Log.e("onActivityStarted", mFinalCount +"");
                if (mFinalCount == 1){
                    //說明從後臺回到了前臺
                }
            }

            @Override
            public void onActivityResumed(Activity activity) {

            }

            @Override
            public void onActivityPaused(Activity activity) {

            }

            @Override
            public void onActivityStopped(Activity activity) {
                mFinalCount--;
                //如果mFinalCount ==0,說明是前臺到後臺
                Log.i("onActivityStopped", mFinalCount +"");
                if (mFinalCount == 0){
                    //說明從前臺回到了後臺
                }
            }

            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

            }

            @Override
            public void onActivityDestroyed(Activity activity) {

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