【问题标题】:Reset RecyclerView adapter from another Fragment从另一个 Fragment 重置 RecyclerView 适配器
【发布时间】:2017-01-06 04:07:05
【问题描述】:

我有一个包含 RecyclerView 的片段。我正在尝试在 RecyclerView 上实现过滤器。过滤器 UI 会打开一个新的片段对话框,用户将在其中输入一个值。一旦用户在 Fragment Dialog 中点击 Search Button,该值应该返回到 RecyclerView Fragment,并且应该清除视图中的现有数据。我想使用将从服务器获取的新数据集重新填充 RecyclerView。我的问题是,我在 RecyclerView Fragment 中有一个名为 resetAdapterDetails() 的方法,如果从 RecyclerView Fragment 本身调用,它会按预期工作。但是,当我尝试从片段对话框调用相同的方法时,我得到一个异常:

transactionList.clear(); --> is trying to clear a list which is null

虽然数据在 RecyclerView 中仍然可见。

RecyclerView 片段

public class TransactionHistoryFragment extends Fragment implements SearchView.OnQueryTextListener, DateRangePickerFragment.OnDateRangeSelectedListener{

    private RecyclerView recyclerview;
    private TransactionHistoryAdapter adapter;
    private List<Transaction> transactionList;

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


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_transaction_history, container, false);

        recyclerview = (RecyclerView) view.findViewById(R.id.recyclerview);


        LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
        recyclerview.setLayoutManager(layoutManager);
        return view;
    }

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

    }


    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        setHasOptionsMenu(true);
        getTransactionHistory("");
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.transactions_history_menu, menu);

        final MenuItem searchItem = menu.findItem(R.id.action_search);
        final SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
        searchView.setOnQueryTextListener(this);


        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.filter_date:
                FragmentManager fmDate = getActivity().getFragmentManager();
                DateRangePickerFragment dialogFragmentDate = DateRangePickerFragment.newInstance(this, true);
                dialogFragmentDate.show(fmDate, "Sample Fragment");
                return true;
            case R.id.filter_mobile:
                FragmentManager fmMobile = getActivity().getFragmentManager();
                SearchMobileFragment dialogFragmentMobile = new SearchMobileFragment ();
                dialogFragmentMobile.show(fmMobile, "Sample Fragment");
                //resetAdapterDetails();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }

    }

    @Override
    public boolean onQueryTextChange(String newText) {
        final List<Transaction> filteredModelList = filter(transactionList, newText);

        adapter.setFilter(filteredModelList);
        return true;
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        return false;
    }

    //for filtering the list
    private List<Transaction> filter(List<Transaction> models, String query) {
        query = query.toLowerCase();final List<Transaction> filteredModelList = new ArrayList<>();
        for (Transaction model : models) {
            final String text = model.getTxnStatus().toLowerCase();
            if (text.contains(query)) {
                filteredModelList.add(model);
            }
        }
        return filteredModelList;
    }
    //for populating the list
    private void getTransactionHistory(String agentId){
        GetTransactionHistoryTask task = new GetTransactionHistoryTask("agent1", "password");
        task.getTransactionsByAgent("OU23","OU230000000123456789").subscribe(transactionHistoryResponse -> {
            if(transactionHistoryResponse != null && transactionHistoryResponse.getTransactions() != null && transactionHistoryResponse.getTransactions().size() > 0 && transactionHistoryResponse.getErrors().size() == 0){
                transactionList = transactionHistoryResponse.getTransactions();

                adapter = new TransactionHistoryAdapter(transactionList);
                recyclerview.addItemDecoration(new DividerItemDecoration(getActivity(), LinearLayoutManager.VERTICAL));
                recyclerview.setAdapter(adapter);
                onClickListnerRecyclerView();

            }
            else{

            }
        }, e -> e.printStackTrace());
    }

    private void onClickListnerRecyclerView() {
        recyclerview.addOnItemTouchListener(
                new RecyclerItemClickListener(getActivity(), new RecyclerItemClickListener.OnItemClickListener() {
                    @Override
                    public void onItemClick(View view, int position) {

                        try {
                           final Transaction transactionModel= (Transaction) adapter.getObjectAt(position);
                            Intent i = new Intent(getActivity(), TransactionDetailsActivity.class);
                            i.putExtra("transaction_object",transactionModel);
                            startActivity(i);
                        }

                        catch (Exception e){
                            Log.e("List issue", e.toString());
                        }

                    }
                })
        );
    }

    @Override
    public void onDateRangeSelected(int startDay, int startMonth, int startYear, int endDay, int endMonth, int endYear) {

    }

    public void fetchDateRange(String startDate, String endDate) {
        Log.e("DateRange",startDate + "\n" + endDate);
    }

    public void fetchMobileNumber(String mobileNumber) {
        Log.e("Mobile",mobileNumber);
        resetAdapterDetails();
    }

    public boolean resetAdapterDetails(){
        try {
            transactionList.clear();
            adapter.notifyDataSetChanged();
            recyclerview.setAdapter(adapter);

        } catch (Exception e) {
            Log.e("Reset Error", ""+e.getMessage());
        }

        return true;
    }
}

