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

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

每个StorageIntentCenter都维护了一个真正跳转的Intent,一个此次跳转的uuid和所有需要传递的数据。

使用方式(以从MainActivity跳转到OtherActivity为例):

MainActivity中:

  1. @AILayout(R.layout.main)
  2. public class MainActivity extends BaseActivity implements ICommunicate {
  3.  
  4. private static final String TAG = MainActivity.class.getSimpleName();
  5.  
  6. @Override
  7. @AIClick({R.id.ac_test_a_btn})
  8. public void onClickCallbackSample(View view) {
  9. switch (view.getId()) {
  10. case R.id.ac_test_a_btn:
  11. new StorageIntentCenter()
  12. .putExtra("iCommunicate", this)
  13. .putExtra("testString", "hello world")
  14. .putExtra("testFloat", 3.2f)
  15. .startActivity(context, OtherActivity.class);
  16.  
  17. break;
  18. }
  19. }
  20.  
  21. @Override
  22. public void hello(String content) {
  23. Logger.d(TAG, "hello received: " + content);
  24. }
  25.  
  26. }

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:

  1. /**
  2. * Author: wangjie
  3. * Email: tiantian.china.2@gmail.com
  4. * Date: 4/2/15.
  5. */
  6. @AILayout(R.layout.other)
  7. public class OtherActivity extends BaseActivity{
  8. private static final String TAG = OtherActivity.class.getSimpleName();
  9.  
  10. private ICommunicate iCommunicate;
  11. private String testString;
  12. private Float testFloat;
  13.  
  14. @Override
  15. protected void onCreate(Bundle savedInstanceState) {
  16. super.onCreate(savedInstanceState);
  17. }
  18.  
  19. @Override
  20. protected void initExtraFromStorage() {
  21. iCommunicate = getExtraFromStorage("iCommunicate", ICommunicate.class);
  22. testString = getExtraFromStorage("testString", String.class);
  23. testFloat = getExtraFromStorage("testFloat", Float.class);
  24. }
  25.  
  26. @Override
  27. @AIClick({R.id.other_btn})
  28. public void onClickCallbackSample(View view) {
  29. switch(view.getId()){
  30. case R.id.other_btn:
  31. if(null == iCommunicate){
  32. return;
  33. }
  34. Logger.d(TAG, "iCommunicate: " + iCommunicate);
  35. iCommunicate.hello("content from ACTestBActivity!");
  36.  
  37. Logger.d(TAG, "testString: " + testString);
  38. Logger.d(TAG, "testFloat: " + testFloat);
  39. finish();
  40.  
  41. break;
  42. }
  43. }
  44. }

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

