Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 探究startActivityForResult在singleTop和singleTask啟動模式討論

探究startActivityForResult在singleTop和singleTask啟動模式討論

編輯:關於Android編程

最近在研究AMS代碼遇到一個問題,在函數startActivityUncheckedLocked中

    Slog.d("DDY", "!!!!!!!!!!!!!!!!!!!" );
        if (r.packageName != null) {
            // If the activity being launched is the same as the one currently
            // at the top, then we need to check if it should only be launched
            // once.
            Slog.d("DDY", "=====11" );
            ActivityStack topStack = getFocusedStack();
            ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
            if (top != null && r.resultTo == null) {
                Slog.d("DDY", "========------ " );
                if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
                    if (top.app != null && top.app.thread != null) {
                        if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top,
                                    top.task);
                            /// M: AMS log enhancement @{
                            if(!ActivityManagerService.IS_USER_BUILD)
                               Slog.d(TAG, "ACT-AM_NEW_INTENT " + top + top.task);
                            /// @}
                            // For paranoia, make sure we have correctly
                            // resumed the top activity.
                            topStack.mLastPausedActivity = null;
                            if (doResume) {
                                resumeTopActivitiesLocked();
                            }
                            ActivityOptions.abort(options);
                            if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
                                // We don't need to start a new activity, and
                                // the client said not to do anything if that
                                // is the case, so this is it!
                                if (r.task == null)  Slog.v(TAG,
                                    "startActivityUncheckedLocked: task left null",
                                    new RuntimeException("here").fillInStackTrace());
                                return ActivityManager.START_RETURN_INTENT_TO_CALLER;
                            }
                            top.deliverNewIntentLocked(callingUid, r.intent);
                            if (r.task == null)  Slog.v(TAG,
                                "startActivityUncheckedLocked: task left null",
                                new RuntimeException("here").fillInStackTrace());
                            return ActivityManager.START_DELIVERED_TO_TOP;
                        }
                    }
                }
            }

        } else {
        Slog.d("DDY", "+++++++++----- " );
            if (r.resultTo != null) {
                r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho,
                        r.requestCode, Activity.RESULT_CANCELED, null);
            }
            ActivityOptions.abort(options);
            if (r.task == null)  Slog.v(TAG,
                "startActivityUncheckedLocked: task left null",
                new RuntimeException("here").fillInStackTrace());
            return ActivityManager.START_CLASS_NOT_FOUND;
        }
        Slog.d("DDY", "=====22" );

ActivityStack topStack = getFocusedStack();
ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
這兩句的意思是獲取當前正在顯示的棧頂的Activity,
這裡寫圖片描述
例如OtherActivity在棧頂。當前獲取的就是OtherActivity,也就是顯示在當前手機界面的Activity。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;"> if (top != null && r.resultTo == null) { Slog.d("DDY", "========------ " ); if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {

top代表當前正在顯示的Activity, r.resultTo :假如A Activity 通過startActivityForResult啟動B Activity,那麼r.resultTo就是接收返回結果的A Activity。
if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) 意思當前正在顯示的Activity正是我們正要啟動的Activity,

 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
                            ..........
                             top.deliverNewIntentLocked(callingUid, r.intent);
                             這裡判斷當前的啟動模式 為FLAG_ACTIVITY_SINGLE_TOP LAUNCH_SINGLE_TOP 就是 singleTop模式,
                             LAUNCH_SINGLE_TASK 就是 singleTask 模式。
                             如果啟動模式為上面任何一種的話就會啟動deliverNewIntentLocked函數,這個函數主要作用就是調用Activity的onNewIntent函數。就是我們常說的app中的單實例Activity。只存在一個Activity,當我們在啟動這個Activity只是重載,並不啟動新的

singleTop:
當某Task中有A、B、C、D4個Activity時,如果D想再啟動一個D類型的Activity,那麼Task將是什麼樣子呢?在singleTop模式下,Task中仍然是A、B、C、D,只不過D的onNewIntent函數將被調用以處理這個新Intent,而在standard模式下,則Task將變成A、B、C、D、D,最後的D為新創建的D類型Activity對象。在singleTop這種模式下,只有目標Acitivity當前正好在棧頂時才有效,例如只有處於棧頂的D啟動時才有用,如果D啟動不處於棧頂的A、B、C等,則無效。
上面是有關singleTop簡單的介紹,大家有沒有想過一個問題。網上有人說startActivityForResult 可以使用singleTop 模式。這句話說得沒錯。這是有一定條件的那就是A Activity啟動 B Activity 可以使用。在B Activity 啟動 自己的時候就不可以使用。那B啟動自己 會有什麼效果呢??

