最近幾天在做文件上傳的時候,想在自定義Adapter中啓動activity時也返回Intent數據,於是想到了用startActivityForResult,可是用mContext怎麼也調不出這個方法,只能調用startActivity這個方法,於是在網上搜一下,可以利用一個方式可以間接的解決這個問題,果斷貼代碼:
Intent mIntent = new Intent(mContext,clazz);
((Activity) mContext).startActivityForResult(mIntent, requestCode);
可以在Activity中定義一個方法,在adapter中調用,這是我在網上看見的原話。
可是adapter中是不可以調用onActivityResult的,因爲我是需要能在文件上傳到文件服務器後返回一個fileId,並將該fileId一起上傳到數據服務器;起初想用interface的方式進行回調返回值,可試了一下沒有達到我想要的效果,再加上返回頁面後我需要更新數據,爲什麼要這樣想呢?因爲我只是想更新一個Item的數據,不想回到Activity調用notifyDataSetChanged這個方法,畢竟這個方法是所有的數據都會去遍歷一遍,這樣做有點浪費了。可事實上我還是這樣做了!此問題不是今天的核心,今天先看看爲什麼在Adapter中不能直接調用此方法呢?
先看看startActivity方法:
@Override
public void startActivity(Intent intent) {
startActivityForResult(intent, -1);
}
startActivity方法中其實直接調用的就是startActivityForResult方法,此時我們繼續跟進看看startActivityForResult方法:
public void startActivityForResult(Intent intent, int requestCode) {
if (mParent == null) {
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
}
} else {
mParent.startActivityFromChild(this, intent, requestCode);
}
}
在這裏我們看見了intent是在execStartActivity方法中執行的,於是我們繼續窺探一下:
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
if (am.match(who, null, intent)) {
am.mHits++;
if (am.isBlocking()) {
return requestCode >= 0 ? am.getResult() : null;
}
break;
}
}
}
}
try {
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
null, 0, token, target != null ? target.mEmbeddedID : null,
requestCode, false, false);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
}
return null;
}
到這裏我們纔看出來我們真正啓動的activity是在這裏,是ActivityManagerNative.getDefault()..startActivity(),我想看到這裏你肯定還不甘心吧,那我們繼續看看這是啥玩意兒:
public int startActivity(IApplicationThread caller, Intent intent,
String resolvedType, Uri[] grantedUriPermissions, int grantedMode,
IBinder resultTo, String resultWho,
int requestCode, boolean onlyIfNeeded,
boolean debug) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeTypedArray(grantedUriPermissions, 0);
data.writeInt(grantedMode);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(onlyIfNeeded ? 1 : 0);
data.writeInt(debug ? 1 : 0);
//看這句代碼就夠了,上邊的不是關心重點
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
mRemote.transact方法實際是調用proxy中的Ontransact方法:
public boolean onTransact(int code, Parcel data, Parcel reply, int flags){
…… //代碼太多直接省略
int res = startActivityLocked(caller, intent, resolvedType,
grantedUriPermissions, grantedMode, aInfo,
resultTo, resultWho, requestCode, -1, -1,
onlyIfNeeded, componentSpecified);
}
startActivityLocked實際調用ApplicationThread中scheduleLaunchActivity:
public final void scheduleLaunchActivity(Intent intent, IBinder token,
ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) {
……//省略代碼
queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
}
此時queueOrSendMessage發消息給ActivityThread 的Handler,然後 handleLaunchActivity(r)執行performLaunchActivity:
private final Activity performLaunchActivity(ActivityRecord r) {
……//省略代碼
mInstrumentation.callActivityOnCreate(activity, r.state);
return activity;
}
最後我們完整的看見了我們所啓動的那個activity了,繞了半天這不就是activity的啓動過程嗎?不錯,就是activity的啓動過程,其實我們剛纔要解決的問題回頭看看是在哪裏跟丟了?
其實第一步的時候就跟丟了,只因爲那時候吸引我們的是activity的啓動過程,路邊的風景實在太迷人,有沒有看見startActivity的頭部有這個東西@Override,有他我們就找往上找:
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}
這是抽象類ContextWrapper中的方法,此時還是看見這個@Override東東和 mBase.startActivity,那麼說明還不是這裏,繼續:
public abstract void startActivity(Intent intent);
呵呵,這裏就是他的老巢了,這是在哪裏呢?這是我們天天都看見的Context類,所以這一下我們就明白爲什麼Context可以調用startActivity而不可以調用startActivityForResult了,startActivityForResult只是Activity中定義的局部方法而已,到此本文分析結束,由於本人第一次用源碼的方式分析文章,其中難免有遺漏或不當之處,如果大家發現了請提出來一起探討,一起學習,謝謝。
你可以在adapter裏面用傳進來的context去調用startActivityForResult,
((Activity) mContext).startActivityForResult(mIntent, requestCode);
但是你要在建立adapter的activity去複寫onActivityResult()那個方法,然後在此方法裏進行處理(通過 EventBus 或 藉口回調等方法)