zoukankan      html  css  js  c++  java
  • Android 自定义Adapter中实现startActivityForResult的分析

    最近几天在做文件上传的时候,想在自定义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 或 借口回调等方法)
  • 相关阅读:
    CodeForces gym Nasta Rabbara lct
    bzoj 4025 二分图 lct
    CodeForces 785E Anton and Permutation
    bzoj 3669 魔法森林
    模板汇总——快读 fread
    bzoj2049 Cave 洞穴勘测 lct
    bzoj 2002 弹飞绵羊 lct裸题
    HDU 6394 Tree 分块 || lct
    HDU 6364 Ringland
    nyoj221_Tree_subsequent_traversal
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/9046346.html
Copyright © 2011-2022 走看看