欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入解析Android系統(tǒng)中應(yīng)用程序前后臺(tái)切換的實(shí)現(xiàn)要點(diǎn)

 更新時(shí)間:2016年04月28日 14:49:05   作者:by2n  
這篇文章主要介紹了Android系統(tǒng)中應(yīng)用程序前后臺(tái)切換的實(shí)現(xiàn)要點(diǎn),除了切換操作的效果之外還重點(diǎn)講解了判斷程序運(yùn)行于前臺(tái)還是后臺(tái)的方法,需要的朋友可以參考下

在介紹程序?qū)崿F(xiàn)之前,我們先看下Android中Activities和Task的基礎(chǔ)知識(shí)。
我們都知道,一個(gè)Activity 可以啟動(dòng)另一個(gè)Activity,即使這個(gè)Activity是定義在別一個(gè)應(yīng)用程序里的,比如說,想要給用戶展示一個(gè)地圖的信息,現(xiàn)在已經(jīng)有一個(gè)Activity可以做這件事情,那么現(xiàn)在你的Activity需要做的就是將請(qǐng)求信息放進(jìn)一個(gè)Intent對(duì)象里,并且將這個(gè)Intent對(duì)象傳遞給startActivity(),那么地圖就可顯示出來了,但用戶按下Back鍵之后,你的Activity又重新出現(xiàn)在屏幕上。

對(duì)用戶來講,顯示地圖的Activity和你的Activity好像在一個(gè)應(yīng)用程序中的,雖然是他們是定義在其他的應(yīng)用程序中并且運(yùn)行在那個(gè)應(yīng)有進(jìn)程中。Android將你的Activity和借用的那個(gè)Activity被放進(jìn)一個(gè)Task中以維持用戶的體驗(yàn)。那么Task是以棧的形式組織起來一組相互關(guān)聯(lián)的Activity,棧中底部的Activity就是開辟這個(gè)Task的,通常是用戶在應(yīng)用程序啟動(dòng)器中選擇的Activity。棧的頂部的Activity是當(dāng)前正在運(yùn)行的Activity--用戶正在交互操作的Activity。

當(dāng)一個(gè)Activity啟動(dòng)另一個(gè)Activity時(shí),新啟動(dòng)的Activity被壓進(jìn)棧中,成為正在運(yùn)行的Activity。舊的Activity仍然在棧中。當(dāng)用戶按下BACK鍵之后,正在運(yùn)行的Activity彈出棧,舊的Activity恢復(fù)成為運(yùn)行的Activity。棧中包含對(duì)象,因此如果一個(gè)任務(wù)中開啟了同一個(gè)Activity子類的的多個(gè)對(duì)象——例如,多個(gè)地圖瀏覽器——?jiǎng)t棧對(duì)每一個(gè)實(shí)例都有一個(gè)單獨(dú)的入口。棧中的Activity不會(huì)被重新排序,只會(huì)被、彈出。Task是一組Activity實(shí)例組成的棧,不是在manifest文件里的某個(gè)類或是元素,所以無法設(shè)定一個(gè)Task的屬性而不管它的Activity,一個(gè)Task的所有屬性值是在底部的Activity里設(shè)置的,這就需要用于Affinity。關(guān)于Affinity這里不再詳述,大家可以查詢文檔。

一個(gè)Task里的所有Activity作為一個(gè)整體運(yùn)轉(zhuǎn)。整個(gè)Task(整個(gè)Activity堆棧)可以被推到前臺(tái)或被推到后臺(tái)。假設(shè)一個(gè)正在運(yùn)行的Task中有四個(gè)Activity——正在運(yùn)行的Activity下面有三個(gè)Activity,這時(shí)用戶按下HOME鍵,回到應(yīng)有程序啟動(dòng)器然后運(yùn)行新的應(yīng)用程序(實(shí)際上是運(yùn)行了一個(gè)新的Task),那么當(dāng)前的Task就退到了后臺(tái),新開啟的應(yīng)用程序的root Activity此時(shí)就顯示出來了,一段時(shí)間后,用戶又回到應(yīng)用程序器,又重新選擇了之前的那個(gè)應(yīng)用程序(先前的那個(gè)Task),那么先前的那個(gè)Task此時(shí)又回到了前臺(tái)了,當(dāng)用戶按下BACK鍵時(shí),屏幕不是顯示剛剛離開的那個(gè)新開啟的那個(gè)應(yīng)用程序的Activity,而是被除回到前臺(tái)的那個(gè)Task的棧頂Activity,將這個(gè)Task的下一個(gè)Activity顯示出來。 上述便是Activity和Task一般的行為,但是這個(gè)行為的幾乎所有方面都是可以修改的。Activity和Task的關(guān)系,以及Task中Activity的行為,是受啟動(dòng)該Activity的Intent對(duì)象的標(biāo)識(shí)和在manifest文件中的Activity的<Activity>元素的屬性共同影響的。

