刷新线程上的UI并更改片段时出错

时间:2018-08-14 07:21:19

标签: android android-fragments android-recyclerview android-thread

因此,我在理解(我认为)刷新UI如何工作方面存在问题。 我有一个带有底部导航栏的活动,其中包含3个加载片段的项目。 每个片段都从Internet加载数据,因此我将这些数据下载到线程中,并在完成后在UI线程上刷新recyclerview。

但是问题是当我在导航栏上选择一个项目并且当我立即选择另一个项目时,我的应用程序崩溃了,因为数据下载完成并且UI线程正在尝试刷新recyclerview,但是我不知道在片段上更长

那么我该如何避免这种崩溃?

这是我的代码:

private void refreshRecyclerView() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                predictionList = ComboBetHTMLParser.getPredictionList();
                updateUI();
            }
        }).start();
    }

    private void updateUI() {
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                adapter = new PredictionAdapter(predictionList);
                recyclerView.setAdapter(adapter);
                adapter.notifyDataSetChanged();
            }
        });
    }

编辑:

这是错误日志:

                  java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v4.app.FragmentActivity.runOnUiThread(java.lang.Runnable)' on a null object reference
                      at com.projects.morgan.kingwin.Fragments.SafeFragment.updateUI(SafeFragment.java:61)
                      at com.projects.morgan.kingwin.Fragments.SafeFragment.access$100(SafeFragment.java:20)
                      at com.projects.morgan.kingwin.Fragments.SafeFragment$1.run(SafeFragment.java:55)
                      at java.lang.Thread.run(Thread.java:764)

主要活动底部导航条形码:

bottomNavigationBar.setTabSelectedListener(new BottomNavigationBar.OnTabSelectedListener() {
            @Override
            public void onTabSelected(int position) {
                displayOnSelectedScreen(position);
            }

            @Override
            public void onTabUnselected(int position) {
                Log.d("TEST", "onTabUnselected:" + position);
            }

            @Override
            public void onTabReselected(int position) {
                Log.d("TEST", "onTabReselected:");
            }
        });



private void displayOnSelectedScreen(int position) {
        // Begin the transaction
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        Fragment fragment = null;
        switch (position) {
            case 0:
                if (accueilFragment == null) {
                    accueilFragment = new AccueilFragment();
                }
                fragment = accueilFragment;
                break;
            case 1:
                if (predictionsFragment == null) {
                    predictionsFragment = new PredictionsFragment();
                }
                fragment = predictionsFragment;
                break;
            case 2:
                if (safeFragment == null) {
                    safeFragment = new SafeFragment();
                }
                fragment = safeFragment;
                break;
        }
        ft.replace(R.id.content_frame,fragment).commit();
    }

片段代码:

public class SafeFragment extends Fragment {

    private List<Prediction> predictionList = new ArrayList<>();
    private RecyclerView recyclerView;
    private PredictionAdapter adapter;

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

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        if (predictionList.size() == 0) {
            refreshRecyclerView();
        }
    }

    private void initRecyclerView(View view) {
        recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
        recyclerView.setHasFixedSize(true);
        adapter = new PredictionAdapter(predictionList);
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        recyclerView.setAdapter(adapter);
    }

    private void refreshRecyclerView() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                predictionList = InternetData.getPredictionList();
                updateUI();
            }
        }).start();
    }

    private void updateUI() {
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                adapter = new PredictionAdapter(predictionList);
                recyclerView.setAdapter(adapter);
                adapter.notifyDataSetChanged();
            }
        });
    }
}

4 个答案:

答案 0 :(得分:0)

请提供完整的片段代码及其宿主活动。您的案件似乎存在一些并发问题。

答案 1 :(得分:0)

在调用如下所示的runOnUiThread方法之前添加空指针检查

if(getActivity() != null){
    getActivity().runOnUiThread(new Runnable() {
        @Override
        public void run() {
            adapter = new PredictionAdapter(predictionList);
            recyclerView.setAdapter(adapter);
            adapter.notifyDataSetChanged();
        }
    });
}

由于您的片段不再存在,因此其getActivity()方法返回null。这样可以避免崩溃。

答案 2 :(得分:0)

我认为问题在于,您正试图获取getActivity()的引用以在ui线程上运行。

private void updateUI() {
    getActivity().runOnUiThread(new Runnable() {
        @Override
        public void run() {
            adapter = new PredictionAdapter(predictionList);
            recyclerView.setAdapter(adapter);
            adapter.notifyDataSetChanged();
        }
    });
}

如果您不在片段中,并尝试调用getActivity(),它将返回null对象。 因此,在调用null之前添加getActivity()检查将解决问题。 像

    if(getActivity() !=null){
    //call the ui thread
      getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                adapter = new PredictionAdapter(predictionList);
                recyclerView.setAdapter(adapter);
                adapter.notifyDataSetChanged();
            }
        });
    }

答案 3 :(得分:0)

您必须首先检查您当前的活动或片段是否存在。因为您正在尝试更新UI,但此时可能不存在片段或活动。  您可以使用以下代码来做到这一点:

if (getActivity() != null) {
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    adapter = new PredictionAdapter(predictionList);
                    recyclerView.setAdapter(adapter);
                    adapter.notifyDataSetChanged();
                }
            });
        }