Fragment 上的 ItemClick 导致 android 应用程序崩溃

ItemClick on Fragment makes the android App crash

我试图证明,当一个项目在一个片段上的项目上单击时,该项目的详细信息会显示在另一个片段上。看来我的代码没有错误。但是,每当我点击一个项目时,android 应用程序崩溃并关闭。

下面是我所有活动的完整(100%)代码和相应的 xml 文件。您可以简单地复制这些代码和 运行。我无法找出每次单击项目时应用程序崩溃的原因。

错误LogCat:

2022-04-17 19:18:09.220 8609-8609/com.example.fragment D/AndroidRuntime: Shutting down VM
2022-04-17 19:18:09.222 8609-8609/com.example.fragment E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.fragment, PID: 8609
    java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
        at com.example.fragment.MainActivity.OnItemSelected(MainActivity.java:32)
        at com.example.fragment.ListFrag.onListItemClick(ListFrag.java:56)
        at androidx.fragment.app.ListFragment.onItemClick(ListFragment.java:64)
        at android.widget.AdapterView.performItemClick(AdapterView.java:330)
        at android.widget.AbsListView.performItemClick(AbsListView.java:1187)
        at android.widget.AbsListView$PerformClick.run(AbsListView.java:3179)
        at android.widget.AbsListView.run(AbsListView.java:4097)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
2022-04-17 19:18:09.249 8609-8609/com.example.fragment I/Process: Sending signal. PID: 8609 SIG: 9

MainActivity.java

包 com.example.fragment;

import androidx.appcompat.app.AppCompatActivity;



import android.os.Bundle;
import android.widget.TextView;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity implements ListFrag.ItemSelected {
  TextView tvDescrtiption;
    ArrayList<String> descriptions;

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

        tvDescrtiption=findViewById(R.id.tvDescription);

        descriptions=new ArrayList<String>();

        descriptions.add("Descriptions for Item 1");
        descriptions.add("Descriptions for Item 2");
        descriptions.add("Descriptions for Item 3");

    }

    public void OnItemSelected(int index) {
        tvDescrtiption.setText(descriptions.get(index));

    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="horizontal"
    tools:context=".MainActivity">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragmentContainerView"
        android:name="com.example.fragment.ListFrag"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        tools:layout="@layout/fragment_list" />

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

ListFrag.java

package com.example.fragment;

import android.content.Context;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.ListFragment;


import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import java.util.ArrayList;

public class ListFrag extends ListFragment {
    ItemSelected activity;
public interface ItemSelected
{
    void OnItemSelected(int index);
}

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

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        activity=(ItemSelected) context;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        ArrayList<String> data= new ArrayList<>();
        data.add("1. This is Item 1");
        data.add("2. This is Item 2");
        data.add("3. This is Item 3");

        setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1,data));

    }

    @Override
    public void onListItemClick( ListView l, View v, int position, long id) {
    
        activity.OnItemSelected(position);
    }
}

fragment_list.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ListFrag">

    <ListView

        android:id="@+id/lvList"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

Detail.java

package com.example.fragment;

import android.os.Bundle;

import androidx.fragment.app.Fragment;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class Detail extends Fragment {
    
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";
    
    private String mParam1;
    private String mParam2;
    public Detail() {
       
    }

   
    public static Detail newInstance(String param1, String param2) {
        Detail fragment = new Detail();
        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) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_detail, container, false);
    }
}

fragment_detail.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/yellow"
    tools:context=".Detail">

    <TextView
        android:id="@+id/tvDescription"
        android:layout_width="122dp"
        android:layout_height="wrap_content"
        android:text="TextView"
        android:textSize="20sp" />
</FrameLayout>

tvDescrtiption 为 null,因为它在 Detail 片段中,而不是直接在 MainActivity 中,您应该尝试从内部更新片段。

您收到 NullPointerException,因为当调用 .setText() 时,它是在 tvDescrtiption 上调用的,它是空的。如果您在第 19 行(tvDescrtiption=findViewById(R.id.tvDescription);)和第 30 行(tvDescrtiption.setText(descriptions.get(index));)设置断点,您将看到 tvDescrtiption 确实为 null。

为什么为空?我最长没有使用 findViewById(),但如果我没记错的话,如果你在 ActivityFragment 中膨胀它,你只能通过这种方式检索 ViewtvDescrtiption 住在 fragment_detail.xml,但在 MainActivity,你正在膨胀 activity_main.xml。您目前只能在 MainActivity 中使用 findViewById() 来检索在 activity_main.xml.

中声明的视图

刚刚找到我正在寻找的解决方案

我刚刚在 MainActivity.java

中添加了以下代码
   @Override
    protected void onPostCreate(@Nullable Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        tvDescrtiption=findViewById(R.id.tvDescription );
    }

现在,使用 onPostCreate ,我可以从另一个布局引用 tvDescriptions,它不再被视为空值。