探究startActivityForResult在singleTop和singleTask启动模式讨论
2016-08-18 11:15
543 查看
最近在研究AMS代码遇到一个问题,在函数startActivityUncheckedLocked中
ActivityStack topStack = getFocusedStack();
ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
这两句的意思是获取当前正在显示的栈顶的Activity,
例如OtherActivity在栈顶。当前获取的就是OtherActivity,也就是显示在当前手机界面的Activity。
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,
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启动自己 会有什么效果呢??
这是主 Activity ,我们在主Activity (MainActivity ) 启动 OtherActivity ,
OtherActivity 模式为singleTop 模式
OtherActivity 代码:
再此情况下点击 MainActivity的Btn2 启动OtherActivity是可以正常启动的此时显示 “我是OtherActivity1”。OtherActivity的Btn2 启动自己也是可以正常启动。此时 会发现 界面仍是OtherActivity1,显示我是“OtherActivity1”你不断点击OtherActivity1的Btn2 。界面仍是显示我是“OtherActivity1”
此时打印日志会显示
Log.d(“DDY”, “OnNewIntent”); 这句话被打印出来了。说明OtherActivity此时的启动并不是新建OtherActivity,只是重载原来的OtherActivity。
说明 函数 top.deliverNewIntentLocked(callingUid, r.intent)被调用了,由于此函数主要作用就是调用 onNewIntent 函数。所以 界面一直重载并不会新建OtherActivity。
现在考虑使用startActivityForResult 情况:
在这种情况下MainActivity的Btn2 启动OtherActivity是可以正常启动的此时显示 “我是OtherActivity1”。
点击返回键可以正常返回到MainActivity ,可以正常打印出
startActivityForResult 在 MainActivity 启动OtherActivity 是起作用的。
如果OtherActivity 启动自己,不断点击Btn2 ,发现 OtherActivity 不断新建 OtherActivity ,并不会重载此时OtherActivity 显示随着点击 不断变化 “我是OtherActivity1” “我是OtherActivity2” “我是OtherActivity3” …….. 等等。
按返回键也可以 返回OtherActivity3 -> OtherActivity2 -> OtherActivity1 .说明此时的 singleTop 在 startActivityForResult 模式下面并没有起作用。这个不起作用有条件的就是:
此时OtherActivity 正在栈顶且为singleTop 模式。并且用startActivityForResult 启动 自己。此时的singleTop 不起作用。被当做standard 模式。会不断新建OtherActivity 。
之所以在startActivityForResult 启动singleTop 不起作用,在源码中一句话决定了。
上面一句话 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 不起作用。。。。
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。
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 模式
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.systemupdate" android:versionCode="11" android:versionName="1.1" > <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="17" /> <uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" /> <uses-permission android:name="android.permission.REBOOT" /> <uses-permission android:name="android.permission.STATUS_BAR" /> <uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/> <uses-permission android:name="android.permission.MASTER_CLEAR" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="pptv" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".OtherActivity" android:launchMode="singleTop"></activity> </application> </manifest>
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 不起作用。。。。
相关文章推荐
- android中Activity的启动模式是singleTask或singleInstance与startActivityForResult,onActivityResult
- StartActivityForResult与启动模式singleTask,singleInstance研究
- StartActivityForResult与SingleTask启动模式之间的关系
- startActivityForResult启动singleTask的Activity,则onActivitResult()立即回调且resultCode为RESULT_CANCEL
- [Android]startActivityForResult启动singleTask的Activity,则onActivitResult()立即回调且resultCode为RESULT_CANCEL
- Intent startActivityForResult 启动 与 Activity启动模式
- Activity的启动模式与startActivityForResult的关系
- Android中关于startActivityForResult()在activity不同启动模式下onActivityResult()的回调
- StartActivityForResult与启动模式
- [Android]startActivityForResult启动singleTask的Activity,则onActivitResult()立即回调且resultCode为RESULT_CANCEL
- Android activity的startActivityForResult和onActivityResult与启动模式的关系
- Activity的启动模式与startActivityForResult的关系
- 一种轻量级解决startActivityForResult启动Activity导致singleTop模式失效
- StartActivityForResult启动模式在不同场景下的不同结果
- activity启动模式与startActivityForResult冲突
- Intent的用法(一),启动activity传递数据以及startActivityForResult .
- Android学习-启动服务startActivityForResult调用activity并覆写onActivityResult()接收返回来的信息
- startActivityForResult无法调用singleTask的Activity
- 关于startActivityForResult、onActivityResult和singleTask
- SingleTask 与 startActivityForResult冲突问题