[Android]Activity跳转传递任意类型的数据、Activity为SingleTask时代替StartActivityForResult的解决方案

简介:

以下内容为原创,欢迎转载,转载请注明

来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/4389674.html

 

需求:在ActivityA跳转到ActivityB,然后在ActivityB操作完返回数据给ActivityA。

这个很普遍的需求,一般情况是使用startActivityForResult的方式去完成。

但是当ActivityB为SingleTask时,这个方式就无效了。你会发现当你执行startActivityForResult后,onActivityResult方法马上就会被回调。至于为什么会出现这种情况,参考这位老兄的文章就可以理解http://blog.csdn.net/sodino/article/details/22101881

解决这种情况的方法,第一种是把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代码如下:

复制代码
 1 /**
 2  * Author: wangjie
 3  * Email: tiantian.china.2@gmail.com
 4  * Date: 3/30/15.
 5  */
 6 public class StoragePool {
 7     /**
 8      * key   -- 标识是哪一个intent的(UUID)
 9      *
10      *         |- key -- 存储的对象标识(StorageKey,使用UUID唯一)
11      * value --|
12      *         |- value -- 存储的内容
13      */
14     private static ConcurrentHashMap<String, HashMap<StorageKey, WeakReference<Object>>> storageMapper = new ConcurrentHashMap<>();
15 
16     private StoragePool() {
17     }
18 
19     public static void storage(String tagUUID, StorageKey key, Object content) {
20         if (null == key || null == content) {
21             return;
22         }
23         HashMap<StorageKey, WeakReference<Object>> extraMapper = storageMapper.get(tagUUID);
24         if (null == extraMapper) {
25             extraMapper = new HashMap<>();
26             storageMapper.put(tagUUID, extraMapper);
27         }
28         extraMapper.put(key, new WeakReference<>(content));
29     }
30 
31     public static Object remove(String tagUUID, StorageKey key) {
32         if (null == key) {
33             return null;
34         }
35         HashMap<StorageKey, WeakReference<Object>> extraMapper = storageMapper.get(tagUUID);
36         if (null == extraMapper) {
37             return null;
38         }
39 
40         WeakReference<Object> ref = extraMapper.remove(key);
41         if (ABTextUtil.isEmpty(extraMapper)) {
42             storageMapper.remove(tagUUID);
43         }
44         return null == ref ? null : ref.get();
45     }
46 
47     public static HashMap<StorageKey, WeakReference<Object>> remove(String tagUUID) {
48         if (null == tagUUID) {
49             return null;
50         }
51         return storageMapper.remove(tagUUID);
52     }
53 
54     public static void clear() {
55         storageMapper.clear();
56     }
57 
58 }
复制代码

如上代码,StoragePool维护了一个HashMap,key是一个UUID,代表唯一的一个Intent跳转,ActivityA跳转时会把这个UUID传递到ActivityB,ActivityB就是通过这个UUID来获取这次跳转需要传递的数据的。value也是一个HashMap,里面存储了某次跳转传递的所有数据。key是StorageKey,实质上也是一个UUID,value是任意的数据。

跳转前的存储数据和真正的StartActivity都需要使用StorageIntentCenter来进行操作,代码如下:

复制代码
 1 /**
 2  * Author: wangjie
 3  * Email: tiantian.china.2@gmail.com
 4  * Date: 3/31/15.
 5  */
 6 public class StorageIntentCenter {
 7     public static final String STORAGE_INTENT_CENTER_KEY_UUID = StorageIntentCenter.class.getSimpleName() + "_UUID";
 8     private static final String TAG = StorageIntentCenter.class.getSimpleName();
 9 
10     private Intent intent;
11     private String uuid;
12     private HashMap<StorageKey, Object> extras;
13     private boolean isUsed;
14     public StorageIntentCenter() {
15         intent = new Intent();
16         uuid = java.util.UUID.randomUUID().toString();
17         intent.putExtra(STORAGE_INTENT_CENTER_KEY_UUID, uuid);
18         isUsed = false;
19     }
20 
21     public StorageIntentCenter putExtra(String intentKey, Object content){
22         if (null == content) {
23             return this;
24         }
25         StorageKey storageKey = new StorageKey(content.getClass());
26         intent.putExtra(intentKey, storageKey);
27         if(null == extras){
28             extras = new HashMap<>();
29         }
30         extras.put(storageKey, content);
31         return this;
32     }
33 
34     public void startActivity(Context packageContext, Class<?> cls){
35         if(isUsed){
36             Logger.e(TAG, this + " can not be reuse!");
37             return;
38         }
39         intent.setClass(packageContext, cls);
40         if(!ABTextUtil.isEmpty(extras)){
41             Set<Map.Entry<StorageKey, Object>> entrySet = extras.entrySet();
42             for(Map.Entry<StorageKey, Object> entry : entrySet){
43                 StoragePool.storage(uuid, entry.getKey(), entry.getValue());
44             }
45         }
46         isUsed = true;
47         packageContext.startActivity(intent);
48     }
49 
50 
51 }
复制代码

