首页 > 代码库 > 自定义Adapter中实现startActivityForResult的分析
自定义Adapter中实现startActivityForResult的分析
最近几天在做文件上传的时候,想在自定义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 = http://www.mamicode.com/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中定义的局部方法而已,到此本文分析结束,由于本人第一次用源码的方式分析文章,其中难免有遗漏或不当之处,如果大家发现了请提出来一起探讨,一起学习,谢谢。
本文出自 “吸博取精自我更新” 博客,请务必保留此出处http://wyong.blog.51cto.com/1115465/1429982