package com.example.systemupdate;

import java.io.File;
import java.io.IOException;
import android.content.Intent; 
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.RecoverySystem;
import android.os.storage.StorageVolume;
import com.android.internal.os.storage.ExternalStorageFormatter;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import android.view.View;
import android.view.View.OnClickListener;


public class MainActivity extends Activity {

    private TextView txt;
    private Button Btn;
    private Button Btn2;
    private ProgressDialog pd;
    private boolean pptv = false;
    private Context context;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setTitle("我是MainActivity");  
        Btn = (Button)findViewById(R.id.btn);
        Btn2 = (Button)findViewById(R.id.btn2);
        Btn2.setOnClickListener(new OnClickListener() 
        {
            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub

                    startActivity(new Intent(MainActivity.this,OtherActivity.class));  

            }  
        });       
    }

}

這是主 Activity ,我們在主Activity (MainActivity ) 啟動 OtherActivity ,
OtherActivity 模式為singleTop 模式



    
    
    
    
    
    
    
    

    
        
            
                
                
            
        
          
    

OtherActivity 代碼:

package com.example.systemupdate;

import java.io.File;
import java.io.IOException;
import android.content.Intent; 
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.RecoverySystem;
import android.os.storage.StorageVolume;
import com.android.internal.os.storage.ExternalStorageFormatter;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import android.view.View;
import android.view.View.OnClickListener;


public class OtherActivity  extends Activity {
    public static int n =0;
    private TextView txt;
    private Button Btn;
    private Button Btn2;
    private ProgressDialog pd;
    private boolean pptv = false;
    private Context context;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        n = n+ 1;
        setTitle("我是OtherActivity" + n);  
        Btn = (Button)findViewById(R.id.btn);
        Btn2 = (Button)findViewById(R.id.btn2);
        Btn2.setOnClickListener(new OnClickListener() 
        {
            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub

                    startActivity(new Intent(OtherActivity.this,OtherActivity.class));  

            }  
        });       
    }
    protected void onNewIntent(Intent intent) {  
        // TODO Auto-generated method stub  
        super.onNewIntent(intent);  
        Log.d("DDY", "OnNewIntent");  
    } 
}

再此情況下點擊 MainActivity的Btn2 啟動OtherActivity是可以正常啟動的此時顯示 “我是OtherActivity1”。OtherActivity的Btn2 啟動自己也是可以正常啟動。此時 會發現 界面仍是OtherActivity1,顯示我是“OtherActivity1”你不斷點擊OtherActivity1的Btn2 。界面仍是顯示我是“OtherActivity1”
此時打印日志會顯示
Log.d(“DDY”, “OnNewIntent”); 這句話被打印出來了。說明OtherActivity此時的啟動並不是新建OtherActivity,只是重載原來的OtherActivity。

D/DDY     ( 5791): !!!!!!!!!!!!!!!!!!!
D/DDY     ( 5791): =====11
D/DDY     ( 5791): ========------
D/DDY     ( 6515): OnNewIntent

說明 函數 top.deliverNewIntentLocked(callingUid, r.intent)被調用了,由於此函數主要作用就是調用 onNewIntent 函數。所以 界面一直重載並不會新建OtherActivity。
現在考慮使用startActivityForResult 情況:

package com.example.systemupdate;

import java.io.File;
import java.io.IOException;
import android.content.Intent; 
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.RecoverySystem;
import android.os.storage.StorageVolume;
import com.android.internal.os.storage.ExternalStorageFormatter;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import android.view.View;
import android.view.View.OnClickListener;


