Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 105492|回复: 0

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

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-4-8 03:53:47 | 显示全部楼层 |阅读模式

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

    来自天天博客: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

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-4-29 03:29 , Processed in 0.075192 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表