日志打印如下:

  1. 04-03 12:09:52.184 25529-25529/com.wangjie.androidstorageintent D/OtherActivity iCommunicate: com.wangjie.androidstorageintent.sample.MainActivity@42879ff8
  2. 04-03 12:09:52.184 25529-25529/com.wangjie.androidstorageintent D/MainActivity hello received: content from ACTestBActivity!
  3. 04-03 12:09:52.184 25529-25529/com.wangjie.androidstorageintent D/OtherActivity testString: hello world
  4. 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

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

  1. Golang 传递任意类型的切片

    肯定有这样的一种场景,写一个函数,该函数可以接收任意类型的切片,完成相应的功能. 就好比这种情况 intSlice := []int{1,2,3,4,5,6,7,8} strSlice := []st ...

  2. Intent Activity跳转 传递数据 Bundle

    1.普通跳转: Intent intent=new Intent(); intent.setClass(MainActivity.this,NewActivity.class); //新建一个Inte ...

  3. C++使用模版技术将任意类型的数据转为某个类型的数据

    将任意类型(int, float, 自定义的数据类型等等)的数据转换的某个类型C中储存,可以通过 将类型C的构造函数写成模版函数的形式,在C中将可以接收任意类型数据.如: class C{ templ ...

  4. 在Activity之间如何传递数据,请尽可能说出你所知道的传递数据的方法,并详细描述其实现过程。

    在Activity之间如何传递数据,请尽可能说出你所知道的传递数据的方法,并详细描述其实现过程. 答案:可以通过Intent对象.静态变量.剪切板和全局对象进行数据传递,具体的数据传递方法如下. 1. ...

  5. 【转】Intent传递数据时,可以传递哪些类型数据?

    在Android应用的开发中,如果我们需要在不同的模块(比如不同的Activity之间)之间传递数据,通常有以下两种方法:1. 利用Intent对象携带数据通过查询Intent/Bundle的API文 ...

  6. 为GCD队列绑定NSObject类型上下文数据-利用__bridge_retained(transfer)转移内存管理权-备

    下面评论的好友“@Jim”给了种新的思路,就是在清除context的函数里面,用“_bridge_transfer”转换context,把context的内存管理权限重新交给ARC,这样,就不用显式调 ...

  7. android入门,activity跳转,并传递message

    首先是布局文件,如下: activity_main.xml <?xml version="1.0" encoding="utf-8"?> <L ...

  8. android 15 activity跳转

    从一个屏幕跳到另一个屏幕,一个activity跳转到另一个activity,Intent类用于组件之间传递数据和跳转,组件包括不仅activity. package com.sxt.day04_01; ...

  9. Android之Activity跳转

    简述 如果把每个activity看成一个页面的话,那么activity之间的跳转和页面的之间的跳转基本上是一样的.首先需要监听一个事件,当这个事件发生的时候,就进行跳转.html中有个<a sr ...

随机推荐

  1. Windows下elasticsearch插入数据报错!

    按照官方文档操作,但是windows下有些不同,它不认识单引号',因此如果这样操作,就会报错: C:\Users\neusoft>curl localhost:9200/b1/b2/1 -d { ...

  2. SQL Server代理(1/12):配置和概况

    SQL Server代理是所有实时数据库的核心.代理有很多不明显的用法,因此系统的知识,对于开发人员还是DBA都是有用的.这系列文章会通俗介绍它的很多用法. SQL Server代理是SQL Serv ...

  3. Httpd运维日志:通过apxs添加模块

    Brief 在部署Httpd时为方便管理和安全等原因,我们仅会安装所需的模块,那么后期功能扩展时则需要通过Httpd内置提供的apxs程序来进行模块添加. 而apxs程序则位于apache/bin目录 ...

  4. iOS宏定义的使用与规范

    宏定义在很多方面都会使用,例如定义高度.判断iOS系统.工具类,还有诸如文件路径.服务端api接口文档.为了对宏能够快速定位和了解其功能,我们最好在定义的时候将其放入特定的头文件中 定义尺寸类的宏 D ...

  5. 使用Spark分析拉勾网招聘信息(三): BMR 入门

    简述 本文,意在以最小的篇幅,来帮助对大数据和Spark感兴趣的小伙伴,能尽快搭建一个可用的Spark开发环境.力求言简意赅.文章,不敢自称BMR的最佳实践,但绝对可以帮助初学者,迅速入门,能够专心于 ...

  6. ASP.NET MVC系列:从Controller访问Model数据

    在项目解决方案中,添加一个MoviesController控制器,选择对应的模板,和模型类以及数据上下文:关于如何添加模型类和数据上下文,我们在ASP.NET MVC系列:添加模型中已经介绍过

  7. Sql Server 2008 无法启动T-Sql调试问题的解决方案

    今天在调试存储过程时,出现无法启动T-SQL 调试的问题

  8. Support for multiple result sets

    https://blueprints.launchpad.net/myconnpy/+spec/sp-multi-resultsets Calling a stored procedure can p ...

  9. 解决SqlPlus前台程序出现中文乱码的问题

    在使用sqlplus的过程中,常常会遇到某一台机器在访问oracle数据库时中文显示乱码的问题,实际上这是因为客户端字符集和服务器字符集不一致导致的.在实际使用中,服务器字符集,客户端字符集和操作系统 ...

  10. 【Linux_Fedora_应用系列】_5_如何安装XZ Utils 解压缩工具以及利用 xz工具来解压缩.xz文件

    有段时间没有来园子了,今天从 www.kernel.org 上面下载了一个 2.6.32.2 内核压缩包,下载 下来后发现是一个  .xz  结尾的文件,一看与通常的  .gz..bz2等格式不一样, ...