每个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();

    @Override
    @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);

                break;
        }
    }

    @Override
    public void hello(String content) {
        Logger.d(TAG, "hello received: " + content);
    }

}
复制代码

 

OtherActivity继承了BaseActivity。

BaseActivity:

复制代码
 1 /**
 2  * Author: wangjie
 3  * Email: tiantian.china.2@gmail.com
 4  * Date: 4/2/15.
 5  */
 6 public class BaseActivity extends AIActivity {
 7     private String storageIntentCenterUUID;
 8 
 9     @Override
10     protected void onCreate(Bundle savedInstanceState) {
11         super.onCreate(savedInstanceState);
12 
13         initExtraFromStorage();
14         // remove extra from StoragePool
15         StoragePool.remove(storageIntentCenterUUID);
16     }
17 
18     protected void initExtraFromStorage() {
19     }
20 
21     protected final <T> T getExtraFromStorage(String key, Class<T> contentType) {
22         StorageKey storageKey = (StorageKey) getIntent().getSerializableExtra(key);
23         if (null == storageIntentCenterUUID) {
24             storageIntentCenterUUID = getIntent().getStringExtra(StorageIntentCenter.STORAGE_INTENT_CENTER_KEY_UUID);
25         }
26         return (T) StoragePool.remove(storageIntentCenterUUID, storageKey);
27     }
28 
29 }
复制代码

Line15:为了防止跳转到OtherActivity后,如果没有去暂存区把数据取出来从而导致暂存区有无用的数据(甚至内存泄漏,暂存区使用软引用也是为了防止这种情况的发生),所以这里提供一个initExtraFromStorage方法让子类重写,子类可以在这个方法中去把数据取出来。然后在initExtraFromStorage方法执行完毕后,再及时把暂存区的数据删除。

Line21~27:这里提供了从暂存区提取数据的方法供子类调用。

 

OtherActivity:

复制代码
/**
 * Author: wangjie
 * Email: tiantian.china.2@gmail.com
 * Date: 4/2/15.
 */
@AILayout(R.layout.other)
public class OtherActivity extends BaseActivity{
    private static final String TAG = OtherActivity.class.getSimpleName();

    private ICommunicate iCommunicate;
    private String testString;
    private Float testFloat;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void initExtraFromStorage() {
        iCommunicate = getExtraFromStorage("iCommunicate", ICommunicate.class);
        testString = getExtraFromStorage("testString", String.class);
        testFloat = getExtraFromStorage("testFloat", Float.class);
    }

    @Override
    @AIClick({R.id.other_btn})
    public void onClickCallbackSample(View view) {
        switch(view.getId()){
            case R.id.other_btn:
                if(null == iCommunicate){
                    return;
                }
                Logger.d(TAG, "iCommunicate: " + iCommunicate);
                iCommunicate.hello("content from ACTestBActivity!");

                Logger.d(TAG, "testString: " + testString);
                Logger.d(TAG, "testFloat: " + testFloat);
                finish();

                break;
        }
    }
}
复制代码

如上代码OtherActivity中获取了从MainActivity中传递过来的MainActivity实例,在点击事件发生后通过MainActivity实例进行直接回调。

日志打印如下:

