You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 05:29:58