[Android]Activity跳转传递任意类型的数据、Activity为SingleTask时代替StartActivityForResult的解决方案
2015-04-03 12:15
489 查看
以下内容为原创,欢迎转载,转载请注明
来自天天博客:/article/4917495.html
需求:在ActivityA跳转到ActivityB,然后在ActivityB操作完返回数据给ActivityA。
这个很普遍的需求,一般情况是使用startActivityForResult的方式去完成。
但是当ActivityB为SingleTask时,这个方式就无效了。你会发现当你执行startActivityForResult后,onActivityResult方法马上就会被回调。至于为什么会出现这种情况,参考这位老兄的文章就可以理解/article/2637339.html。
解决这种情况的方法,第一种是把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代码如下:
如上代码,StoragePool维护了一个HashMap,key是一个UUID,代表唯一的一个Intent跳转,ActivityA跳转时会把这个UUID传递到ActivityB,ActivityB就是通过这个UUID来获取这次跳转需要传递的数据的。value也是一个HashMap,里面存储了某次跳转传递的所有数据。key是StorageKey,实质上也是一个UUID,value是任意的数据。
跳转前的存储数据和真正的StartActivity都需要使用StorageIntentCenter来进行操作,代码如下:
每个StorageIntentCenter都维护了一个真正跳转的Intent,一个此次跳转的uuid和所有需要传递的数据。
使用方式(以从MainActivity跳转到OtherActivity为例):
MainActivity中:
OtherActivity继承了BaseActivity。
BaseActivity:
Line15:为了防止跳转到OtherActivity后,如果没有去暂存区把数据取出来从而导致暂存区有无用的数据(甚至内存泄漏,暂存区使用软引用也是为了防止这种情况的发生),所以这里提供一个initExtraFromStorage方法让子类重写,子类可以在这个方法中去把数据取出来。然后在initExtraFromStorage方法执行完毕后,再及时把暂存区的数据删除。
Line21~27:这里提供了从暂存区提取数据的方法供子类调用。
OtherActivity:
如上代码OtherActivity中获取了从MainActivity中传递过来的MainActivity实例,在点击事件发生后通过MainActivity实例进行直接回调。
日志打印如下:
MainActivity被回调,并获取了数据“content from ACTestBActivity!”字符串。
注:
1. 以上使用的代码已托管到github:https://github.com/wangjiegulu/AndroidStorageIntent
2. 上面的注解实现使用AndroidInject:https://github.com/wangjiegulu/androidInject
来自天天博客:/article/4917495.html
需求:在ActivityA跳转到ActivityB,然后在ActivityB操作完返回数据给ActivityA。
这个很普遍的需求,一般情况是使用startActivityForResult的方式去完成。
但是当ActivityB为SingleTask时,这个方式就无效了。你会发现当你执行startActivityForResult后,onActivityResult方法马上就会被回调。至于为什么会出现这种情况,参考这位老兄的文章就可以理解/article/2637339.html。
解决这种情况的方法,第一种是把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 StartActivityForResult两个Activity相互跳转传递消息
- Android学习之使用startActivityForResult()和onActivityResult()进行跳转并返回数据
- 使用EventBus代替startActivityForResult向上传递数据
- Android Fragment的使用 七 Argument和startActivityForResult传递数据
- (转)android中使用startActivityForResult回传数据
- android中使用startActivityForResult回传数据
- android中使用startActivityForResult回传数据
- android中使用startActivityForResult回传数据
- android中使用startActivityForResult回传数据
- Android 页面回调跳转(startActivityForResult)
- android中使用startActivityForResult()回传数据
- Android singleTask、startActivityForResult 冲突解决
- android中使用startActivityForResult回传数据(转)
- Android中使用startActivityForResult回传数据
- android中使用startActivityForResult回传数据 或同时销毁几个页面
- android之activity之间共享数据 startActivityForResult
- android中使用startActivityForResult回传数据
- Android TabHost中使用startActivityForResult无法接收返回值的解决方案
- Android中返回数据到前一个Activity — startActivityForResult方法
- android中使用startActivityForResult回传数据