您好,登錄后才能下訂單哦!
最近幾天在做文件上傳的時候,想在自定義Adapter中啟動activity時也返回Intent數據,于是想到了用startActivityForResult,可是用mContext怎么也調不出這個方法,只能調用startActivity這個方法,于是在網上搜一下,可以利用一個方式可以間接的解決這個問題,果斷貼代碼:
Intent mIntent = new Intent(mContext,clazz); |
可以在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, Parcel data = Parcel.obtain(); //看這句代碼就夠了,上邊的不是關心重點 |
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中定義的局部方法而已,到此本文分析結束,由于本人第一次用源碼的方式分析文章,其中難免有遺漏或不當之處,如果大家發現了請提出來一起探討,一起學習,謝謝。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。