以上是關(guān)于Activity和Task的描述。

在開發(fā)Android項(xiàng)目時(shí),用戶難免會(huì)進(jìn)行程序切換,在切換過程中,程序?qū)⑦M(jìn)入后臺(tái)運(yùn)行,需要用時(shí)再通過任務(wù)管理器或是重新點(diǎn)擊程序或是通過點(diǎn)擊信息通知欄中的圖標(biāo)返回原來的界面。這種效果類似于騰訊QQ的效果,打開QQ后顯示主界面,在使用其他的程序時(shí),QQ將以圖標(biāo)的形式顯示在信息通知欄里,如果再用到QQ時(shí)再點(diǎn)擊信息通知欄中的圖標(biāo)顯示QQ主界面。
先看下本示例實(shí)現(xiàn)效果圖:

2016428144551137.jpg (416×686)

2016428144627452.jpg (419×693)

在上圖第二個(gè)圖中,我們點(diǎn)擊時(shí)將會(huì)返回到的原來的Activity中。

當(dāng)我們的程序進(jìn)入后臺(tái)運(yùn)作時(shí),在我們的模擬器頂部將以圖標(biāo)形式出現(xiàn),如下圖:

2016428144647679.jpg (416×164)

對(duì)于這種效果一般的做法是在Activity中的onStop()方法中編寫相應(yīng)代碼,因?yàn)楫?dāng)Activity進(jìn)入后臺(tái)時(shí)將會(huì)調(diào)用onStop()方法,我們可以在onStop()方法以Notification形式顯示程序圖標(biāo)及信息,其中代碼如下所示:

@Override 
  protected void onStop() { 
  // TODO Auto-generated method stub 
    super.onStop(); 
    Log.v("BACKGROUND", "程序進(jìn)入后臺(tái)"); 
    showNotification(); 
  } 

以上的showNotification()方法就是Notification。
然后點(diǎn)擊信息通知欄的Notification后再返回到原來的Activity。
當(dāng)然,我們也可以捕捉HOME鍵,在用戶按下HOME鍵時(shí)顯示Notification, 以下是代碼示例:

// 點(diǎn)擊HOME鍵時(shí)程序進(jìn)入后臺(tái)運(yùn)行 
 
  @Override 
 
  public boolean onKeyDown(int keyCode, KeyEvent event) { 
 
    // TODO Auto-generated method stub 
 
    // 按下HOME鍵 
 
    if(keyCode == KeyEvent.KEYCODE_HOME){ 
 
      // 顯示Notification 
 
      notification = new NotificationExtend(this); 
 
      notification.showNotification(); 
 
      moveTaskToBack(true);         

      return true; 
 
    } 
 
    return super.onKeyDown(keyCode, event); 
 
  } 

這里的NotificationExtend是對(duì)顯示Notification的一個(gè)封裝,類中的代碼如下:

package com.test.background; 

import android.app.Activity; 
 
import android.app.Notification; 
 
import android.app.NotificationManager; 
 
import android.app.PendingIntent; 
 
import android.content.Intent; 
 
import android.graphics.Color; 

/** 
 * Notification擴(kuò)展類 
 * @Description: Notification擴(kuò)展類 
 * @File: NotificationExtend.java 
 * @Package com.test.background 
 */ 
 
public class NotificationExtend { 
 
  private Activity context; 

  public NotificationExtend(Activity context) { 
 
    // TODO Auto-generated constructor stub 
 
    this.context = context; 
 
  } 
 
  // 顯示Notification 
 
