zoukankan      html  css  js  c++  java
  • [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

  • 相关阅读:
    大数据分析项目中的“最差”实践
    【Python】Python正则表达式使用指导
    大数据分析的5个方面
    你真的会python嘛?
    你是如何自学 Python 的?
    python中#!/usr/bin/python与#!/usr/bin/env python的区别
    [实验吧刷题]密码学部分
    [bugku]高阶web 综合帖
    [bugku]sqlmap部分
    【ctf第一次校赛】+不会的web/ +凉凉的省赛预赛 + 最后摸了 个二等。。
  • 原文地址:https://www.cnblogs.com/tiantianbyconan/p/4389674.html
Copyright © 2011-2022 走看看