复制代码
04-03 12:09:52.184  25529-25529/com.wangjie.androidstorageintent D/OtherActivity﹕ iCommunicate: com.wangjie.androidstorageintent.sample.MainActivity@42879ff8
04-03 12:09:52.184  25529-25529/com.wangjie.androidstorageintent D/MainActivity﹕ hello received: content from ACTestBActivity!
04-03 12:09:52.184  25529-25529/com.wangjie.androidstorageintent D/OtherActivity﹕ testString: hello world
04-03 12:09:52.184  25529-25529/com.wangjie.androidstorageintent D/OtherActivity﹕ testFloat: 3.2
复制代码

MainActivity被回调,并获取了数据“content from ACTestBActivity!”字符串。

 

注:

1. 以上使用的代码已托管到github:https://github.com/wangjiegulu/AndroidStorageIntent

2. 上面的注解实现使用AndroidInject:https://github.com/wangjiegulu/androidInject

 本文转自天天_byconan博客园博客,原文链接:http://www.cnblogs.com/tiantianbyconan/p/4389674.html,如需转载请自行联系原作者

相关文章
|
1月前
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
78 6
|
29天前
|
程序员 开发工具 Android开发
Android|WebView 禁止长按,限制非白名单域名的跳转层级
如何限制 WebView 仅域名白名单网址能随意跳转,并禁用长按选择文字。
34 2
|
1月前
|
消息中间件 Android开发 索引
Android面试高频知识点(4) 详解Activity的启动流程
Android面试高频知识点(4) 详解Activity的启动流程
27 3
|
1月前
|
缓存 前端开发 Android开发
Android实战之如何截取Activity或者Fragment的内容?
本文首发于公众号“AntDream”,介绍了如何在Android中截取Activity或Fragment的屏幕内容并保存为图片。包括截取整个Activity、特定控件或区域的方法,以及处理包含RecyclerView的复杂情况。
19 3
|
21天前
|
安全 搜索推荐 程序员
深入探索Android系统的碎片化问题及其解决方案
在移动操作系统的世界中,Android以其开放性和灵活性赢得了广泛的市场份额。然而,这种开放性也带来了一个众所周知的问题——系统碎片化。本文旨在探讨Android系统碎片化的现状、成因以及可能的解决方案,为开发者和用户提供一种全新的视角来理解这一现象。通过分析不同版本的Android系统分布、硬件多样性以及更新机制的影响,我们提出了一系列针对性的策略,旨在减少碎片化带来的影响,提升用户体验。
|
1月前
|
开发框架 移动开发 Android开发
安卓与iOS开发中的跨平台解决方案:Flutter入门
【9月更文挑战第30天】在移动应用开发的广阔舞台上,安卓和iOS两大操作系统各自占据半壁江山。开发者们常常面临着选择:是专注于单一平台深耕细作,还是寻找一种能够横跨两大系统的开发方案?Flutter,作为一种新兴的跨平台UI工具包,正以其现代、响应式的特点赢得开发者的青睐。本文将带你一探究竟,从Flutter的基础概念到实战应用,深入浅出地介绍这一技术的魅力所在。
82 7
|
2月前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台解决方案
【9月更文挑战第27天】在移动应用开发的广阔天地中,安卓和iOS两大操作系统如同双子星座般耀眼。开发者们在这两大平台上追逐着创新的梦想,却也面临着选择的难题。如何在保持高效的同时,实现跨平台的开发?本文将带你探索跨平台开发的魅力所在,揭示其背后的技术原理,并通过实际案例展示其应用场景。无论你是安卓的忠实拥趸,还是iOS的狂热粉丝,这篇文章都将为你打开一扇通往跨平台开发新世界的大门。
|
1月前
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
18 0
|
1月前
|
Android开发
Android开发显示头部Bar的需求解决方案--Android应用实战
Android开发显示头部Bar的需求解决方案--Android应用实战
21 0
|
2月前
|
Android开发 开发者
Android面试之Activity启动流程简述
每个Android开发者都熟悉的Activity,但你是否了解它的启动流程呢?本文将带你深入了解。启动流程涉及四个关键角色:Launcher进程、SystemServer的AMS、应用程序的ActivityThread及Zygote进程。核心在于AMS与ActivityThread间的通信。文章详细解析了从Launcher启动Activity的过程,包括通过AIDL获取AMS、Zygote进程启动以及ActivityThread与AMS的通信机制。接着介绍了如何创建Application及Activity的具体步骤。整体流程清晰明了,帮助你更深入理解Activity的工作原理。
53 0
下一篇
无影云桌面