对话框片段

public class SearchMobileFragment extends DialogFragment {

    EditText mMobileNumberEditText;
    Button search_button;

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



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

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_search_mobile, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        mMobileNumberEditText = (EditText) view.findViewById(R.id.mobile_number_editText);
        search_button = (Button) view.findViewById(R.id.search_button);
        search_button.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {

                dismiss();
                TransactionHistoryFragment obj = new TransactionHistoryFragment();
                obj.fetchMobileNumber(mMobileNumberEditText.getText().toString());
            }
        });

    }
}

TransactionHistoryFragment (RecyclerView Fragment) 中的fetchMobileNumber() 方法是通过SearchMobileFragment (Dialog Fragment) 调用的fetchMobileNumber() 方法调用的。

我哪里错了?为什么transactionList.clear();会抛出空指针异常?

【问题讨论】:

    标签: java android android-fragments dialog android-recyclerview


    【解决方案1】:

    您遇到问题是因为您正在创建新的 TransactionHistoryFragment 实例 search_button 单击 SearchMobileFragment。这使得它的所有变量都为空并再次初始化它,在这里您的 transactionList 变为空。

    您也可以通过不同的方式轻松实现相同的目标。作为 SearchMobileFragment 作为 DialogFragment 的位置,您可以将其设置为 Activity 并从 TransactionHistoryFragment 将其作为 startActivityForResult 启动,并实现 onActivityResult 回调以进行过滤。

    但现在,在您的情况下,您也可以通过不同的方式对其进行管理:

    第一种方式: 正如您在 DialogFragment 中所做的那样

    search_button.setOnClickListener(new View.OnClickListener() {
    
                public void onClick(View v) {
    
                    dismiss();
                    /*TransactionHistoryFragment obj = new TransactionHistoryFragment();
                    obj.fetchMobileNumber(mMobileNumberEditText.getText().toString());*/
                }
            });
    

    不要在此处调用 fetchMobileNumber,在您的 TransactionHistoryFragment 的 onResume 中,您应该为此调用。单击 search_button 将过滤器数据保存到 SharedPreferences 并在 TransactionHistoryFragment 的 onResume 中使用该数据进行过滤,然后从 SharedPreferences onPause 清除此片段的保存数据。

    你应该删除

    transactionList.clear(); 
    

    来自 TransactionHistoryFragment 中 resetAdapterDetails() 的代码,因为在搜索过滤器之后,您将获得已传递给适配器的更新事务列表,然后强制不需要清除它。或者在清除之前先检查一下:

    if(transactionList!=null){
       transactionList.clear();
    }
    

    第二种方式:使用 BroadcastReceiver 可以达到同样的效果。 在您的 TransactionHistoryFragment 中注册一个接收器并从 SearchMobileFragment 发送广播。在 TransactionHistoryFragment 的 onReceive 中进行过滤。

    【讨论】:

    • 感谢您的回复。你建议我打电话清除 TransactionHistoryFragment 的 onResume 中的 RecyclerView,但 onResume 并不总是触发。
    • 是的,第一种方法只有在 onResume 每次都会被调用的情况下才有效。不是问题,您可以使用第二种方式(广播接收器)或通过创建 SearchMobileFragment 作为活动,正如我在回答中详述的那样。如果您需要更多帮助,请告诉我。
    • 嘿伙计!找到了一个很酷的方法来处理这个问题,我已经在上面发布了答案,非常感谢您的帮助和想法。
    【解决方案2】:

    我以不同的方式解决了上述问题。在 Dialog Fragment 中,我实现了一个 View.OnClickListener 并创建了一个 Interface 来从 RecyclerView Fragment 初始化它。我在下面发布完整的源代码; SearchMobileFragment 现在看起来像:

    public class SearchMobileFragment extends DialogFragment implements View.OnClickListener{
    
        private OnMobileNumberSelectedListener onMobileNumberSelectedListener;
    
        EditText mMobileNumberEditText;
        Button mSearchButton;
    
        public SearchMobileFragment() {
            // Required empty public constructor
        }
    
        public static SearchMobileFragment newInstance(OnMobileNumberSelectedListener callback) {
            SearchMobileFragment searchMobileFragment = new SearchMobileFragment();
            searchMobileFragment.initialize(callback);
            return searchMobileFragment;
        }
    
        public void initialize(OnMobileNumberSelectedListener callback) {
            onMobileNumberSelectedListener = callback;
        }
    
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View root = inflater.inflate(R.layout.fragment_search_mobile, container, false);
            getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
            mMobileNumberEditText = (EditText) root.findViewById(R.id.mobile_number_editText);
            mSearchButton = (Button) root.findViewById(R.id.search_button);
            mSearchButton.setOnClickListener(this);
            return root;
        }
    
        @Override
        public void onStart() {
            super.onStart();
            if (getDialog() == null)
                return;
            getDialog().getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
        }
    
        public void setOnMobileNumberSelectedListener(OnMobileNumberSelectedListener callback) {
            this.onMobileNumberSelectedListener = callback;
        }
    
        @Override
        public void onClick(View v) {
            dismiss();
    
    
            onMobileNumberSelectedListener.onMobileNumberSelected(mMobileNumberEditText.getText().toString());
    
        }
    
    
    
        public interface OnMobileNumberSelectedListener {
            void onMobileNumberSelected(String mobileNumber);
        }
    }
    

    RecyclerView Fragment 修改:

    public class TransactionHistoryFragment extends Fragment implements SearchView.OnQueryTextListener,
            DateRangePickerFragment.OnDateRangeSelectedListener, SearchMobileFragment.OnMobileNumberSelectedListener{
    
        private RecyclerView recyclerview;
        private TransactionHistoryAdapter adapter;
        private List<Transaction> transactionList;
    
        SearchView search;
    
        public static final String TIMERANGEPICKER_TAG = "timerangepicker";
    
    
    
        public TransactionHistoryFragment() {
            // Required empty public constructor
        }
    
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
    
            View view = inflater.inflate(R.layout.fragment_transaction_history, container, false);
    
            recyclerview = (RecyclerView) view.findViewById(R.id.recyclerview);
    
    
            LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
            recyclerview.setLayoutManager(layoutManager);
            return view;
        }
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
        }
    
    
    
        @Override
        public void onViewCreated(View view, Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
    
            setHasOptionsMenu(true);
            getTransactionHistory();
        }
    
        @Override
        public void onResume() {
            Log.e("onResumeTHF","invoked");
            super.onResume();
        }
    
        @Override
        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
            inflater.inflate(R.menu.transactions_history_menu, menu);
            search = (SearchView) menu.findItem(R.id.action_search).getActionView();
            search.setOnQueryTextListener(this);
    
            super.onCreateOptionsMenu(menu, inflater);
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            switch (item.getItemId()) {
                case R.id.filter_date:
                    FragmentManager fmDate = getActivity().getFragmentManager();
                    DateRangePickerFragment dialogFragmentDate = DateRangePickerFragment.newInstance(this, true);
                    dialogFragmentDate.show(fmDate, "Sample Fragment");
                    return true;
                case R.id.filter_mobile:
                    FragmentManager fmMobile = getActivity().getFragmentManager();
                    SearchMobileFragment dialogFragmentMobile = SearchMobileFragment.newInstance(this);
                    dialogFragmentMobile.show(fmMobile, "Sample Fragment");
                    return true;
                default:
                    return super.onOptionsItemSelected(item);
            }
    
        }
    
        @Override
        public boolean onQueryTextChange(String newText) {
            Log.e("newText",newText);
           final List<Transaction> filteredModelList = filter(transactionList, newText);
    
            adapter.setFilter(filteredModelList);
            return true;
        }
    
        @Override
        public boolean onQueryTextSubmit(String query) {
            return false;
        }
    
    
    
    
        @Override
        public void onMobileNumberSelected(String mobileNumber) {
    
            Log.e("mobileNumber",mobileNumber);
    
            resetAdapterDetails();
        }
    
    
        public boolean resetAdapterDetails(){
            try {
                transactionList.clear();
                adapter.notifyDataSetChanged();
                recyclerview.setAdapter(adapter);
    
            } catch (Exception e) {
                Log.e("Reset Error", ""+e.getMessage());
            }
    
            return true;
        }
    }
    

    编码愉快!

    【讨论】:

      【解决方案3】:

      空指针异常是因为当您使用new 创建新的TransactionHistoryFragment 时,不会调用onViewCreated,因此永远不会初始化transactionList。您可以为列表创建一个 setter 或将其作为构造函数传递给片段以解决此问题

      【讨论】:

      • 你不认为调用父片段的构造函数会重新初始化适配器并且会出现同样的问题吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-06
      • 2018-10-11
      • 1970-01-01
      • 1970-01-01
      • 2016-10-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多