如何修复 Android 片段中的 "Only the original thread that created a view hierarchy can touch its views"?
How to fix "Only the original thread that created a view hierarchy can touch its views" in Android Fragment?
我的以下代码有问题
public class StatusFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_status, container, false);
//Untuk menjalankan command dari API
{
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
final TextView tv0 = (TextView) view.findViewById(R.id.textView0);
final TextView tv1 = (TextView) view.findViewById(R.id.textView1);
final TextView tv2 = (TextView) view.findViewById(R.id.textView2);
final TextView tv3 = (TextView) view.findViewById(R.id.textView3);
final TextView tv4 = (TextView) view.findViewById(R.id.textView4);
final TextView tv5 = (TextView) view.findViewById(R.id.textView5);
final TextView tv6 = (TextView) view.findViewById(R.id.textView6);
final TextView tv7 = (TextView) view.findViewById(R.id.textView7);
final TextView tv8 = (TextView) view.findViewById(R.id.textView8);
ApiConnection con = MainActivity.getCon();
if (con !=null)
try {
//Untuk Menampilkan Resource dari Mikrotik
String rs = con.execute("/system/resource/print interval=3",
new ResultListener() {
public void receive(Map<String, String> result) {
tv0.setText(result.get("platform"));
tv1.setText(result.get("board-name"));
tv2.setText(result.get("version"));
tv3.setText(result.get("uptime"));
tv4.setText(String.format("%s %%", result.get("cpu-load")));
tv5.setText(String.format("%s MB", Integer.parseInt(result.get("free-memory")) / (1024*1024)));
tv6.setText(String.format("%s MB", Integer.parseInt(result.get("total-memory")) / (1024*1024)));
tv7.setText(String.format("%s MB", Integer.parseInt(result.get("free-hdd-space")) / (1024*1024)));
tv8.setText(String.format("%s MB", Integer.parseInt(result.get("total-hdd-space")) / (1024*1024)));
}
public void error(MikrotikApiException e) {
System.out.println("An error occurred: " + e.getMessage());
}
public void completed() {
System.out.println("Asynchronous command has finished");
}
}
);
} catch (MikrotikApiException e) {
e.printStackTrace();
}
}
});
}
return view;
}
}
------------崩溃开始
05-10 08:26:58.797 7122-7164/com.tasanahetech.mikroboxv2
E/AndroidRuntime: FATAL EXCEPTION: Mikrotik API Result Processor
Process: com.tasanahetech.mikroboxv2, PID: 7122
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6556)
at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:907)
at android.view.View.requestLayout(View.java:18722)
at android.view.View.requestLayout(View.java:18722)
at android.view.View.requestLayout(View.java:18722)
at android.view.View.requestLayout(View.java:18722)
at android.view.View.requestLayout(View.java:18722)
at android.view.View.requestLayout(View.java:18722)
at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:360)
at android.view.View.requestLayout(View.java:18722)
at android.view.View.requestLayout(View.java:18722)
at android.support.constraint.ConstraintLayout.requestLayout(ConstraintLayout.java:3172)
at android.view.View.requestLayout(View.java:18722)
at android.view.View.requestLayout(View.java:18722)
at android.view.View.requestLayout(View.java:18722)
at android.widget.TextView.checkForRelayout(TextView.java:7172)
at android.widget.TextView.setText(TextView.java:4342)
at android.widget.TextView.setText(TextView.java:4199)
at android.widget.TextView.setText(TextView.java:4174)
at com.tasanahetech.mikroboxv2.StatusFragment.receive(StatusFragment.java:57)
at com.tasanahetech.mikroboxv2.api.impl.ApiConnectionImpl$Processor.run(ApiConnectionImpl.java:258)
谢谢
解决该问题最快的方法是,将 receive() 函数内的所有 "tv0.setText()" 调用包装到另一个 "runOnUiThread" 块。像这样:
public void receive(Map<String, String> result) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
tv0.setText(result.get("platform"));
tv1.setText(result.get("board-name"));
tv2.setText(result.get("version"));
tv3.setText(result.get("uptime"));
tv4.setText(String.format("%s %%", result.get("cpu-load")));
tv5.setText(String.format("%s MB", Integer.parseInt(result.get("free-memory")) / (1024*1024)));
tv6.setText(String.format("%s MB", Integer.parseInt(result.get("total-memory")) / (1024*1024)));
tv7.setText(String.format("%s MB", Integer.parseInt(result.get("free-hdd-space")) / (1024*1024)));
tv8.setText(String.format("%s MB", Integer.parseInt(result.get("total-hdd-space")) / (1024*1024)));
});
}
外层"getActivity().runOnUiThread"可以去掉
我的以下代码有问题
public class StatusFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_status, container, false);
//Untuk menjalankan command dari API
{
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
final TextView tv0 = (TextView) view.findViewById(R.id.textView0);
final TextView tv1 = (TextView) view.findViewById(R.id.textView1);
final TextView tv2 = (TextView) view.findViewById(R.id.textView2);
final TextView tv3 = (TextView) view.findViewById(R.id.textView3);
final TextView tv4 = (TextView) view.findViewById(R.id.textView4);
final TextView tv5 = (TextView) view.findViewById(R.id.textView5);
final TextView tv6 = (TextView) view.findViewById(R.id.textView6);
final TextView tv7 = (TextView) view.findViewById(R.id.textView7);
final TextView tv8 = (TextView) view.findViewById(R.id.textView8);
ApiConnection con = MainActivity.getCon();
if (con !=null)
try {
//Untuk Menampilkan Resource dari Mikrotik
String rs = con.execute("/system/resource/print interval=3",
new ResultListener() {
public void receive(Map<String, String> result) {
tv0.setText(result.get("platform"));
tv1.setText(result.get("board-name"));
tv2.setText(result.get("version"));
tv3.setText(result.get("uptime"));
tv4.setText(String.format("%s %%", result.get("cpu-load")));
tv5.setText(String.format("%s MB", Integer.parseInt(result.get("free-memory")) / (1024*1024)));
tv6.setText(String.format("%s MB", Integer.parseInt(result.get("total-memory")) / (1024*1024)));
tv7.setText(String.format("%s MB", Integer.parseInt(result.get("free-hdd-space")) / (1024*1024)));
tv8.setText(String.format("%s MB", Integer.parseInt(result.get("total-hdd-space")) / (1024*1024)));
}
public void error(MikrotikApiException e) {
System.out.println("An error occurred: " + e.getMessage());
}
public void completed() {
System.out.println("Asynchronous command has finished");
}
}
);
} catch (MikrotikApiException e) {
e.printStackTrace();
}
}
});
}
return view;
}
}
------------崩溃开始
05-10 08:26:58.797 7122-7164/com.tasanahetech.mikroboxv2 E/AndroidRuntime: FATAL EXCEPTION: Mikrotik API Result Processor Process: com.tasanahetech.mikroboxv2, PID: 7122 android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6556) at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:907) at android.view.View.requestLayout(View.java:18722) at android.view.View.requestLayout(View.java:18722) at android.view.View.requestLayout(View.java:18722) at android.view.View.requestLayout(View.java:18722) at android.view.View.requestLayout(View.java:18722) at android.view.View.requestLayout(View.java:18722) at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:360) at android.view.View.requestLayout(View.java:18722) at android.view.View.requestLayout(View.java:18722) at android.support.constraint.ConstraintLayout.requestLayout(ConstraintLayout.java:3172) at android.view.View.requestLayout(View.java:18722) at android.view.View.requestLayout(View.java:18722) at android.view.View.requestLayout(View.java:18722) at android.widget.TextView.checkForRelayout(TextView.java:7172) at android.widget.TextView.setText(TextView.java:4342) at android.widget.TextView.setText(TextView.java:4199) at android.widget.TextView.setText(TextView.java:4174) at com.tasanahetech.mikroboxv2.StatusFragment.receive(StatusFragment.java:57) at com.tasanahetech.mikroboxv2.api.impl.ApiConnectionImpl$Processor.run(ApiConnectionImpl.java:258)
谢谢
解决该问题最快的方法是,将 receive() 函数内的所有 "tv0.setText()" 调用包装到另一个 "runOnUiThread" 块。像这样:
public void receive(Map<String, String> result) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
tv0.setText(result.get("platform"));
tv1.setText(result.get("board-name"));
tv2.setText(result.get("version"));
tv3.setText(result.get("uptime"));
tv4.setText(String.format("%s %%", result.get("cpu-load")));
tv5.setText(String.format("%s MB", Integer.parseInt(result.get("free-memory")) / (1024*1024)));
tv6.setText(String.format("%s MB", Integer.parseInt(result.get("total-memory")) / (1024*1024)));
tv7.setText(String.format("%s MB", Integer.parseInt(result.get("free-hdd-space")) / (1024*1024)));
tv8.setText(String.format("%s MB", Integer.parseInt(result.get("total-hdd-space")) / (1024*1024)));
});
}
外层"getActivity().runOnUiThread"可以去掉