  public void showNotification() { 
 
    // 創(chuàng)建一個(gè)NotificationManager的引用 
 
    NotificationManager notificationManager = ( 
 
        NotificationManager)context.getSystemService( 
 
            android.content.Context.NOTIFICATION_SERVICE); 
 
    // 定義Notification的各種屬性 
 
    Notification notification = new Notification( 
 
        R.drawable.icon,"閱讀器",  
 
        System.currentTimeMillis()); 
 
    // 將此通知放到通知欄的"Ongoing"即"正在運(yùn)行"組中 
 
    notification.flags |= Notification.FLAG_ONGOING_EVENT; 
 
    // 表明在點(diǎn)擊了通知欄中的"清除通知"后,此通知自動(dòng)清除。 
 
    notification.flags |= Notification.FLAG_AUTO_CANCEL 
 
    notification.flags |= Notification.FLAG_SHOW_LIGHTS; 
 
    notification.defaults = Notification.DEFAULT_LIGHTS; 
 
    notification.ledARGB = Color.BLUE; 
 
    notification.ledOnMS = 5000; 

    // 設(shè)置通知的事件消息 
 
    CharSequence contentTitle = "閱讀器顯示信息"; // 通知欄標(biāo)題 
 
    CharSequence contentText = "推送信息顯示,請(qǐng)查看……"; // 通知欄內(nèi)容 

    Intent notificationIntent = new Intent(context,context.getClass()); 
 
    notificationIntent.setAction(Intent.ACTION_MAIN); 
    notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER); 
    PendingIntent contentIntent = PendingIntent.getActivity( 
    context, 0, notificationIntent,PendingIntent.FLAG_UPDATE_CURRENT); 
    notification.setLatestEventInfo( 
    context, contentTitle, contentText, contentIntent); 
    // 把Notification傳遞給NotificationManager 
    notificationManager.notify(0, notification); 
 
  } 

  // 取消通知 
 
  public void cancelNotification(){ 
 
    NotificationManager notificationManager = ( 
 
        NotificationManager) context.getSystemService( 
 
            android.content.Context.NOTIFICATION_SERVICE); 
 
    notificationManager.cancel(0); 
 
  } 
 
} 

這里需要在配置文件中設(shè)置每個(gè)Activity以單任務(wù)運(yùn)行,否則,每次返回原Activity時(shí)會(huì)新增加一個(gè)Activity,而不會(huì)返回到原Activity。

在使用FLAG_ACTIVITY_NEW_TASK控制標(biāo)識(shí)時(shí)也會(huì)出現(xiàn)不會(huì)返回到原Activity的現(xiàn)象。如果該標(biāo)識(shí)使一個(gè)Activity開始了一個(gè)新的Task,然后當(dāng)用戶按了HOME鍵離開這個(gè)Activity,在用戶按下BACK鍵時(shí)將無法再返回到原Activity。一些應(yīng)用(例如Notification)總是在一個(gè)新的Task里打開Activity,而從來不在自己的Task中打開,所以它們總是將包含F(xiàn)LAG_ACTIVITY_NEW_TASK的Intent傳遞給startActivity()。所以如果有一個(gè)可以被其他的東西以這個(gè)控制標(biāo)志調(diào)用的Activity,請(qǐng)注意讓應(yīng)用程序有獨(dú)立的回到原Activity的方法。 代碼如下:

<activity android:name="ShowMessageActivity" 
       android:launchMode="singleTask"></activity>  

Android應(yīng)用前后臺(tái)切換的判斷
Android中沒有提供一個(gè)應(yīng)用前后臺(tái)切換的回調(diào)或廣播,這個(gè)功能只能我們自己來處理。以前遇到這個(gè)問題的處理方式是,實(shí)現(xiàn)一個(gè)BaseActivity,然后讓其他所有Activity都繼承自它,然后在生命周期函數(shù)中做相應(yīng)的檢測(cè)。具體檢測(cè)方法如下:
       在Activity的onStart和onStop方法中進(jìn)行計(jì)數(shù),計(jì)數(shù)變量為count,在onStart中將變量加1,onStop中減1,假設(shè)應(yīng)用有兩個(gè)Activity,分別為A和B。
       情況一、首先啟動(dòng)A,A再啟動(dòng)B:?jiǎn)?dòng)A,count=1,A啟動(dòng)B,生命周期的順序?yàn)锽.onStart->A.onStop,count的計(jì)數(shù)仍然為1。
       情況二、首先啟動(dòng)A,然后按Home鍵返回桌面:?jiǎn)?dòng)A,count=1,按Home鍵返回桌面,會(huì)執(zhí)行A.onStop,count的計(jì)數(shù)變位0。
       從上面的兩種情況看出,可以通過對(duì)count計(jì)數(shù)為0,來判斷應(yīng)用被從前臺(tái)切到了后臺(tái)。同樣的,從后臺(tái)切到前臺(tái)也是類似的道理。具體實(shí)現(xiàn)看后面的代碼。
       但是如果項(xiàng)目中不是所有的Activity都繼承自同一個(gè)BaseActivity,就無法實(shí)現(xiàn)這個(gè)功能了。幸運(yùn)的是,Android在API 14之后,在Application類中,提供了一個(gè)應(yīng)用生命周期回調(diào)的注冊(cè)方法,用來對(duì)應(yīng)用的生命周期進(jìn)行集中管理,這個(gè)接口叫registerActivityLifecycleCallbacks,可以通過它注冊(cè)自己的ActivityLifeCycleCallback,每一個(gè)Activity的生命周期都會(huì)回調(diào)到這里的對(duì)應(yīng)方法。其實(shí)這個(gè)注冊(cè)方法的本質(zhì)和我們實(shí)現(xiàn)BaseActivity是一樣的,只是將生命周期管理移到了Activity本身的實(shí)現(xiàn)中。
 具體使用方法如下:

