Android中向已存在Fragment回传数据失败的问题求助
Android Fragment 数据回传问题
导航流程:ThirdFragment(fragment1)→ PickedImageFragment(fragment2)→ ThirdFragment(fragment1),需先从ThirdFragment向PickedImageFragment传递数据,用户完成补充后再将完整数据回传给ThirdFragment。
目前从ThirdFragment向PickedImageFragment传递数据的代码可正常运行:
// 封装图片URI Bundle bundle = new Bundle(); bundle.putString("imageURI", result.toString()); // 跳转到图片展示页面并传递URI NavController navController = Navigation.findNavController(view); navController.navigate(R.id.pickedImageFragment, bundle);
但从PickedImageFragment回传数据至ThirdFragment的代码无法正常工作:
// 创建Image对象 String photoName = binding.photoDescription.getText().toString().trim(); String imageID = UUID.randomUUID().toString(); Image myImage = new Image(imageID, photoName, imageUri); // 用Gson序列化 Gson gson = new Gson(); Bundle bundle = new Bundle(); bundle.putString("IMAGE", gson.toJson(myImage)); // 跳转回ThirdFragment并传参 NavController navController = Navigation.findNavController(view); navController.navigate(R.id.ThirdFragment, bundle);
ThirdFragment的接收代码:
Gson gson = new Gson(); if (gson.fromJson(requireArguments().getString("IMAGE"), Image.class) != null) { Image myImage = gson.fromJson(requireArguments().getString("IMAGE"), Image.class); Log.d("test", myImage.getImageName()); Log.d("test", myImage.getId()); Log.d("test", myImage.getPhoto().toString()); }
已尝试让Image类实现Serializable接口,但无效。以下是完整代码:
ThirdFragment 代码
package com.example.briefingaboutitapp; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.Toast; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.navigation.NavController; import androidx.navigation.Navigation; import androidx.navigation.fragment.NavHostFragment; import com.example.briefingaboutitapp.databinding.FragmentThirdBinding; import com.google.gson.Gson; import Entities.Image; public class ThirdFragment extends Fragment { private FragmentThirdBinding binding; private ActivityResultLauncher<String> galleryLauncher; @Override public View onCreateView( @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) { binding = FragmentThirdBinding.inflate(inflater, container, false); return binding.getRoot(); } public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); try { Gson gson = new Gson(); if (gson.fromJson(requireArguments().getString("IMAGE"), Image.class) != null) { Image myImage = gson.fromJson(requireArguments().getString("IMAGE"), Image.class); Log.d("test", myImage.getImageName()); Log.d("test", myImage.getId()); Log.d("test", myImage.getPhoto().toString()); } } catch (Exception e){ Log.d("test", "image still null"); } binding.returnToEditText.setOnClickListener(view1 -> NavHostFragment.findNavController(ThirdFragment.this) .navigate(R.id.action_ThirdFragment_to_SecondFragment)); Button photoPickerButton = view.findViewById(R.id.photo_picker_button); galleryLauncher = registerForActivityResult(new ActivityResultContracts.GetContent(), result -> { if(result!= null){ //package image uri Bundle bundle = new Bundle(); bundle.putString("imageURI", result.toString()); //navigate to image display and set title with parceled uri NavController navController = Navigation.findNavController(view); navController.navigate(R.id.pickedImageFragment, bundle); } else{ Toast.makeText(getContext(), "Please select an image!", Toast.LENGTH_SHORT).show(); } }); photoPickerButton.setOnClickListener(view12 -> galleryLauncher.launch("image/*")); binding.submitForm.setOnClickListener(view1 -> { Intent goToMainActivity = new Intent(getContext(), MainActivity.class); this.startActivity(goToMainActivity); Toast.makeText(this.getContext(),"Article submitted successfully!",Toast.LENGTH_SHORT).show(); }); } @Override public void onDestroyView() { super.onDestroyView(); binding = null; } }
PickedImageFragment 代码
package com.example.briefingaboutitapp; import android.net.Uri; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.navigation.NavController; import androidx.navigation.Navigation; import com.example.briefingaboutitapp.databinding.FragmentPickedImageBinding; import com.google.gson.Gson; import java.util.UUID; import Entities.Image; public class PickedImageFragment extends Fragment { private FragmentPickedImageBinding binding; private Uri imageUri; @Override public View onCreateView( @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) { binding = FragmentPickedImageBinding.inflate(inflater, container, false); return binding.getRoot(); } public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); this.imageUri = Uri.parse(requireArguments().getString("imageURI")); //get passed image ImageView imageView = view.findViewById(R.id.image_view); imageView.setImageURI(this.imageUri); binding.submitMyPhotoButton.setOnClickListener(view1 -> { if(binding.photoDescription.getText().toString().trim().equals("")){ Toast.makeText(getContext(), "Pick title/description for photo!", Toast.LENGTH_SHORT).show(); } else{ //create the gotten image class String photoName = binding.photoDescription.getText().toString().trim(); String imageID = UUID.randomUUID().toString(); Image myImage = new Image(imageID, photoName, imageUri); //bundle it Gson gson = new Gson(); Bundle bundle = new Bundle(); bundle.putString("IMAGE", gson.toJson(myImage)); //send the bundled image on it's way NavController navController = Navigation.findNavController(view); navController.navigate(R.id.ThirdFragment, bundle); } }); } @Override public void onDestroyView() { super.onDestroyView(); binding = null; } }
Image 实体类代码
package Entities; import android.net.Uri; import java.io.Serializable; public class Image implements Serializable{ private final String id; private final Uri photo; private final String imageName; public Image(String id, String imageName, Uri photo) { this.id = id; this.imageName = imageName; this.photo = photo; } public Uri getPhoto() { return photo; } public String getImageName() { return imageName; } public String getId() { return id; } }
问题原因及修复方案
1. 核心问题
- 导航方式错误:直接调用
navigate(R.id.ThirdFragment)会新建ThirdFragment实例,而非回到原实例,导致原实例无法接收参数。 - Uri序列化问题:Gson无法默认正确序列化
Uri对象,解析时会出现异常。
2. 具体修复步骤
步骤1:修改Image类,存储Uri字符串
将Uri对象转为字符串存储,避免Gson序列化失败:
package Entities; import android.net.Uri; import java.io.Serializable; public class Image implements Serializable{ private final String id; private final String photoUriStr; private final String imageName; public Image(String id, String imageName, Uri photo) { this.id = id; this.imageName = imageName; this.photoUriStr = photo.toString(); } public Uri getPhoto() { return Uri.parse(photoUriStr); } public String getImageName() { return imageName; } public String getId() { return id; } }
步骤2:修改PickedImageFragment的回传逻辑
使用SavedStateHandle传递参数并向上导航,回到原ThirdFragment实例:
// 替换原跳转代码 binding.submitMyPhotoButton.setOnClickListener(view1 -> { if(binding.photoDescription.getText().toString().trim().equals("")){ Toast.makeText(getContext(), "Pick title/description for photo!", Toast.LENGTH_SHORT).show(); } else{ String photoName = binding.photoDescription.getText().toString().trim(); String imageID = UUID.randomUUID().toString(); Image myImage = new Image(imageID, photoName, imageUri); Gson gson = new Gson(); String imageJson = gson.toJson(myImage); NavController navController = Navigation.findNavController(view); // 向原ThirdFragment传递结果 navController.getPreviousBackStackEntry().getSavedStateHandle().set("IMAGE_RESULT", imageJson); // 向上导航返回 navController.navigateUp(); } });
步骤3:修改ThirdFragment的参数接收逻辑
监听SavedStateHandle的结果变化,而非读取requireArguments():
@Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // 监听回传的图片数据 NavHostFragment.findNavController(this).getCurrentBackStackEntry() .getSavedStateHandle().getLiveData("IMAGE_RESULT") .observe(getViewLifecycleOwner(), imageJson -> { if (imageJson != null) { Gson gson = new Gson(); Image myImage = gson.fromJson(imageJson, Image.class); Log.d("test", myImage.getImageName()); Log.d("test", myImage.getId()); Log.d("test", myImage.getPhoto().toString()); } }); // 原有其他代码... }
替代方案:使用导航Action
若在navigation.xml中定义了从PickedImageFragment到ThirdFragment的Action,可直接使用该Action跳转并配置回退栈:
<action android:id="@+id/action_pickedImageFragment_to_thirdFragment" app:destination="@id/ThirdFragment" app:popUpTo="@id/ThirdFragment" app:popUpToInclusive="true"/>
跳转代码改为:
navController.navigate(R.id.action_pickedImageFragment_to_thirdFragment, bundle);
内容的提问来源于stack exchange,提问作者cocojambo01
相关产品推荐
相关产品推荐

