`
ch_kexin
  • 浏览: 897638 次
  • 性别: Icon_minigender_2
  • 来自: 青岛
社区版块
存档分类
最新评论

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

 
阅读更多

需求:在ActivityA跳转到ActivityB,然后在ActivityB操作完返回数据给ActivityA。

这个很普遍的需求,一般情况是使用startActivityForResult的方式去完成。

但是当ActivityB为SingleTask时,这个方式就无效了。你会发现当你执行startActivityForResult后,onActivityResult方法马上就会被回调。至于为什么会出现这种情况,参考这位老兄的文章就可以理解

http://ch-kexin.iteye.com/blog/2398000

解决这种情况的方法,第一种是把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跳转是Android开发中不可或缺的部分,理解Intent、启动模式以及返回结果的处理对于构建复杂的Android应用至关重要。通过熟练掌握这些知识点,开发者可以更自如地控制应用的导航流程,为用户提供更好的...

    Android应用源码之(Activity跳转与操作).zip

    Activity跳转与操作是Android开发者必须掌握的关键技能,涉及到Intent、生命周期、数据传递等多个方面。本资源“Android应用源码之(Activity跳转与操作).zip”包含了关于这些主题的实例代码,下面将详细解释这些知识...

    Android Activity跳转与操作Demo源码.rar

    在进行Activity跳转时,我们通常会创建一个Intent,并通过startActivity()或startActivityForResult()方法启动目标Activity。Intent可以携带数据,例如通过putExtra()方法传递键值对,接收方Activity则通过getExtras...

    Android 开发Activity基础 启动和跳转并传递参数

    三、跳转Activity 启动Intent后,需调用startActivity()方法进行跳转: ```java context.startActivity(intent); ``` 如果需要在新的Activity启动后关闭当前Activity,可以使用startActivityForResult(),并在...

    Android Activity之间的跳转

    三、传递数据 1. 通过Intent的putExtra()和getExtra():可以将简单类型的数据(如字符串、整型、布尔值等)附加到Intent中,然后在目标Activity中通过getExtra()获取。 2. 使用Parcelable或Serializable接口:对于...

    安卓Android源码——(Activity跳转与操作).zip

    这个压缩包文件“安卓Android源码——(Activity跳转与操作).zip”显然专注于讲解如何在Android系统中进行Activity的跳转和操作。以下是关于这个主题的详细知识点: 一、Activity生命周期 1. Activity有七个关键状态...

    android开发activity跳转

    "Android开发Activity跳转"是Android编程中的一个核心概念,对于初学者来说至关重要。理解并熟练掌握Activity间的跳转机制,能帮助开发者构建功能丰富的应用程序。 在Android中,Activity之间的跳转通常通过Intent...

    Android应用源码之(Activity跳转与操作)-IT计算机-毕业设计.zip

    Activity跳转与操作是Android开发者必须掌握的关键技能,这在给定的“Android应用源码之(Activity跳转与操作)”中得到了深入的演示。这份源码资源对于毕业生进行Android项目的实践学习具有很高的参考价值。 一、...

    android Activity 详述 demo

    在"ActivityDemo"项目中,开发者通常会创建一系列示例Activity,展示上述各个知识点的实际应用,包括生命周期调试、启动模式的实验、Intent传递数据的演示等。通过这样的实践,开发者能更好地理解和掌握Android ...

    android activity互相调用 操作数据库

    - **startActivity()和startActivityForResult()**:startActivity()常用于无返回结果的跳转,而startActivityForResult()则用于需要返回结果的情况,比如用户在新Activity中完成操作后返回主Activity,结果会通过...

    实现Activity之间跳转

    如果需要传递数据,可以在Intent中添加额外的数据,然后在目标Activity中通过getIntent()获取。 ```java // 添加数据 intent.putExtra("key", "value"); // 在目标Activity中获取数据 String value = ...

    ACTIVITY的跳转

    一、Intent:Activity跳转的桥梁 Intent是Android系统中的一个关键概念,它是启动或通信的意图声明。在Activity间跳转时,Intent起到了桥梁的作用,用于传递启动新Activity的信息。Intent有两种类型:显式Intent和...

    activity之间的数据传递(SeekBaar版)

    本教程将深入探讨如何在两个Activity之间传递数据,特别是通过SeekBaar(滑动条)进行数据传输。首先,我们要理解Activity的启动模式以及Intent在数据传递中的角色。 1. **Activity启动模式**: - **Standard**:...

    四个Activity的跳转

    总结,"四个Activity的跳转"实例涵盖了Android开发中Activity间的基本交互,包括Intent的使用、Activity的启动和关闭,以及数据的传递和返回。对于初学者来说,这是一个很好的起点,有助于理解Android应用的基本架构...

    android实现页面跳转

    本篇将深入讲解如何利用Intent这一核心组件来实现在不同Activity(Android应用程序的基本组成单元)之间的跳转。 Intent在Android中扮演着消息传递者的角色,它可以理解为一个意图,表达了应用程序想要执行的动作...

    Android的界面跳转

    总结,Android界面跳转是通过Intent在Activity之间传递信息,结合不同的启动模式,实现用户在应用中的导航。理解并熟练掌握这些机制,对于开发高效且用户体验良好的Android应用至关重要。在实际项目中,我们还需要...

    Activity之间的调用

    Activity之间的调用是Android应用中常见的功能,用于实现不同界面间的跳转和数据传递。本主题将深入讲解Activity之间的调用机制以及Intent在其中的作用。 一、Activity的启动模式 Activity的启动模式分为四种:...

    Android中页面跳转

    如果需要传递数据,可以在Intent中添加额外的数据,然后在目标Activity中通过getIntent()获取: ```java // 在SourceActivity中设置数据 intent.putExtra("key", "value"); // 在TargetActivity中获取数据 String ...

    ViewPager加载Activity

    由于我们不再依赖于onActivityResult()来传递数据,所以可能需要使用其他机制,如Intent的Extra或者自定义的EventBus库来实现数据通信。 最后,考虑到性能和用户体验,我们应确保每个Activity在不被展示时能有效地...

    android各种页面跳转实例

    本教程将深入探讨“android各种页面跳转实例”,旨在帮助开发者掌握不同类型的页面跳转方法,确保用户在应用中的顺畅体验。下面我们将详细讨论以下几个关键知识点: 1. **Intent**: Intent是Android中用于启动活动...

Global site tag (gtag.js) - Google Analytics