public class MyApplication extends Application{ 
  public int count = 0; 
  @Override 
  public void onCreate() { 
    super.onCreate(); 
 
    registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { 
 
      @Override 
      public void onActivityStopped(Activity activity) { 
        Log.v("viclee", activity + "onActivityStopped"); 
        count--; 
        if (count == 0) { 
          Log.v("viclee", ">>>>>>>>>>>>>>>>>>>切到后臺(tái) lifecycle"); 
        } 
      } 
 
      @Override 
      public void onActivityStarted(Activity activity) { 
        Log.v("viclee", activity + "onActivityStarted"); 
        if (count == 0) { 
          Log.v("viclee", ">>>>>>>>>>>>>>>>>>>切到前臺(tái) lifecycle"); 
        } 
        count++; 
      } 
 
      @Override 
      public void onActivitySaveInstanceState(Activity activity, Bundle outState) { 
        Log.v("viclee", activity + "onActivitySaveInstanceState"); 
      } 
 
      @Override 
      public void onActivityResumed(Activity activity) { 
        Log.v("viclee", activity + "onActivityResumed"); 
      } 
 
      @Override 
      public void onActivityPaused(Activity activity) { 
        Log.v("viclee", activity + "onActivityPaused"); 
      } 
 
      @Override 
      public void onActivityDestroyed(Activity activity) { 
        Log.v("viclee", activity + "onActivityDestroyed"); 
      } 
 
      @Override 
      public void onActivityCreated(Activity activity, Bundle savedInstanceState) { 
        Log.v("viclee", activity + "onActivityCreated"); 
      } 
    }); 
  } 
} 

除此之外,有沒有其他方法可以實(shí)現(xiàn)這個(gè)功能呢?
當(dāng)應(yīng)用切到后臺(tái)的時(shí)候,運(yùn)行在前臺(tái)的進(jìn)程由我們的app變成了桌面app,依據(jù)這一點(diǎn),我們可以實(shí)現(xiàn)檢測(cè)應(yīng)用前后臺(tái)切換的功能。在Activity的onStop生命周期中執(zhí)行檢測(cè)代碼,如果發(fā)現(xiàn)當(dāng)前運(yùn)行在前臺(tái)的進(jìn)程不是我們自己的進(jìn)程,說明應(yīng)用切到了后臺(tái)。
想想為什么要在onStop中檢測(cè),而不是onPause?這是由于A啟動(dòng)B時(shí),生命周期的執(zhí)行順序如下:A.onPause->B.onCreate->B.onStart->B.onResume->A.onStop,也就是說,在A的onPause方法中,B的生命周期還沒有執(zhí)行,進(jìn)程沒有進(jìn)入前臺(tái),當(dāng)然是檢測(cè)不到的。我們把代碼移到onPause生命周期中,發(fā)現(xiàn)確實(shí)沒有效果。
具體實(shí)現(xiàn)代碼如下:

//用來控制應(yīng)用前后臺(tái)切換的邏輯 
 private boolean isCurrentRunningForeground = true; 
 @Override 
 protected void onStart() { 
   super.onStart(); 
   if (!isCurrentRunningForeground) { 
     Log.d(TAG, ">>>>>>>>>>>>>>>>>>>切到前臺(tái) activity process"); 
   } 
 } 
 
 @Override 
 protected void onStop() { 
   super.onStop(); 
   isCurrentRunningForeground = isRunningForeground(); 
   if (!isCurrentRunningForeground) { 
     Log.d(TAG,">>>>>>>>>>>>>>>>>>>切到后臺(tái) activity process"); 
   } 
 } 
 
 public boolean isRunningForeground() { 
   ActivityManager activityManager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE); 
   List<ActivityManager.RunningAppProcessInfo> appProcessInfos = activityManager.getRunningAppProcesses(); 
   // 枚舉進(jìn)程 
   for (ActivityManager.RunningAppProcessInfo appProcessInfo : appProcessInfos) { 
     if (appProcessInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { 
       if (appProcessInfo.processName.equals(this.getApplicationInfo().processName)) { 
         Log.d(TAG,"EntryActivity isRunningForeGround"); 
         return true; 
       } 
     } 
   } 
   Log.d(TAG, "EntryActivity isRunningBackGround"); 
   return false; 
 } 

相關(guān)文章

最新評(píng)論