一个关于startActivityForResult的小问题

之前开发需求时,需要调用系统相机拍照.并将拍照照片上传服务端.但拍照后死活获取不到返回的result.

	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (requestCode == CAMERA_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
			if (mCurrentCameraFile != null && mCurrentCameraFile.exists()) {
				....
				Log.v( TAG,"onActivityResult get pic success ");
				//通知MediaScan进行扫描添加数据库
				BitmapUtils.notifyAddPictureToSDCard(mContext, mCurrentCameraFile);
			}
		}
	}
怎么都不打印日志:onActivityResult get pic success.这里我打印日志比较片面,仅打印了成功的日志....

为了这个破问题折腾了好几个小时.太菜了呃...

         首先上传调用相机的代码

<span style="white-space:pre">	</span>mCurrentCameraFile = Utils.getOutputMediaFile();
	Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        Uri outputFileUri = Uri.fromFile(mCurrentCameraFile);
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
	cameraIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
	mParentFragment.startActivityForResult(cameraIntent, CAMERA_REQUEST_CODE);
        无意中发现,只要去掉cameraIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)这一行,就立马可以得到正确的ActivityResult了.为啥啊?不就是新起一个栈来启动相机吗?

直接看看startActivity的源码怎么对这个FLAG_ACTIVITY_NEW_TASK怎么处理的吧,源码位于(android4.4.2)frameworks\base\services\java\com\android\server\am\ActivityStackSupervisor.java


final int startActivityUncheckedLocked(ActivityRecord r,
            ActivityRecord sourceRecord, int startFlags, boolean doResume,
            Bundle options) {
        final Intent intent = r.intent;
        final int callingUid = r.launchedFromUid;

        int launchFlags = intent.getFlags();

        ...

        if (sourceRecord == null) {
            // This activity is not being started from another...  in this
            // case we -always- start a new task.
            if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
                Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
                        "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
                <span style="color:#ff0000;">launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;</span>
            }
        } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
            // The original activity who is starting us is running as a single
            // instance...  this new activity it is starting must go on its
            // own task.
            <span style="color:#ff0000;">launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;</span>
        } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
                || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
            // The activity being started is a single instance...  it always
            // gets launched into its own task.
            <span style="color:#ff0000;">launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;</span>
        }

        ActivityInfo newTaskInfo = null;
        Intent newTaskIntent = null;
        final ActivityStack sourceStack;
        if (sourceRecord != null) {
            if (sourceRecord.finishing) {
                // If the source is finishing, we can't further count it as our source.  This
                // is because the task it is associated with may now be empty and on its way out,
                // so we don't want to blindly throw it in to that task.  Instead we will take
                // the NEW_TASK flow and try to find a task for it. But save the task information
                // so it can be used when creating the new task.
                if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
                    Slog.w(TAG, "startActivity called from finishing " + sourceRecord
                            + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
                    <span style="color:#ff0000;">launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;</span>
                    newTaskInfo = sourceRecord.info;
                    newTaskIntent = sourceRecord.task.intent;
                }
                sourceRecord = null;
                sourceStack = null;
            } else {
                sourceStack = sourceRecord.task.stack;
            }
        } else {
            sourceStack = null;
        }

        if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
            // For whatever reason this activity is being launched into a new
            // task...  yet the caller has requested a result back.  Well, that
            // is pretty messed up, so instead immediately send back a cancel
            // and let the new task continue launched as normal without a
            // dependency on its originator.
            Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
            <span style="color:#ff0000;">r.resultTo.task.stack.sendActivityResultLocked(-1,
                    r.resultTo, r.resultWho, r.requestCode,
                Activity.RESULT_CANCELED, null);</span>
            r.resultTo = null;
        }

        .....

        if (newTask) {
            EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
        }
        ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
        targetStack.mLastPausedActivity = null;
        <span style="color:#ff0000;">targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);</span>
        mService.setFocusedActivityLocked(r);
        return ActivityManager.START_SUCCESS;
    }

上面的startActivityUncheckedLocked()方法我主要截取了前面对FLAG_ACTIVITY_NEW_TASK的处理.

1.对于一下场景,都会对intent的FLAG_ACTIVITY_NEW_TASK标志位置1.

(1)sourceRecord为空,即执行startActivity的哪个ActvityRecord为空;

                (2)sourceRecord.launchMode为ActivityInfo.LAUNCH_SINGLE_INSTANCE;

                (3)待启动的新ActivityRecord的launchMode为LAUNCH_SINGLE_INSTANCE或者LAUNCH_SINGLE_TASK;

2.若需要返回result,且intent的FLAG_ACTIVITY_NEW_TASK标志位为1,则首先给ResultToActivity一个RESULT_CANCELED(即-1)结果.这个逻辑比较简单,直接让ActivityThread来分发onActivityResult()

        3.初始化好目标targetStack后,继续执行startActivity,具体可以参见老罗的android之旅Android应用程序内部启动Activity过程(startActivity)的源代码分析.


通过上面startActivityUncheckedLocked()方法的分析,直到只要设置了FLAG_ACTIVITY_NEW_TASK,源Activity就会收到RESULT_CANCELED结果回调.下面用demo测试下.

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		Log.e("onActivityResult ", "requestCode:" + requestCode + "resultCode:" + resultCode + ",data" + data);
		
		Toast.makeText(this, "onActivityResult resultCode " + resultCode, Toast.LENGTH_SHORT).show();
		super.onActivityResult(requestCode, resultCode, data);
	}
	public static final int CAMERA_REQUEST_CODE = 111;
	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.btn1:
			Intent intent = getContentProviderActivityIntent();
			intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			if (intent != null) {
				startActivityForResult(intent, CAMERA_REQUEST_CODE);
			}
			break;
		case R.id.btn2:
			Intent intent1 = getContentProviderActivityIntent();
			if (intent1 != null) {
				startActivityForResult(intent1, CAMERA_REQUEST_CODE);
			}
			break;
		}
	}
	private File mCurrentCameraFile;
	public Intent getContentProviderActivityIntent() {
		mCurrentCameraFile = getOutputMediaFile();
		if (mCurrentCameraFile != null) {
			return getCameraAppIntent(mCurrentCameraFile);
		} else {
			return null;
		}
	}
	
	public static Intent getCameraAppIntent(File outFile) {
		Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        Uri outputFileUri = Uri.fromFile(outFile);
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
		return cameraIntent;
	}
	public static File getOutputMediaFile() {
		File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "Camera");

		if (!mediaStorageDir.exists()) {
			if (!mediaStorageDir.mkdirs()) {
				return null;
			}
		}

		// Create a media file name
		String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(new Date());
		File mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
		return mediaFile;
	}


两个按钮,分别为添加和不添加FLAG_ACTIVITY_NEW_TASK标志.打印日志如下:

btn1:在相机页面还没起来前就打印了:12-31 09:51:39.566: E/onActivityResult(20938): requestCode:111resultCode:0,datanull

btn2:在相机页面结束后才打印了:12-31 09:53:01.880: E/onActivityResult(20938): requestCode:111resultCode:-1,datanull


就这样了,startActivityForResult时不能设置FLAG_ACTIVITY_NEW_TASK标志

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值