【问题标题】:NullPointerException in Fragment TabLayout when using BaseAdapter使用 BaseAdapter 时片段 TabLayout 中的 NullPointerException
【发布时间】:2020-02-23 14:21:56
【问题描述】:

我已经成功解析了一个带有后台 AsyncTask 的简单 rss 提要(XML 提要)。但无法使用 BaseAdapter (MyBaseAdapter) 将接收到的提要从 Fragment (FragmentTOI) 设置为 ListView。由于解析来自片段,我使用“getActivity()”而不是“MainActivity.this”。我可以看到从 rss xml 提要解析的 logcat 中的所有标题。附上代码 sn-ps 和 Logcat 截图。

代码:

    // Fragment
    public static class FragmentTOI extends Fragment {
        ListView listView;
        MyAsyncTask myAsyncTask;
        Context context;
        ArrayAdapter<String> arrayAdapter;

        public FragmentTOI(Context context) {
//            this.context = context;
        }

        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            super.onCreateView (inflater, container, savedInstanceState);
            View view = inflater.inflate (R.layout.fragment_toi, container, false);
            listView = view.findViewById (R.id.list_view_toi);
            startTask ();
            return view;
        }

        // Method to start the AsyncTask with new one if null.
        public void startTask() {
            //if the download is empty then cancel, else start the task
            if (myAsyncTask != null) {
                myAsyncTask.cancel (true);
            } else {
                myAsyncTask = new MyAsyncTask (getActivity ());
                myAsyncTask.execute ();
            }
        }

        // Method to receive data from onPostExecute of AsyncTask.
        public void receiveData(ArrayList<HashMap<String, String>> results) {
            Log.d ("XML", "FragmentTOI receiveData Method: " + results);
            listView.setAdapter (new MyBaseAdapter (context, results));
            listView.setAdapter (arrayAdapter);
        }
    }

    // AsyncTask downloader
    public static class MyAsyncTask extends AsyncTask<Void, Void, ArrayList<HashMap<String, String>>> {

        @Override
        protected void onPostExecute(ArrayList<HashMap<String, String>> hashMaps) {
            super.onPostExecute (hashMaps);
            fragmentTOI.receiveData (hashMaps);
        }
    }

    public static class MyBaseAdapter extends BaseAdapter {
        ArrayList<HashMap<String, String>> data;
        LayoutInflater layoutInflater;

        public MyBaseAdapter(Context context, ArrayList<HashMap<String, String>> data) {
            this.data = data;
            layoutInflater = (LayoutInflater) context.getSystemService (Context.LAYOUT_INFLATER_SERVICE);
        }

        @Override
        public int getCount() {
            return data.size ();
        }

        @Override
        public Object getItem(int i) {
            return data.get (i);
        }

        @Override
        public long getItemId(int i) {
            return i;
        }

        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            View view1 = view;
            MyRowHolder myRowHolder = null;
            if (view1 == null) {
                view1 = layoutInflater.inflate (R.layout.single_row, viewGroup, false);
                myRowHolder = new MyRowHolder (view1);
                view1.setTag (myRowHolder);
            } else {
                myRowHolder = (MyRowHolder) view1.getTag ();
            }
            HashMap<String, String> currentItem = data.get (i);
            myRowHolder.textViewTitle.setText (currentItem.get ("title"));
            return view1;
        }
    }

    static class MyRowHolder {
        TextView textViewTitle;

        public MyRowHolder(View view) {
            textViewTitle = view.findViewById (R.id.text_view_title);
        }
    }

Logcat:

【问题讨论】:

    标签: android android-studio android-fragments android-listview android-tablayout


    【解决方案1】:

    当您将适配器设置为您的列表视图时,请使用context,如下所示。

    // Method to receive data from onPostExecute of AsyncTask.
    public void receiveData(ArrayList<HashMap<String, String>> results) {
        //listView.setAdapter (new MyBaseAdapter (getActivity (), results)); // here you got exception.
    
        // use context as you initialize it inside the constructor of your fragment.
        listView.setAdapter (new MyBaseAdapter (context, results));
        listView.setAdapter (arrayAdapter);
    }
    

    【讨论】:

    • 请将您的activity 代码贴在您拨打FragmentTOI 的位置。
    【解决方案2】:

    选项 - 1:

    试试requireActivity()requireContext()

    而不是

    listView.setAdapter (new MyBaseAdapter (getActivity (), results));
    

    使用

    listView.setAdapter (new MyBaseAdapter (requireActivity(), results));
    

    选项 - 2: 无需在 Adapter 中传递Context 即可获取LayoutInflater。删除这个:

    public MyBaseAdapter(Context context, ArrayList<HashMap<String, String>> data) {
        this.data = data;
        //layoutInflater = (LayoutInflater) context.getSystemService (Context.LAYOUT_INFLATER_SERVICE);
    }
    

    getView 里面试试这样:

    if (view1 == null) {
        view1 = LayoutInflater.from(viewGroup.getContext()).inflate (R.layout.single_row, viewGroup, false);
        myRowHolder = new MyRowHolder (view1);
        view1.setTag (myRowHolder);
    }
    

    【讨论】:

    • 为什么你的片段static 以及为什么你通过Context 来调用片段?如果您需要传递Context,请使用它而不是getActivity()。不是吗?
    • 在我的回答中尝试使用 option-2,然后告诉我
    • 当我删除 static 时发生此异常:java.lang.IllegalStateException: Fragment com.shiva.pillu.headlinessample.MainActivity.FragmentTOI must be a public static class to be properly recreated from instance state. 当我尝试选项 2 时发生此错误:java.lang.IllegalStateException: Fragment FragmentTOI{c84840f} not attached to an activity.
    • 不要在 AsyncTask 中使用 fragmentTOI = new FragmentTOI (context);,而是使用接口将数据返回到片段。您创建了一个不附加到活动的 FragmentTOI 的新实例
    • 请进一步研究并重构您的代码库。它充满了问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    相关资源
    最近更新 更多