android用代理實現Rx方式獲取startActivityForResult結果
昨天,在整理程式碼的時候發現onActivityResult方法真的好煩,太影響程式碼的閱讀了,而且編寫的時候也需要到處切code位置。於是就有了這篇部落格和RxActivityResult 這個庫。
大概的呼叫方式就是這樣的
RxActivityResult.with(MainActivity.this).putString("key", "笑一個")
.startActivityWithResult(new Intent(MainActivity.this, SecondActivity.class))
.subscribe(new Consumer<Intent>() {
@Override
public void accept(Intent intent) throws Exception {
tv.setText(intent.getStringExtra("msg"));
}
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
原始碼大家直接到連結看好了,這篇部落格主要是聊聊思路
要想完全告別onActivityResult(),有兩種方案
1、使用程序注入的方式hook系統的activity資料傳送,這種方案比較複雜,用到ndk知識,需要在原始碼下編譯應用,不適合大部分人。
2、利用代理進行跳轉事件轉發代理和 onActivityResult()事件代理接收後再通知委託者。
這裡我們用第二種,代理物件有兩個供選擇,一個是activity,每次startActivityForResult的時候開啟的使我們的代理activity(ProxyActivity),然後由ProxyActivity進行轉發intent,並在ProxyActivity裡進行 onActivityResult()事件處理,然後通知委託者;所以我們需要在manifest進行註冊,並且需要合理的管理activity的堆疊。
一個是利用Fragment,這就需要將Fragment載入到activity上,否則發起intent的時候會報 not attach activity 異常,再一個就是需要相容v4和app兩種情況,當然,如果大家的專案裡的基類是固定的一種就不需要了。
下面我們來看看具體實現方式
首先構建一個請求容器物件,用來存放被轉發的intent和請求識別碼
public class Request {
Intent intent;
int code;
public Request(Intent intent, int code) {
this.intent = intent;
this.code = code;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
再構建一個結果容器物件,用來存放onActivityResult返回的結果和請求識別碼
public class Result {
Intent intent;
public Result(Intent intent, int code) {
this.intent = intent;
this.code = code;
}
int code;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
然後我們的返回結果是要以RxJava的方式傳遞給委託者的。這裡我們可以參考rxbus的實現方式
構建一個subject
static PublishSubject<Result> subject = PublishSubject.create();
- 1
- 1
然後我們需要把Fragment載入到Activity上,這就需要有一個介面控制元件ID和一個FragmentManager,FragmentManager我們可以從委託者獲取,根據activity和fragmentActivity的不同決定獲取不同的FragmentManager,這個控制元件ID怎麼來呢?熟悉Android原始碼的同學可能就知道了,每個介面的根佈局其實都是同一個系統ID(android.R.id.content)這個ID其實可以用來做很多事,比如透明狀態列時軟鍵盤不頂起佈局的時候可以用來強制位移佈局,或者自己做偽分屏。
接下來就是建立一個代理fragment並且把請求委託給它
final Request request = new Request(intent, intent.hashCode());
final V4Fragment v4Fragment = new V4Fragment();
v4Fragment.setRequest(request);
v4Transaction.replace(android.R.id.content, v4Fragment)
.commitAllowingStateLoss();
v4Transaction = null;
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
這裡的請求識別碼我們直接通過求intent的hash值來得到。
在代理fragment裡進行轉發intent和轉發返回結果操作
public class V4Fragment extends Fragment {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
if (request != null) {
RxActivityResult.post(new Result(data, request.code));
}
request = null;
this.getActivity().getSupportFragmentManager().beginTransaction().detach(this).commit();
}
super.onActivityResult(requestCode, resultCode, data);
}
Request request;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (request != null) {
Intent intent = request.intent;
startActivityForResult(intent, 0);
}
}
public void setRequest(Request request) {
this.request = request;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
通過subject進行傳送
protected static void post(Result result) {
if (result.intent != null) {
subject.onNext(result);
} else {
subject.onError(new Exception("intent is null"));
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
根據請求識別碼進行篩選
return subject.filter(new Predicate<Result>() {
@Override
public boolean test(Result result) throws Exception {
return request.code == result.code;
}
}).map(new Function<Result, Intent>() {
@Override
public Intent apply(Result result) throws Exception {
return result.intent;
}
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
這樣就得到了委託者所需要的返回結果了。