[Android]Activity跳轉傳遞任意類型的數據、Activity為SingleTask時代替StartActivityForResult的解決方案


以下內容為原創,歡迎轉載,轉載請注明

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM