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 或 借口回调等方法)
  • 相关阅读:
    1075: 聚餐人数统计
    1074: 百钱买百鸡
    1072: 青蛙爬井
    1073: 级数求和
    1071: 分解质因子
    1070: 小汽车的位置
    1068: 二进制数
    2019 牛客多校 第六场
    2019 牛客多校 第五场
    2019 牛客多校 第二场
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/9046346.html
Copyright © 2011-2022 走看看