singletask模式activity task任务栈按返回键想跳回前一个页面怎么办

2010年9月 移动平台大版内专家分月排行榜第二
2010年12月 移动平台大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。Activity以singleTask模式启动,intent传值的解决办法
时间: 10:32:04
&&&& 阅读:5104
&&&& 评论:
&&&& 收藏:1
标签:&&&&&&&&&&&&转载请注明出处,谢谢
因为项目中,有一个消息推送的功能,每次推送一个消息,就会开启FunctionActivity,那么为了避免重复开启它,在退后的时候,多次出现该Activity,就将该Activity的启动模式变为singleTask。
这样在之后的多次启动该Activity,便会调用onNewIntent(Intent intent)方法。
activity通过intent传递数据的时候,如果activity未启动,那么在这个刚启动的activity里通过getIntent()会获取到这个intent的数据.如果要启动的activity是已经存在的,这时候通过getInten()方法获取到的intent是已启动的activity的原始intent.换句话说intent的数据没有更新.这样在已启动的activity里拿到的intent的数据是旧数据.如果要每次获取intent传来的新数据就需要在onNewIntent(Intent
intent)方法里调用setIntent(intent)设置这个传来的最新的intent.如下所示:
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e(&tag&, &onNewINtent执行了&);
setIntent(intent);
String ringName = intent.getStringExtra(&ringName&);
Log.e(&tag&, ringName+&传过来的值&);
if (ringName != null) {
pager.setCurrentItem(1);
当然,如果activity的启动模式是standard,那么每次都重新创建一个新的activity.这样intent也是最新的.就不用通过setIntent来更新这个intent.
我这个项目中,FunctionActivity中里面是四个Fragment,这样我从其他Activity跳转到FunctionActivity是不会实例化,通过getIntent()方法也不能获得最新的intent,为了解决这个办法。还是在onNewIntent方法中,将更新的intent通过getIntent().putExtras(intent);共享出去,如下所示:
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e(&tag&, &onNewINtent执行了&);
setIntent(intent);
getIntent().putExtras(intent);
这样在与它关联的Fragment中,就可以调用
public void onResume() {
super.onResume();
// 第一次进入这个页面,下面的方法是不会执行的,因为ringName是null
String ringName = getActivity().getIntent().getStringExtra(&ringName&);
if (ringName != null) {
newSound.setText(ringName);
Log.e(&tag&, ringName + &要保存的值&);
SharedPreferenceUtil.setString(getActivity(),
SharedPreferenceUtil.RINGTONE_NAME, ringName);
注意,这里Fragment调用的时候,一定要在onResume方法中。
标签:&&&&&&&&&&&&
&&国之画&&&& &&
版权所有 京ICP备号-2
迷上了代码!以下内容为原创,欢迎转载,转载请注明
来自天天博客:
需求:在ActivityA跳转到ActivityB,然后在ActivityB操作完返回数据给ActivityA。
这个很普遍的需求,一般情况是使用startActivityForResult的方式去完成。
但是当ActivityB为SingleTask时,这个方式就无效了。你会发现当你执行startActivityForResult后,onActivityResult方法马上就会被回调。至于为什么会出现这种情况,参考这位老兄的文章就可以理解。
解决这种情况的方法,第一种是把ActivityA也设置为SingleTask,然后在ActivityB中startActivity(context, ActivityA.class),然后ActivityA在onNewIntent(Intent intent)方法中去获取传递数据,这样的方式不仅破坏了ActivityA的lauchMode,而且还需要ActivityB中启动指定的ActivityA。
所以,如果能把ActivityA的当前对象(实现某个接口)传到ActivityB中,然后ActivityB中通过接口直接回调那就解决问题了。
但是问题是怎么把当前对象传过去,使用Intent显然不行。
思路是维护一个StoragePool,里面可以暂存需要传递的数据。相当于一个暂存区,ActivityA跳转前,把数据放入这个暂存区,获得一个唯一标识,然后把这个唯一标识使用Intent的方式传递给ActivityB,然后ActivityB拿到这个唯一标识后去暂存区去取数据就好了。
暂存区StoragePool代码如下:
* Author: wangjie
* Email: tiantian.china.
* Date: 3/30/15.
6 public class StoragePool {
-- 标识是哪一个intent的(UUID)
|- key -- 存储的对象标识(StorageKey,使用UUID唯一)
* value --|
|- value -- 存储的内容
private static ConcurrentHashMap&String, HashMap&StorageKey, WeakReference&Object&&& storageMapper = new ConcurrentHashMap&&();
private StoragePool() {
public static void storage(String tagUUID, StorageKey key, Object content) {
if (null == key || null == content) {
HashMap&StorageKey, WeakReference&Object&& extraMapper = storageMapper.get(tagUUID);
if (null == extraMapper) {
extraMapper = new HashMap&&();
storageMapper.put(tagUUID, extraMapper);
extraMapper.put(key, new WeakReference&&(content));
public static Object remove(String tagUUID, StorageKey key) {
if (null == key) {
return null;
HashMap&StorageKey, WeakReference&Object&& extraMapper = storageMapper.get(tagUUID);
if (null == extraMapper) {
return null;
WeakReference&Object& ref = extraMapper.remove(key);
if (ABTextUtil.isEmpty(extraMapper)) {
storageMapper.remove(tagUUID);
return null == ref ? null : ref.get();
public static HashMap&StorageKey, WeakReference&Object&& remove(String tagUUID) {
if (null == tagUUID) {
return null;
return storageMapper.remove(tagUUID);
public static void clear() {
storageMapper.clear();
如上代码,StoragePool维护了一个HashMap,key是一个UUID,代表唯一的一个Intent跳转,ActivityA跳转时会把这个UUID传递到ActivityB,ActivityB就是通过这个UUID来获取这次跳转需要传递的数据的。value也是一个HashMap,里面存储了某次跳转传递的所有数据。key是StorageKey,实质上也是一个UUID,value是任意的数据。
跳转前的存储数据和真正的StartActivity都需要使用StorageIntentCenter来进行操作,代码如下:
* Author: wangjie
* Email: tiantian.china.
* Date: 3/31/15.
6 public class StorageIntentCenter {
public static final String STORAGE_INTENT_CENTER_KEY_UUID = StorageIntentCenter.class.getSimpleName() + "_UUID";
private static final String TAG = StorageIntentCenter.class.getSimpleName();
private HashMap&StorageKey, Object&
private boolean isU
public StorageIntentCenter() {
intent = new Intent();
uuid = java.util.UUID.randomUUID().toString();
intent.putExtra(STORAGE_INTENT_CENTER_KEY_UUID, uuid);
isUsed = false;
public StorageIntentCenter putExtra(String intentKey, Object content){
if (null == content) {
return this;
StorageKey storageKey = new StorageKey(content.getClass());
intent.putExtra(intentKey, storageKey);
if(null == extras){
extras = new HashMap&&();
extras.put(storageKey, content);
return this;
public void startActivity(Context packageContext, Class&?& cls){
if(isUsed){
Logger.e(TAG, this + " can not be reuse!");
intent.setClass(packageContext, cls);
if(!ABTextUtil.isEmpty(extras)){
Set&Map.Entry&StorageKey, Object&& entrySet = extras.entrySet();
for(Map.Entry&StorageKey, Object& entry : entrySet){
StoragePool.storage(uuid, entry.getKey(), entry.getValue());
isUsed = true;
packageContext.startActivity(intent);
每个StorageIntentCenter都维护了一个真正跳转的Intent,一个此次跳转的uuid和所有需要传递的数据。
使用方式(以从MainActivity跳转到OtherActivity为例):
MainActivity中:
@AILayout(R.layout.main)
public class MainActivity extends BaseActivity implements ICommunicate {
private static final String TAG = MainActivity.class.getSimpleName();
@AIClick({R.id.ac_test_a_btn})
public void onClickCallbackSample(View view) {
switch (view.getId()) {
case R.id.ac_test_a_btn:
new StorageIntentCenter()
.putExtra("iCommunicate", this)
.putExtra("testString", "hello world")
.putExtra("testFloat", 3.2f)
.startActivity(context, OtherActivity.class);
public void hello(String content) {
Logger.d(TAG, "hello received: " + content);
OtherActivity继承了BaseActivity。
BaseActivity:
* Author: wangjie
* Email: tiantian.china.
* Date: 4/2/15.
6 public class BaseActivity extends AIActivity {
private String storageIntentCenterUUID;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initExtraFromStorage();
// remove extra from StoragePool
StoragePool.remove(storageIntentCenterUUID);
protected void initExtraFromStorage() {
protected final &T& T getExtraFromStorage(String key, Class&T& contentType) {
StorageKey storageKey = (StorageKey) getIntent().getSerializableExtra(key);
if (null == storageIntentCenterUUID) {
storageIntentCenterUUID = getIntent().getStringExtra(StorageIntentCenter.STORAGE_INTENT_CENTER_KEY_UUID);
return (T) StoragePool.remove(storageIntentCenterUUID, storageKey);
Line15:为了防止跳转到OtherActivity后,如果没有去暂存区把数据取出来从而导致暂存区有无用的数据(甚至内存泄漏,暂存区使用软引用也是为了防止这种情况的发生),所以这里提供一个initExtraFromStorage方法让子类重写,子类可以在这个方法中去把数据取出来。然后在initExtraFromStorage方法执行完毕后,再及时把暂存区的数据删除。
Line21~27:这里提供了从暂存区提取数据的方法供子类调用。
OtherActivity:
* Author: wangjie
* Email: tiantian.china.
* Date: 4/2/15.
@AILayout(R.layout.other)
public class OtherActivity extends BaseActivity{
private static final String TAG = OtherActivity.class.getSimpleName();
private ICommunicate iC
private String testS
private Float testF
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
protected void initExtraFromStorage() {
iCommunicate = getExtraFromStorage("iCommunicate", ICommunicate.class);
testString = getExtraFromStorage("testString", String.class);
testFloat = getExtraFromStorage("testFloat", Float.class);
@AIClick({R.id.other_btn})
public void onClickCallbackSample(View view) {
switch(view.getId()){
case R.id.other_btn:
if(null == iCommunicate){
Logger.d(TAG, "iCommunicate: " + iCommunicate);
iCommunicate.hello("content from ACTestBActivity!");
Logger.d(TAG, "testString: " + testString);
Logger.d(TAG, "testFloat: " + testFloat);
如上代码OtherActivity中获取了从MainActivity中传递过来的MainActivity实例,在点击事件发生后通过MainActivity实例进行直接回调。
日志打印如下:
04-03 12:09:52.184
/com.wangjie.androidstorageintent D/OtherActivity﹕ iCommunicate: com.wangjie.androidstorageintent.sample.MainActivity@42879ff8
04-03 12:09:52.184
/com.wangjie.androidstorageintent D/MainActivity﹕ hello received: content from ACTestBActivity!
04-03 12:09:52.184
/com.wangjie.androidstorageintent D/OtherActivity﹕ testString: hello world
04-03 12:09:52.184
/com.wangjie.androidstorageintent D/OtherActivity﹕ testFloat: 3.2
MainActivity被回调,并获取了数据&content from ACTestBActivity!&字符串。
1. 以上使用的代码已托管到github:
2. 上面的注解实现使用AndroidInject:
阅读(...) 评论()我的Android进阶之旅------&Android Activity的singleTask加载模式和onActivityResult方法之间的冲突
博客专家
我的Android进阶之旅------&Android Activity的singleTask加载模式和onActivityResult方法之间的冲突
Android应用开发
&&&&&&&& 今天调试一个bug的时候,情景如下:&&&&&&&&& 一个Activity A,需要用startActivityForResult方法开启Activity B。Activity B的launch mode被设置为singleTask,那么在Activity B开启之后的瞬间(未等B返回任何result),Activity A中的onActivityResult方法就会被调用,并且收到一个RESULT_CANCEL的request code。&&&&&&&& 然后在ActivityB中做了一些逻辑之后,在Activity B通过setResult方法返回Activity A的时候,Activity A中的onActivityResult方法就不再被调用。导致数据不刷新。后来去查看AndroidManifest.xml文档才发现Activity A,Activity B的lunch mode都定义为singleTask。后来把Activity A,Activity B的lunch mode都改为standard后就正常了。============================================================================================================================================================================================================下面这篇文字正好解释了startActivityForResult启动singleTask的Activity,则onActivitResult()立即回调且resultCode为RESULT_CANCEL的现象
,下面转载于:http://blog.csdn.net/sodino/article/details/问题现象:& & & & & 在刚安装完demo应用未登录任何帐号时,通过系统内的分享功能想将文件/图片等内容&发送给好友&或&发送到我的电脑&,触发登录界面,但登录成功后,没有跳转到选择demo好友发送界面,无法继续发送。&&&&&&&&本文为所有,转载请注明出处:代码分析:&&&&&&&& demo中JumpActivity处理着各种外部应用分享入口,通过调试发现进行分享时会判断是否登录过,如果未登录则会跳转至LoginActivity进行登录。如下代码:[java] private&void&doShare(booleancheckLogin)&{&&&&&&&&&&&&&&&&&&&&&&&&Intent&intent&=&getIntent();&&&&&&&&&&&&...&...&&&&&&&&&&&&...&...&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if&(checkLogin&&&!demo.isLogin()){&&&&&&&&&&&&&&&&&&&&&Intent&i&=&newIntent(this,&LoginActivity.class);&&&&&&&&&&&&&&&&&&&&&i.putExtra(&isActionSend&,true);&&&&&&&&&&&&&&&&&&&&&i.putExtras(extra);&&&&&&&&&&&&&&&&&&&&&i.putExtras(i);&&&&&&&&&&&&&&&&&&&&&startActivityForResult(i,SHARE_LOGIN_REQUEST);&&&&&&&&&&&&&&&&&&&&&return;&&&&&&&&&&&&}&&&&&&&&&&&&...&...&&}&&&&&&&&&& 查阅代码得知登录成功后,则JumpActivity.onActivityResult()将会得到requestCode值为SHARE_LOGIN_REQUEST的回调。为此,在onActivityResult()回调处设置断点,再次跟进。&&&&&&&& &&&&&&&& 设置断点,执行分享操作进行调试,发现每次执行完startActivityForResult(),则onActivityResult()便立刻被回调了,且resultCode值为RESULT_CANCEL。至些,问题开始有了头绪。&&&&&&&& 通过排查,发现LoginActivity在之前有被改动过,其launchMode赋值为singleTask。分享功能就是在这次改动之后失效了的。只要恢复launchMode为standard,即可让onActivityResult()在LoginActivity登录成功后正常回调回来,执行分享操作,恢复功能。&&&&&&&& &&&&&&&& 至此,问题得到解决,但问题原因仍是一头雾水:为什么通过startActivityForResult()方式去启动launchMode=singleTask的Activity,onActivityResult()会被立即回调且resultCode值为RESULT_CANCEL??&&&&&&&&原因解析:经查文档,发现文档中另一相似的方法startActivityForResult(Intent,int,Bundle)有说明如下:Note that this method should only be used with Intent protocols thatare defined to return a result. In other protocols (such as ACTION_MAIN orACTION_VIEW), you may not get the result when you expect. For example,if the activity you are launching uses thesingleTask launch mode, it will not run in your task and thus you willimmediately receive a cancel result.&但这点注释让人理解得仍不是很透彻。继续搜索,发现文档(点击)里说了下面的这一种现象。在下图中,存在着前两个栈,其中直接显示在屏幕上与用户交互的Back Stack,及另一个隐藏在后台的Background Task,该栈栈顶的Activity Y其launchMode为singleTask。如果在Activity 2中调用BackgroundTask中已经启动过的Activity Y,则Background Task内占据屏幕并且该Task下所有的栈都会保留当前的栈位置及顺序push进Back Task形成新的结构,顺序由上至下为Activity Y→Activity X→Activity 2→Activity 1。在Activity Y界面按返回键,则ActivityY出栈,Activity X占据屏幕!注意,由Activity2调用的Activity Y,但返回键后,回退显示的是Activity X!所以即使在Activity Y执行setResult(),Activity 2也是无法接收到的。换回文章开头的问题,即在JumpActivity处启动LoginActivity(已经被设置singleTask了),则LoginActivity的setResult()结果有可能不会传给JumpActivity。继续按返回键,则才回到Activity 2。&&问题结论:由此,我们再回到先前的问题。在这种Tasks的入栈与出栈设计下,由于可能有Activity X的存在,所以在Activity 2启动Activity Y时,则直接回调了onActivityResult()并给出了RESULT_CANCEL也就可以理解了。============================================================================================================================================================================================================下面这篇文字正好解释了这个现象,转载于:探索在Google上搜索android activity onactivityresult singTop找到了一些问题。stackoverflowstackoverflow上有些人跟我遇到的问题类似。比如说有一位开发者把Activity设置成了singleTask模式,onActivityResult就收不到任何结果了。当他把singleTask模式改回标准模式,又恢复正常。这个问题下面给出的答案中,有一位说startActivityForResult的文档中有这么一句话:For example, if the activity you are launching uses the singleTask launch mode,&it will not run in your task and thus you will immediately receive a cancel result.意思是:比如说,如果你正加载的activity使用了singleTask的加载模式,它不会在你的栈中运行,而且这样你会马上收到一个取消的结果。即在onActivityResult里马上得到一个RESULT_CANCEL.他还补充说没有很好的补救方法。可以试试用监听广播的方法。另一个stackoverflow的问题中,有人直接回答了不能再singleInstance或singleTop模式下使用startActivityForResult()方法,不仅被采纳了,票数还不低。剩下的一个stackoverflow问题中,有人说把singleTask改成singleTop就会正常,得到高达59票并被采纳。实际上我用的就是singTop,可是onActivityResult还是无缘无故被调用了。startActivityForResult的文档:public void startActivityForResult (Intent intent, int requestCode, Bundle options)Added in API level 16Launch an activity for which you would like a result when it finished. When this activity exits, your onActivityResult() method will be called with the given requestCode. Using a negative requestCode is the same as calling startActivity(Intent) (the activity is not launched as a sub-activity).加载一个Activity,当它结束时你会得到结果。当这个Activty退出了,你的onActivityResult()方法会根据给出的requestCode被调用。使用一个负的requestCode和调用startActivity(intent)一样(activity不被加载成子activity)Note that this method should only be used with Intent protocols that are defined to return a result. In other protocols (such as ACTION_MAIN or ACTION_VIEW), you may not get the result when you expect. For example, if the activity you are launching uses the singleTask launch mode, it will not run in your task and thus you will immediately receive a cancel result.注意这个方法只能用于被定义要返回结果的Intent协议。在其他协议中(譬如ACTION_MAIN或ACTION_VIEW),你可能在你想得到结果时得不到。比如,当你正载入的Activity使用的singleTask加载模式,它不会在你的栈中运行,这样你会立马得到一个取消的结果。As a special case, if you call startActivityForResult() with a requestCode &= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your activity, then your window will not be displayed until a result is returned back from the started activity. This is to avoid visible flickering when redirecting to another activity.有一个特例是,当你在初始的onCreate()方法或onResume()方法中用一个大于等于0的请求码调用startActivityForResult(),你的窗口在被启动的Activity返回结果前不会显示。这是为了避免跳转到另一Activity时可见的闪烁。This method throws ActivityNotFoundException if there was no Activity found to run the given Intent.如果运行所给Intent的Activity没被找到,该方法会抛出ActivityNotFoundException异常。Activity的加载模式Use CasesLaunch ModeMultiple Instances?CommentsNormal launches for most activities&standard&YesDefault. The system always creates a new instance of the activity in the target task and routes the intent to it.&singleTop&ConditionallyIf an instance of the activity already exists at the top of the target task, the system routes the intent to that instance through a call to its&method, rather than creating a new instance of the activity.Specialized launches(not recommended for general use)&singleTask&NoThe system creates the activity at the root of a new task and routes the intent to it. However, if an instance of the activity already exists, the system routes the intent to existing instance through a call to its&method, rather than creating a new one.&singleInstance&NoSame as &singleTask&, except that the system doesn't launch any other activities into the task holding the instance. The activity is always the single and only member of its task.singleTop模式,可用来解决栈顶多个重复相同的Activity的问题。singleTask模式和后面的singleInstance模式都是只创建一个实例的。当intent到来,需要创建singleTask模式Activity的时候,系统会检查栈里面是否已经有该Activity的实例。如果有直接将intent发送给它。singleInstance模式解决了这个问题(绕了这么半天才说到正题)。让这个模式下的Activity单独在一个task栈中。这个栈只有一个Activity。导游应用和google地图应用发送的intent都由这个Activity接收和展示。总结后来我改变了onActivityResult里面ResultCode为RESULT_OK时刷新界面的具体实现方法,可是onActivityResult还是会自己被调用,只是暂时没触发任何bug,可它还是个定时炸弹啊。以后在选择Activity的加载模式时,要考虑onActivtyResult方法与之存在冲突。参考&&&&&&&& ====================================================================================& 作者:欧阳鹏& 欢迎转载,与人分享是进步的源泉!& 转载请保留原文地址:====================================================================================
我的热门文章
即使是一小步也想与你分享今天看啥 热点:
Activity以singleTask模式启动,intent传值的解决办法,singletaskintent
转载请注明出处,谢谢http://blog.csdn.net/harryweasley/article/details/
因为项目中,有一个消息推送的功能,每次推送一个消息,就会开启FunctionActivity,那么为了避免重复开启它,在退后的时候,多次出现该Activity,就将该Activity的启动模式变为singleTask。
这样在之后的多次启动该Activity,便会调用onNewIntent(Intent intent)方法。
activity通过intent传递数据的时候,如果activity未启动,那么在这个刚启动的activity里通过getIntent()会获取到这个intent的数据.如果要启动的activity是已经存在的,这时候通过getInten()方法获取到的intent是已启动的activity的原始intent.换句话说intent的数据没有更新.这样在已启动的activity里拿到的intent的数据是旧数据.如果要每次获取intent传来的新数据就需要在onNewIntent(Intent
intent)方法里调用setIntent(intent)设置这个传来的最新的intent.如下所示:
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e(&tag&, &onNewINtent执行了&);
setIntent(intent);
String ringName = intent.getStringExtra(&ringName&);
Log.e(&tag&, ringName+&传过来的值&);
if (ringName != null) {
pager.setCurrentItem(1);
当然,如果activity的启动模式是standard,那么每次都重新创建一个新的activity.这样intent也是最新的.就不用通过setIntent来更新这个intent.
我这个项目中,FunctionActivity中里面是四个Fragment,这样我从其他Activity跳转到FunctionActivity是不会实例化,通过getIntent()方法也不能获得最新的intent,为了解决这个办法。还是在onNewIntent方法中,将更新的intent通过getIntent().putExtras(intent);共享出去,如下所示:
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e(&tag&, &onNewINtent执行了&);
setIntent(intent);
getIntent().putExtras(intent);
这样在与它关联的Fragment中,就可以调用
public void onResume() {
super.onResume();
// 第一次进入这个页面,下面的方法是不会执行的,因为ringName是null
String ringName = getActivity().getIntent().getStringExtra(&ringName&);
if (ringName != null) {
newSound.setText(ringName);
Log.e(&tag&, ringName + &要保存的值&);
SharedPreferenceUtil.setString(getActivity(),
SharedPreferenceUtil.RINGTONE_NAME, ringName);
注意,这里Fragment调用的时候,一定要在onResume方法中。
相关搜索:
相关阅读:
相关频道:
Android教程最近更新}

我要回帖

更多关于 activity taskservice 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信