当相机 Activity 返回时,托管此片段的 Activity 会调用其 onActivityResult
。
我的片段启动了一个结果活动,目的是发送给相机拍照。图片应用程序加载正常,拍照并返回。但是,onActivityResult
永远不会被击中。我设置了断点,但没有触发任何东西。片段可以有 onActivityResult
吗?我会这么认为,因为它是一个提供的功能。为什么不触发这个?
ImageView myImage = (ImageView)inflatedView.findViewById(R.id.image);
myImage.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, 1888);
}
});
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if( requestCode == 1888 ) {
Bitmap photo = (Bitmap) data.getExtras().get("data");
((ImageView)inflatedView.findViewById(R.id.image)).setImageBitmap(photo);
}
}
requestCode >= 0
!
托管活动覆盖 onActivityResult()
,但它没有为未处理的结果代码调用 super.onActivityResult()
。显然,即使片段是发出 startActivityForResult()
调用的片段,活动也会首先处理结果。当您考虑片段的模块化时,这是有道理的。一旦我为所有未处理的结果实现了 super.onActivityResult()
,片段就可以处理结果。
还有来自@siqing 的回答:
要在片段中获取结果,请确保在片段中调用 startActivityForResult(intent,111);
而不是 getActivity().startActivityForResult(intent,111);
。
我想你打电话给 getActivity().startActivityForResult(intent,111);
。您应该调用 startActivityForResult(intent,111);
。
PreferenceFragment
的 RingtonePreference
也有同样的问题。不幸的是,RingtonePreference
调用了 getActivity().startActivityForResult()
,即使我在 Activity 的 onActivityResult
中调用了 super.onActivityResult
,我也没有得到结果。我不得不创建一个派生自 RingtonePreference
的类,该类将自身绑定到 PreferenceFragment
并调用 fragment.startActivityForResult()
。
选项1:
如果您从片段调用 startActivityForResult()
,那么您应该调用 startActivityForResult()
,而不是 getActivity().startActivityForResult()
,因为它会导致片段 onActivityResult()。
如果您不确定在 startActivityForResult()
上调用的位置以及调用方法的方式。
选项 2:
由于 Activity 获得 onActivityResult()
的结果,因此您需要覆盖 Activity 的 onActivityResult()
并调用 super.onActivityResult()
以传播到相应的片段以获取未处理的结果代码或全部。
如果以上两个选项都不起作用,那么请参考选项 3,因为它肯定会起作用。
选项 3:
从 fragment 到 onActivityResult 函数的显式调用如下。
在父 Activity 类中,重写 onActivityResult() 方法,甚至在 Fragment 类中重写,并调用如下代码。
在父类中:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.dualPane);
fragment.onActivityResult(requestCode, resultCode, data);
}
在子类中:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// In fragment class callback
}
setResult(); finish();
当我从第二个活动中按下时,onActivityResult
也会被提供的 RESULT_CODE
调用。
onActivityResult()
返回一个奇怪的 requestCode
,它被传递给我的片段然后被忽略 =/
如果您不知道活动中的片段,只需枚举它们并发送活动结果参数:
//Java
// In your activity
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
fragment.onActivityResult(requestCode, resultCode, data);
}
}
//科特林
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
for (fragment in supportFragmentManager.fragments) {
fragment.onActivityResult(requestCode, resultCode, data)
}
}
我在使用 ChildFragmentManager
时遇到了同样的问题。管理器不会将结果传递给嵌套片段,您必须在基本片段中手动执行此操作。
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
Fragment fragment = (Fragment) getChildFragmentManager().findFragmentByTag(childTag);
if (fragment != null) {
fragment.onActivityResult(requestCode, resultCode, intent);
}
}
Fragment fragment = myChildFragment;
替换上面的 findFragmentByTag
行代码。其余的可以保持不变。
FragmentActivity
将 requestCode
替换为修改后的。之后,当 onActivityResult()
将被调用时,FragmentActivity
解析高 16 位并恢复原始 Fragment 的索引。看看这个方案:
https://i.stack.imgur.com/F92yr.png
如果您在根级别有一些片段,则没有问题。但是,如果您有嵌套片段,例如 Fragment
在 ViewPager
中有几个选项卡,您保证会遇到问题(或已经遇到问题)。
因为只有一个索引存储在 requestCode
中。那是其 FragmentManager
内的 Fragment
的索引。当我们使用嵌套片段时,有子 FragmentManager
,它们有自己的片段列表。因此,有必要保存从根 FragmentManager
开始的整个索引链。
https://i.stack.imgur.com/qgcFV.png
我们如何解决此问题? 有常见的解决方法 in this post。
GitHub:https://github.com/shamanland/nested-fragment-issue
这是最受欢迎的问题之一。我们可以找到很多关于这个问题的线程。但它们都对我没有用。
所以我已经使用这个解决方案解决了这个问题。
让我们首先了解为什么会发生这种情况。
我们可以直接从 Fragment 调用 startActivityForResult
,但实际上背后的机制都是由 Activity 处理的。
从 Fragment 调用 startActivityForResult
后,requestCode 将更改为将 Fragment 的身份附加到代码中。这将使 Activity 能够在收到结果后追踪发送此请求的人。
一旦 Activity 被导航回来,结果将被发送到 Activity 的 onActivityResult 以及修改后的 requestCode 将被解码为原始 requestCode + Fragment 的身份。之后,Activity 会通过 onActivityResult 将 Activity Result 发送到该 Fragment。这一切都完成了。
问题是:
Activity 只能将结果发送到直接附加到 Activity 的 Fragment,但不能发送到嵌套的 Fragment。这就是为什么无论如何都不会调用嵌套片段的 onActivityResult 的原因。
解决方案:
1)通过以下代码在您的片段中启动意图:
/** Pass your fragment reference **/
frag.startActivityForResult(intent, REQUEST_CODE); // REQUEST_CODE = 12345
2) 现在在您的父活动覆盖中**onActivityResult()
:**
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
您必须在父活动中调用它才能使其工作。
3)在您的片段调用中:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
}
}
而已。使用此解决方案,它可以应用于任何单个片段,无论它是否嵌套。是的,它也涵盖了所有情况!此外,代码也很干净。
使用 Android Navigation Component 的人应该在 Activity 的 onActivityResult(...)
中使用 primaryNavigationFragment
来获取它的片段引用并调用片段的 fragment.onActivityResult(...)
。
这是 Activity 的 onActivityResult(...)
@Override
public void onActivityResult(int requestCode, int resultCode, Intent imageData)
{
super.onActivityResult(requestCode, resultCode, imageData);
for (Fragment fragment : getSupportFragmentManager().getPrimaryNavigationFragment().getChildFragmentManager().getFragments())
{
fragment.onActivityResult(requestCode, resultCode, imageData);
}
}
对于许多嵌套片段(例如,在片段中使用 ViewPager 时)
在您的主要活动中:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
在您的片段中:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
for (Fragment fragment : getChildFragmentManager().getFragments()) {
fragment.onActivityResult(requestCode, resultCode, data);
}
}
在您的嵌套片段中
通话活动
getParentFragment().startActivityForResult(intent, uniqueInstanceInt);
uniqueInstanceInt - 用嵌套片段中唯一的 int 替换它,以防止另一个片段处理答案。
收到回复
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == uniqueInstanceInt ) {
// TODO your code
}
}
注意力
需要在 uniqueInstanceInt 中使用 0 到 65536 之间的数字以避免错误“只能将低 16 位用于 requestCode”。
当我将这段代码从 Fragment 转移到 Utility Class 时,我也面临同样的问题,parentActivity
作为 argument,
Intent intent = new Intent(parentActivity, CameraCaptureActivity.class);
parentActivity.startActivityForResult(intent,requestCode);
然后我在那个 Fragment 的 onActivityResult
方法中没有得到任何值,之后,我将 argument 更改为 Fragment,所以修改后的定义的方法看起来像,
Intent intent = new Intent(fragment.getContext(), CameraCaptureActivity.class);
fragment.startActivityForResult(intent,requestCode);
之后,我能够在 Fragment 上的 onActivityResult
中获得价值
如果有人仍然无法做到,我可以添加两个建议。在 Manifest.xml 文件中,确保在回调时托管活动未完成,并且要启动的活动以启动模式为标准。请参阅以下详细信息:
对于托管活动,如果有,则将无历史记录属性设置为 false
android:noHistory="false"
对于要启动的 Activity,如果有,请将启动模式设置为标准
android:launchMode="standard"
Kotlin 版本适用于那些使用受 Mohit Mehta 回答启发的 Android 导航组件的人
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
supportFragmentManager.primaryNavigationFragment?.childFragmentManager?.fragments?.forEach { fragment ->
fragment.onActivityResult(requestCode, resultCode, data)
}
}
FOR NESTED FRAGMENTS(例如,当使用 ViewPager 时)
在您的主要活动中:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
在您的主要顶级片段(ViewPager 片段)中:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
YourFragment frag = (YourFragment) getChildFragmentManager().getFragments().get(viewPager.getCurrentItem());
frag.yourMethod(data); // Method for callback in YourFragment
super.onActivityResult(requestCode, resultCode, data);
}
在 YourFragment (嵌套片段)中:
public void yourMethod(Intent data){
// Do whatever you want with your data
}
我也在片段中遇到了这个问题。我在 DialogFragment
中调用了 startActivityForResult
。
但是现在这个问题已经解决了:
FragmentClassname.this.startActivityForResult
。
startActivityForResult(...)
。
就我而言,这是一个 Android 错误 (http://technet.weblineindia.com/mobile/onactivityresult-not-getting-called-in-nested-fragments-android/),如果您使用受支持的 FragmentActivity
,则必须使用 getSupportFragmentManager
而不是 getChildFragmentManager
:
List<Fragment> fragments = getSupportFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
if(fragment instanceof UserProfileFragment) {
fragment.onActivityResult(requestCode, resultCode, data);
}
}
}
简而言之,
在片段中,声明 Fragment fragment = this
;
之后使用 fragment.startActivityForResult
。
结果将在activityResult中返回。
解决方案1:
调用 startActivityForResult(intent, REQUEST_CODE);
而不是 getActivity().startActivityForResult(intent, REQUEST_CODE);
。
解决方案2:
当调用 startActivityForResult(intent, REQUEST_CODE);
时,将调用 Activity 的 onActivityResult(requestCode,resultcode,intent)
,然后您可以从这里调用 fragments onActivityResult()
,并传递 requestCode, resultCode and intent
。
在您的片段中,调用
this.startActivityForResult(intent, REQUEST_CODE);
其中 this
指的是片段。否则按照@Clevester 所说的那样做:
Fragment fragment = this;
....
fragment.startActivityForResult(intent, REQUEST_CODE);
我也不得不打电话
super.onActivityResult(requestCode, resultCode, data);
在父 Activity 的 onActivityResult
中使其工作。
(我根据@Clevester 的回答改编了这个答案。)
使用 Android 的 Navigation 组件,当您嵌套了 Fragments 时,这个问题可能会让人感觉像是一个无法解开的谜团。
根据本文中以下答案的知识和灵感,我设法制定了一个有效的简单解决方案:
在这个帖子里回答
在这个帖子里回答
在您的 Activity 的 onActivityResult()
中,您可以循环访问您使用 FragmentManager
的 getFragments()
方法获得的活动片段列表。
请注意,要执行此操作,您需要使用 getSupportFragmentManager()
或定位 API 26 及更高版本。
这里的想法是使用 instanceof
在列表中循环检查列表中每个 Fragment 的实例类型。
虽然循环浏览此 Fragment
类型的列表是理想的,但不幸的是,当您使用 Android 导航组件时,该列表将只有一项,即 NavHostFragment
。
那么现在怎么办?我们需要让 NavHostFragment
知道 Fragments。 NavHostFragment
本身就是一个片段。因此,使用 getChildFragmentManager().getFragments()
,我们再次获得了 NavHostFragment
已知的 List<Fragment>
个片段。我们遍历该列表,检查每个片段的 instanceof
。
在列表中找到我们感兴趣的 Fragment 后,我们调用它的 onActivityResult()
,将 Activity 的 onActivityResult()
声明的所有参数传递给它。
// 你的活动的 onActivityResult() @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); List
这些答案中的大多数一直说您必须在您的主机 Activity
中为您的 Fragment
调用 super.onActivityResult(...)
。但这似乎对我不起作用。
因此,在您的主机 Activity
中,您应该调用您的 Fragments
onActivityResult(...)
。这是一个例子。
public class HostActivity extends Activity {
private MyFragment myFragment;
protected void onActivityResult(...) {
super.onActivityResult(...);
this.myFragment.onActivityResult(...);
}
}
在您的 HostActivity
中的某个时间点,您需要为 this.myFragment
分配您正在使用的 Fragment
。或者,使用 FragmentManager
获取 Fragment
而不是在 HostActivity
中保留对它的引用。此外,请在尝试调用 this.myFragment.onActivityResult(...);
之前检查 null
。
public class takeimage extends Fragment {
private Uri mImageCaptureUri;
private static final int PICK_FROM_CAMERA = 1;
private static final int PICK_FROM_FILE = 2;
private String mPath;
private ImageView mImageView;
Bitmap bitmap = null;
View view;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.activity_send_image, container, false);
final String[] items = new String[] { "From Camera", "From SD Card" };
mImageView = (ImageView)view.findViewById(R.id.iv_pic);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.select_dialog_item, items);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Select Image");
builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
if (item == 0) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File file = new File(Environment.getExternalStorageDirectory(), "tmp_avatar_"
+ String.valueOf(System.currentTimeMillis())
+ ".jpg");
mImageCaptureUri = Uri.fromFile(file);
try {
intent.putExtra(
android.provider.MediaStore.EXTRA_OUTPUT,
mImageCaptureUri);
intent.putExtra("return-data", true);
getActivity().startActivityForResult(intent,
PICK_FROM_CAMERA);
} catch (Exception e) {
e.printStackTrace();
}
dialog.cancel();
} else {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
getActivity().startActivityForResult(
Intent.createChooser(intent,
"Complete action using"), PICK_FROM_FILE);
}
}
});
final AlertDialog dialog = builder.create();
Button show = (Button) view.findViewById(R.id.btn_choose);
show.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// Switch the tab content to display the list view.
dialog.show();
}
});
return view;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK)
return;
if (requestCode == PICK_FROM_FILE) {
mImageCaptureUri = data.getData();
// mPath = getRealPathFromURI(mImageCaptureUri); //from Gallery
if (mPath == null)
mPath = mImageCaptureUri.getPath(); // from File Manager
if (mPath != null)
bitmap = BitmapFactory.decodeFile(mPath);
} else {
mPath = mImageCaptureUri.getPath();
bitmap = BitmapFactory.decodeFile(mPath);
}
mImageView.setImageBitmap(bitmap);
}
public String getRealPathFromURI(Uri contentUri) {
String [] proj = {MediaStore.Images.Media.DATA};
Cursor cursor = managedQuery(contentUri, proj, null, null,null);
if (cursor == null) return null;
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
}
您可以简单地在片段 baseActivity.startActivityForResult 上覆盖 BaseActivity onActivityResult 。在 BaseActivity 添加接口并覆盖 onActivityResult。私人 OnBaseActivityResult baseActivityResult;公共静态最终 int BASE_RESULT_RCODE = 111;公共接口 OnBaseActivityResult{ void onBaseActivityResult(int requestCode, int resultCode, Intent data); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(getBaseActivityResult() !=null && requestCode == BASE_RESULT_RCODE){ getBaseActivityResult().onBaseActivityResult(requestCode, resultCode, data); setBaseActivityResult(null); } On Fragment 实现 OnBaseActivityResult @Override public void onBaseActivityResult(int requestCode, int resultCode, Intent data) { Log.d("RQ","OnBaseActivityResult"); if (data != null) { Log.d("RQ","OnBaseActivityResult + Data");捆绑参数 = data.getExtras(); } }
这种解决方法可以解决问题。
如果在 Facebook 登录时遇到上述问题,那么您可以在片段的父活动中使用以下代码,例如:
Fragment fragment = getFragmentManager().findFragmentById(android.R.id.tabcontent);
fragment.onActivityResult(requestCode, resultCode, data);
或者:
Fragment fragment = getFragmentManager().findFragmentById("fragment id here");
fragment.onActivityResult(requestCode, resultCode, data);
并在您的片段中添加以下调用...
callbackManager.onActivityResult(requestCode, resultCode, data);
其他答案中尚未描述的另一个用例:
使用 exception.startResolutionForResult()
时不调用片段中声明的 onActivityResult()
:
if (exception is ResolvableApiException) {
exception.startResolutionForResult(activity!!, MY_REQUEST_CODE)
}
在这种情况下,将 exception.startResolutionForResult()
替换为片段的 startIntentSenderForResult()
:
if (exception is ResolvableApiException) {
startIntentSenderForResult(exception.resolution.intentSender, MY_REQUEST_CODE, null, 0, 0, 0, null)
}
Kotlin 版本(在您的活动 onActivityResult() 中)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
//add following lines in your activity
if(supportFragmentManager?.fragments!=null && supportFragmentManager?.fragments!!.size>0)
for (i in 0..supportFragmentManager?.fragments!!.size-1) {
val fragment= supportFragmentManager?.fragments!!.get(i)
fragment.onActivityResult(requestCode, resultCode, data)
}
}
添加这个
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT,MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 1);
}
当你用上面的代码替换你的代码然后自动你的这个
public void onActivityResult(int requestCode, int resultCode,
@Nullable Intent data){}
方法将开始工作
//No Need to write this code in onclick method
Intent intent=new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT)
startActivityForResult(intent,1);
Toast.makeText(getContext(), "image"+intent, Toast.LENGTH_SHORT).show();
正如 Ollie C 所提到的,当您使用嵌套片段时,使用返回值到 onActivityResult 的支持库存在一个活动错误。我刚刚击中它:-(。
请参阅 Fragment.onActivityResult not called when requestCode != 0。
我强烈怀疑这里的所有答案只不过是黑客。我已经尝试了所有这些方法和许多其他方法,但没有任何可靠的结论,因为总是存在某种愚蠢的问题。我不能依赖不一致的结果。如果您查看 Fragments 的官方 Android API 文档,您会看到 Google 清楚地说明了以下内容:
从包含片段的 Activity 调用 startActivityForResult(Intent, int)。
因此,似乎最正确和最可靠的方法是从托管活动中实际调用 startActivityForResult() 并从那里处理生成的 onActivityResult() 。
mActivity.startActivityFromFragment(this, intent, requestCode)
- 所以它只不过是一个方便的包装器
您的代码有一个嵌套片段。调用 super.onActivityForResult 不起作用
您不想修改可以从中调用您的片段的每个活动,或者绕过调用片段链中的每个片段的工作。
这是许多可行的解决方案之一。动态创建一个片段并使用支持片段管理器将其直接连接到活动。然后从新创建的片段中调用 startActivityForResult。
private void get_UserEmail() {
if (view == null) {
return;
}
((TextView) view.findViewById(R.id.tvApplicationUserName))
.setText("Searching device for user accounts...");
final FragmentManager fragManager = getActivity().getSupportFragmentManager();
Fragment f = new Fragment() {
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
startActivityForResult(AccountPicker.newChooseAccountIntent(null, null,
new String[]{"com.google"}, false, null, null, null, null), REQUEST_CODE_PICK_ACCOUNT);
}
@Override
public void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (requestCode == REQUEST_CODE_PICK_ACCOUNT) {
String mEmail = "";
if (resultCode == Activity.RESULT_OK) {
if (data.hasExtra(AccountManager.KEY_ACCOUNT_NAME)) {
mEmail = data
.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
}
}
if (mActivity != null) {
GoPreferences.putString(mActivity, SettingApplication.USER_EMAIL, mEmail);
}
doUser();
}
super.onActivityResult(requestCode, resultCode, data);
fragManager.beginTransaction().remove(this).commit();
}
};
FragmentTransaction fragmentTransaction = fragManager
.beginTransaction();
fragmentTransaction.add(f, "xx" + REQUEST_CODE_PICK_ACCOUNT);
fragmentTransaction.commit();
}
我的问题是主机活动,我用一组 android:launchMode="standard"
找到了它,我暂时删除了它,它可以工作!
不定期副业成功案例分享
getParentFragment().startActivityForResult
,以便父片段将调用其 onActivityResult 方法。