自定义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中实现startActivityForResult的分析,布布扣,bubuko.com

时间: 2024-08-09 16:32:49

自定义Adapter中实现startActivityForResult的分析的相关文章

自定义Adapter中getView( )中使用View.setTag()和不使用的区别。

首先来看使用Tag的情况. @Override public View getView(int position, View view, ViewGroup group) { ViewHolder holder = new ViewHolder(); if(view==null){ view = inflater.inflate(R.layout.note_list_item, null);//加载列表项的布局文件. holder.title = (TextView)view.findViewB

自定义adapter的基础上Listview优化方案以及几个小错误(checkbox吃掉点击事件以及对象重复问题)

每次adapter运行都有一个getcount,有多少条就调用多少次getview,就会解析多少次xml文件(创建view,条数多了很消耗时间),13年谷歌提出了一个机制,每次只缓存一屏幕多几个,把划出屏幕外的listview回收(用的convertView),只要修改里面的值就可以重新用不用再创建一个view 修改的是自定义adapter中的getview方法 @Overridepublic View getView(int position, View convertView, ViewGr

自定义Adapter及其实例

Android界面中有时候需要显示稍微复杂的界面时,就需要我们自定义一个adapter,而此adapter就要继承BaseAdapter,重新其中的方法. Android中Adapter类其实就是把数据源绑定到指定的View上,然后再返回该View,而返回来的这个View就是ListView中的某一行item.这里返回来的View正是由我们的Adapter中的getView方法返回的.这样就会容易理解数据是怎样一条一条显示在ListView中的. 在完成这篇文章中的例子之后,我思考了很长时间,关

android 自定义adapter和线程结合 + ListView中按钮滑动后状态丢失解决办法

adapter+线程 1.很多时候自定义adapter的数据都是来源于服务器的,所以在获取服务器的时候就需要异步获取,这里就需要开线程了(线程池)去获取服务器的数据了.但这样有的时候adapter的中没有数据. 如下面的代码: 这就是在initData中异步获取服务器的数据,然后实例化adatper,再将adapter赋给listView. 2.initData()中的代码是: 这里线程要睡眠5秒钟,是为了模仿网络的耗时操作 3.Handler: 在Handler中接收到数据后给list赋值后,

【转】Android中Spinner下拉列表(使用ArrayAdapter和自定义Adapter实现)

原文网址:http://embed.21ic.com/software/android/201403/31603.html 1 :Android中Spinner下拉列表(使用ArrayAdapter和自定义Adapter实现) . 今天学习了Spinner组件,使用Spinner相当于从下拉列表中选择项目,下面演示一下Spinner的使用(分别使用ArrayAdapter和自定义Adapter实现) (一):使用ArrayAdapter进行适配数据: ①:首先定义一个布局文件: android:

Binder AIDL中自定义类型传递的源码分析

binder机制实现的IPC和共享内存的方式不同,它采取的是值拷贝的方式,即进程间传递的实体遵循Parcelable协议, Bp端负责向Parcel里写东西,Bn端负责从Parcel里读取还原,顺序是双方约定的.原型如下,Bp/Bn端收到的其实 都只是彼此的clone. Aidl(Android Interface Definition Language)简化了binder的使用,做了大量封装 但Aidl默认支持的类型包括Java 原始类型(如int.long.boolean等) 和 基础封装类

ListView中使用自定义Adapter及时更xin

在项目中,遇到不能ListView及时更新的问题.写了一个demo,其中也遇到一些问题,一并写出来.好吧,上代码: public class PersonAdapter extends BaseAdapter { private ArrayList<PersonBean> mList; private Context mContext; public PersonAdapter(ArrayList<PersonBean> list, Context context) { mList

Android中的普通对话框、单选对话框、多选对话框、带Icon的对话框、以及自定义Adapter和自定义View对话框详解

对话框就是一个AlertDialog,但是一个简单的AlertDialog,我们却可以将它玩出许多花样来,下面我们就来一起总结一下AlertDialog的用法.看看各位童鞋在平时的工作中否都用到了AlertDialog的这些特性. OK,废话不多说,进入我们今天的正题. 普通对话框 普通对话框就是我们最最常用的对话框,实现起来并不复杂,实现出来的效果当然也是最简单的,如下: AlertDialog dialog = new AlertDialog.Builder(this).setTitle("

Android中Spinner下拉列表(使用ArrayAdapter和自定义Adapter实现)

public class MySpinnerActivity extends Activity { private Spinner spinner; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); spinner = (Spinner)findViewById(R.id