在 Thread 上刷新 UI 并更改 Fragment 时出错
Error when refreshing UI on Thread and changing Fragment
所以我在理解(我认为)刷新 UI 的工作原理时遇到了问题。
我有一个带有底部导航栏的 activity,其中包含 3 个加载片段的项目。
每个片段都从互联网加载数据,所以我将这些数据下载到一个线程中,完成后我在 UI 线程上刷新我的 recyclerview。
但问题是,当我 select 导航栏上的一个项目时,当我立即 select 另一个项目时,我的应用程序崩溃了,因为数据下载已完成并且 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.access0(SafeFragment.java:20)
at com.projects.morgan.kingwin.Fragments.SafeFragment.run(SafeFragment.java:55)
at java.lang.Thread.run(Thread.java:764)
主Activity底部导航条码:
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();
}
});
}
}
请提供完整的片段代码及其宿主activity。您的案例似乎存在一些并发问题。
在调用您的 runOnUiThread 方法之前添加空指针检查,如下所示
if(getActivity() != null){
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
adapter = new PredictionAdapter(predictionList);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
});
}
由于您的片段不再存在,其 getActivity() 方法 returns 为空。这应该可以避免崩溃。
我认为问题出在您试图在 ui 线程上获取对 运行 的 getActivity() 的引用。
private void updateUI() {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
adapter = new PredictionAdapter(predictionList);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
});
}
如果您不在片段中并试图调用 getActivity()
它将 return null
对象。
所以在调用getActivity()
之前添加null
检查将解决问题。
像
if(getActivity() !=null){
//call the ui thread
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
adapter = new PredictionAdapter(predictionList);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
});
}
您必须首先检查您当前的 activity 或片段是否存在,或者 not.Because 您正在尝试更新 UI 但可能当时片段或 activity 不存在。
您可以使用以下代码执行此操作:
if (getActivity() != null) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
adapter = new PredictionAdapter(predictionList);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
});
}
所以我在理解(我认为)刷新 UI 的工作原理时遇到了问题。 我有一个带有底部导航栏的 activity,其中包含 3 个加载片段的项目。 每个片段都从互联网加载数据,所以我将这些数据下载到一个线程中,完成后我在 UI 线程上刷新我的 recyclerview。
但问题是,当我 select 导航栏上的一个项目时,当我立即 select 另一个项目时,我的应用程序崩溃了,因为数据下载已完成并且 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.access0(SafeFragment.java:20)
at com.projects.morgan.kingwin.Fragments.SafeFragment.run(SafeFragment.java:55)
at java.lang.Thread.run(Thread.java:764)
主Activity底部导航条码:
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();
}
});
}
}
请提供完整的片段代码及其宿主activity。您的案例似乎存在一些并发问题。
在调用您的 runOnUiThread 方法之前添加空指针检查,如下所示
if(getActivity() != null){
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
adapter = new PredictionAdapter(predictionList);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
});
}
由于您的片段不再存在,其 getActivity() 方法 returns 为空。这应该可以避免崩溃。
我认为问题出在您试图在 ui 线程上获取对 运行 的 getActivity() 的引用。
private void updateUI() {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
adapter = new PredictionAdapter(predictionList);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
});
}
如果您不在片段中并试图调用 getActivity()
它将 return null
对象。
所以在调用getActivity()
之前添加null
检查将解决问题。
像
if(getActivity() !=null){
//call the ui thread
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
adapter = new PredictionAdapter(predictionList);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
});
}
您必须首先检查您当前的 activity 或片段是否存在,或者 not.Because 您正在尝试更新 UI 但可能当时片段或 activity 不存在。 您可以使用以下代码执行此操作:
if (getActivity() != null) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
adapter = new PredictionAdapter(predictionList);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
});
}