public class MainActivity extends Activity {
    final public int CODE= 0x717;
    public static int n =1;
    private TextView txt;
    private Button Btn;
    private Button Btn2;
    private ProgressDialog pd;
    private boolean pptv = false;
    private Context context;
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(requestCode==CODE && resultCode==CODE){
            Log.e("DDY", "======================:");
        }
    }
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setTitle("我是MainActivity");  
        Btn = (Button)findViewById(R.id.btn);
        Btn2 = (Button)findViewById(R.id.btn2);
        Btn2.setOnClickListener(new OnClickListener() 
        {
            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub

                    startActivityForResult(new Intent(MainActivity.this,OtherActivity.class),CODE);  

            }  
        });       
    }

}
package com.example.systemupdate;

import java.io.File;
import java.io.IOException;
import android.content.Intent; 
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.RecoverySystem;
import android.os.storage.StorageVolume;
import com.android.internal.os.storage.ExternalStorageFormatter;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import android.view.View;
import android.view.View.OnClickListener;


public class OtherActivity  extends Activity {
    final public int CODE= 0x717;
    public static int n =1;
    private TextView txt;
    private Button Btn;
    private Button Btn2;
    private ProgressDialog pd;
    private boolean pptv = false;
    private Context context;

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(requestCode==CODE && resultCode==CODE){
            Log.e("DDY", "======================:");
        }
    }
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        n = n+ 1;
        setTitle("我是OtherActivity" + n );  
        Btn = (Button)findViewById(R.id.btn);
        Btn2 = (Button)findViewById(R.id.btn2);
        Btn2.setOnClickListener(new OnClickListener() 
        {
            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub

                    startActivityForResult(new Intent(OtherActivity.this,OtherActivity.class),CODE);  

            }  
        });       
    }
    protected void onNewIntent(Intent intent) {  
        // TODO Auto-generated method stub  
        super.onNewIntent(intent);  
        Log.d("DDY", "OnNewIntent");  
    } 
}

在這種情況下MainActivity的Btn2 啟動OtherActivity是可以正常啟動的此時顯示 “我是OtherActivity1”。
點擊返回鍵可以正常返回到MainActivity ,可以正常打印出

        Log.e("DDY", "======================:");
D/DDY     ( 5791): !!!!!!!!!!!!!!!!!!!
D/DDY     ( 5791): =====11
D/DDY     ( 5791): =====22
E/DDY     ( 7156): ======================:

startActivityForResult 在 MainActivity 啟動OtherActivity 是起作用的。

如果OtherActivity 啟動自己,不斷點擊Btn2 ,發現 OtherActivity 不斷新建 OtherActivity ,並不會重載此時OtherActivity 顯示隨著點擊 不斷變化 “我是OtherActivity1” “我是OtherActivity2” “我是OtherActivity3” …….. 等等。
按返回鍵也可以 返回OtherActivity3 -> OtherActivity2 -> OtherActivity1 .說明此時的 singleTop 在 startActivityForResult 模式下面並沒有起作用。這個不起作用有條件的就是:
此時OtherActivity 正在棧頂且為singleTop 模式。並且用startActivityForResult 啟動 自己。此時的singleTop 不起作用。被當做standard 模式。會不斷新建OtherActivity 。
之所以在startActivityForResult 啟動singleTop 不起作用,在源碼中一句話決定了。

  ActivityStack topStack = getFocusedStack();
            ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
            if (top != null && r.resultTo == null) {
                Slog.d("DDY", "========------ " );
                if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
                    if (top.app != null && top.app.thread != null) {
                        if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
                            ......
                             top.deliverNewIntentLocked(callingUid, r.intent);

上面一句話 if (top != null && r.resultTo == null) {
r.resultTo == null 表示啟動沒有返回結果。當我們的OtherActivity 用startActivity 或者startActivityForResult啟動自己,調用到底層時候都會調用到這裡。其中startActivity 啟動的時候r.resultTo == null 表示不需要返回結果,startActivityForResult啟動時候r.resultTo != null 表示要有返回結果。
startActivity 的 r.resultTo == null 成立。所以會繼續往下執行。調用
top.deliverNewIntentLocked(callingUid, r.intent)函數 ,進而使用 onNewIntent 重載OtherActivity ,而startActivityForResult 的r.resultTo != null 函數成立,會跳過這段函數。進而當做標准啟動模式,不斷新建OtherActivity,所以 singleTop 不起作用。。。。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved