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

从Fragment向MainActivity传数据时出现NullPointerException求助

Fragment交互引发NullPointerException问题排查与解决

问题背景

在Udemy学习Android Studio时,实现列表Fragment与详情Fragment交互练习,点击列表项触发NullPointerException。报错指向MainActivity的onItemClicked方法中调用TextView.setText时对象为空。经排查,tvName和tvTel控件实际属于DetailFragment的布局文件,而非MainActivity布局,导致MainActivity通过findViewById无法获取控件实例。


相关代码与报错信息

DetailFragment代码

public class DetailFrag extends Fragment {
    ImageView imageView;
    TextView tvName, tvTel;

    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";

    private String mParam1;
    private String mParam2;

    public DetailFrag() {
        // Required empty public constructor
    }

    public static DetailFrag newInstance(String param1, String param2) {
        DetailFrag fragment = new DetailFrag();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_detail, container, false);
    }
}

ListFragment代码

public class ListFrag extends Fragment {
    RecyclerView recyclerView;
    RecyclerView.Adapter myAdapter;
    RecyclerView.LayoutManager layoutManager;
    View view;

    public ListFrag() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_list, container, false);
        return view;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        recyclerView = view.findViewById(R.id.list);
        recyclerView.setHasFixedSize(true);

        layoutManager = new LinearLayoutManager(this.getActivity());
        recyclerView.setLayoutManager(layoutManager);

        myAdapter = new PersonAdapter(this.getActivity(), ApplicationClass.people);
        recyclerView.setAdapter(myAdapter);
    }
}

MainActivity代码

public class MainActivity extends AppCompatActivity implements PersonAdapter.ItemClicked {
    TextView tvName,tvTel;
    EditText etName, etTel;
    Button btnAdd;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tvName = findViewById(R.id.tvName);
        tvTel = findViewById(R.id.tvTel);
        etName = findViewById(R.id.etName);
        etTel = findViewById(R.id.etTel);
        btnAdd = findViewById(R.id.btnAdd);

        btnAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            }
        });
    }

    @Override
    public void onItemClicked(int index) {
        tvName.setText(ApplicationClass.people.get(index).getName());
        tvTel.setText(ApplicationClass.people.get(index).getTelNr());
    }
}

异常信息

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.recyclerfragments, PID: 31089
    java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
        at com.example.recyclerfragments.MainActivity.onItemClicked(MainActivity.java:43)
        at com.example.recyclerfragments.PersonAdapter$ViewHolder$1.onClick(PersonAdapter.java:46)
        at android.view.View.performClick(View.java:7575)
        at android.view.View.performClickInternal(View.java:7548)
        at android.view.View.access$3600(View.java:837)
        at android.view.View$PerformClick.run(View.java:28933)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:236)

MainActivity布局文件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragmentContainerView"
        android:name="com.example.recyclerfragments.ListFrag"
        android:layout_width="200dp"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:layout="@layout/fragment_list" />

    <LinearLayout
        android:id="@+id/linearLayout"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:orientation="vertical"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/fragmentContainerView"
        app:layout_constraintTop_toTopOf="parent">

        <androidx.fragment.app.FragmentContainerView
            android:id="@+id/fragmentContainerView2"
            android:name="com.example.recyclerfragments.DetailFrag"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="2"
            tools:layout="@layout/fragment_detail" />

        <androidx.fragment.app.FragmentContainerView
            android:id="@+id/fragmentContainerView3"
            android:name="com.example.recyclerfragments.AddPersonFragment"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="3"
            tools:layout="@layout/fragment_add_person" />
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

解决方案

方案1:通过MainActivity中转数据给DetailFragment

适合入门场景的直接修复方式:

  1. 修改DetailFragment:初始化控件并添加更新UI方法
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_detail, container, false);
    // 初始化布局内控件
    tvName = view.findViewById(R.id.tvName);
    tvTel = view.findViewById(R.id.tvTel);
    imageView = view.findViewById(R.id.imageView);
    return view;
}

// 对外暴露更新详情的方法
public void updatePersonInfo(String name, String tel) {
    tvName.setText(name);
    tvTel.setText(tel);
}
  1. 修改MainActivity:移除无效控件声明,通过Fragment实例更新UI
public class MainActivity extends AppCompatActivity implements PersonAdapter.ItemClicked {
    // 移除不属于当前布局的tvName、tvTel变量
    EditText etName, etTel;
    Button btnAdd;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 移除tvName、tvTel的初始化代码
        etName = findViewById(R.id.etName);
        etTel = findViewById(R.id.etTel);
        btnAdd = findViewById(R.id.btnAdd);

        btnAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            }
        });
    }

    @Override
    public void onItemClicked(int index) {
        // 获取已加载的DetailFragment实例
        DetailFrag detailFragment = (DetailFrag) getSupportFragmentManager()
                .findFragmentById(R.id.fragmentContainerView2);
        
        if (detailFragment != null) {
            Person selectedPerson = ApplicationClass.people.get(index);
            detailFragment.updatePersonInfo(selectedPerson.getName(), selectedPerson.getTelNr());
        }
    }
}

方案2:使用ViewModel共享数据(推荐)

遵循Android组件化最佳实践,实现Fragment解耦:

  1. 创建共享ViewModel
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

public class PersonViewModel extends ViewModel {
    private final MutableLiveData<Person> selectedPerson = new MutableLiveData<>();

    public void selectPerson(Person person) {
        selectedPerson.setValue(person);
    }

    public MutableLiveData<Person> getSelectedPerson() {
        return selectedPerson;
    }
}
  1. 修改ListFragment适配器点击逻辑:直接通过ViewModel传递数据
// 在PersonAdapter的ViewHolder点击事件中
itemView.setOnClickListener(v -> {
    int position = getAdapterPosition();
    if (position != RecyclerView.NO_POSITION) {
        Person person = ApplicationClass.people.get(position);
        // 获取Activity级别的ViewModel实例
        PersonViewModel viewModel = new ViewModelProvider(requireActivity()).get(PersonViewModel.class);
        viewModel.selectPerson(person);
    }
});
  1. 修改DetailFragment:观察ViewModel数据变化并更新UI
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    // 初始化控件
    tvName = view.findViewById(R.id.tvName);
    tvTel = view.findViewById(R.id.tvTel);
    imageView = view.findViewById(R.id.imageView);

    // 监听ViewModel数据变化
    PersonViewModel viewModel = new ViewModelProvider(requireActivity()).get(PersonViewModel.class);
    viewModel.getSelectedPerson().observe(getViewLifecycleOwner(), person -> {
        if (person != null) {
            tvName.setText(person.getName());
            tvTel.setText(person.getTelNr());
        }
    });
}
  1. 简化MainActivity:无需再实现PersonAdapter.ItemClicked接口,移除相关代码

内容的提问来源于stack exchange,提问作者Chris Damianidis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 09:15:30