之前开发需求时,需要调用系统相机拍照.并将拍照照片上传服务端.但拍照后死活获取不到返回的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标志