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

来自天天博客: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代码如下:

 /**
* Author: wangjie
* Email: tiantian.china.2@gmail.com
* Date: 3/30/15.
*/
public class StoragePool {
/**
* key -- 标识是哪一个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) {
return;
}
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.2@gmail.com
* Date: 3/31/15.
*/
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 Intent intent;
private String uuid;
private HashMap<StorageKey, Object> extras;
private boolean isUsed;
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!");
return;
}
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(); @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:

 /**
* Author: wangjie
* Email: tiantian.china.2@gmail.com
* Date: 4/2/15.
*/
public class BaseActivity extends AIActivity {
private String storageIntentCenterUUID; @Override
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.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

[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. Asp.net Core的代码移植技巧,半天将SqlSugarORM转成Core

    .net  core中有哪些被抛弃的类 1.DataTable DataRow SqlDataAdapter DataRow DataColumn DataColumn 虽然这些类不是我ORM核心功能 ...

  2. UWP开发入门(二十一)——保持Ui线程处于响应状态

    GUI的程序有时候会因为等待一个耗时操作完成,导致界面卡死.本篇我们就UWP开发中可能遇到的情况,来讨论如何优化处理. 假设当前存在点击按钮跳转页面的操作,通过按钮打开的新页面,在初始化过程中存在一些 ...

  3. 关于Entity Framework自动关联查询与自动关联更新导航属性对应的实体注意事项说明

    一.首先了解下Entity Framework 自动关联查询: Entity Framework 自动关联查询,有三种方法:Lazy Loading(延迟加载),Eager Loading(预先加载) ...

  4. 阅读《LEARNING HARD C#学习笔记》知识点总结与摘要一

    本人有幸在Learning Hard举行的整点抢书活动<Learninghard C#学习笔记>回馈网友,免费送书5本中免费获得了一本<LEARNING HARD C#学习笔记> ...

  5. [python基础]关于装饰器

    在面试的时候,被问到装饰器,在用的最多的时候就@classmethod ,@staticmethod,开口胡乱回答想这和C#的static public 关键字是不是一样的,等面试回来一看,哇,原来是 ...

  6. SQL Server时间粒度系列----第1节时间粒度概述

    本文目录列表: 1.什么是时间粒度?2.SQL Server提供的时间粒度3.SQL Server时间粒度代码演示   4.SQL Server基准日期 5.总结语6.参考清单列表   什么是时间粒度 ...

  7. ES6笔记(1) -- 环境配置支持

    系列文章 -- ES6笔记系列 虽然ES6已经发布一年多了,但在各大浏览器之中的支持度还不是很理想,在这查看ES6新特性支持度 Chrome的最新版本浏览器大部分已经支持,在Node.js环境上支持度 ...

  8. IIS 架构解析

    我们在使用ASP.NET平台做web开发的时候,经常会接触到IIS(Internet Information Services 互联网信息服务).这篇文章主要来介绍IIS7.0+的架构.IIS的安全脆 ...

  9. Oracle命名规范

    1.编写目的 使用统一的命名和编码规范,使数据库命名及编码风格标准化,以便于阅读.理解和继承. 2.适用范围 本规范适用于公司范围内所有以ORACLE作为后台数据库的应用系统和项目开发工作. 3.对象 ...

  10. Win10 IoT C#开发 5 - 操作 IoT 设备内嵌 SQLite 数据库 CURD

    Windows 10 IoT Core 是微软针对物联网市场的一个重要产品,与以往的Windows版本不同,是为物联网设备专门设计的,硬件也不仅仅限于x86架构,同时可以在ARM架构上运行. 前几章我 ...