最近自己再写一个小项目练手,创建一个线程从网络获取数据然后显示在 recyclerView 上。写好后发现页面能够显示,但是有时候会把请求的数据显示过来,有时候不会。点开 android monitor 一看,有一个提示 :
Only the original thread that created a view hierarchy can touch its views.
异常的意思是说只有创建这个view的线程才能操作这个 view,普通会认为是将view创建在非UI线程中才会出现这个错误。
本来我想将就下,能看到算了的,说明我会简单使用 fragment 了。不过作为程序员我们肯定要寻根问底的啊。
这段请求数据代码如下所示:
new Thread(new Runnable() { @Override public void run() { try { String url = ""; OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(url).method("GET", null).build(); okhttp3.Response response = client.newCall(request).execute(); if (response.isSuccessful()) { String responseString = (response.body() == null ? "" : response.body().string()); ......解析数据 WidgetActionEvent event = new WidgetActionEvent(WidgetActionEvent.ACTION_CLICK); event.object = feedModel; EventBus.getDefault().post(event); //iLoadData.loadData(feedModel); } else { Log.i(TAG, "okHttp is request error"); } } catch (IOException e) { e.printStackTrace(); } } }).start();
数据请求之后,解析,并采用 eventbus 来传送数据。
ps :如果你是在 mainActivity 中调用上述代码,是不会产生的异常的,因为都是运行在主线程中。
变形一 : 崩溃
于是我换了一种形式来传递数据,这次采用回调的方式,也就是上面被注释掉的那行代码:
iLoadData.loadData(feedModel);
这次不用 eventbus 竟然崩溃了......我能怎么办,我也很无奈啊。
FATAL EXCEPTION: Thread-932 Process: example.hope.mvpwithrecyclerview, PID: 4916 android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
解决办法:采用 handle
实现代码如下:
/** * 发起网络请求 */ public static void okHttp_synchronousGet(final Handler handler) { new Thread(new Runnable() { @Override public void run() { try { String url = "url"; OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(url).method("GET", null).build(); okhttp3.Response response = client.newCall(request).execute(); if (response.isSuccessful()) { String responseString = (response.body() == null ? "" : response.body().string()); ......解析数据 handler.sendMessage(handler.obtainMessage(22, feedModel)); } else { Log.i(TAG, "okHttp is request error"); } } catch (IOException e) { e.printStackTrace(); } } }).start(); }
然后再 fragment 添加下面代码用来处理传过来的数据:
/** * 接收解析后传过来的数据 */ Handler handler = new Handler() { @Override public void handleMessage(Message msg) { Object model = (Object) msg.obj; showPictures(model); } };
这样就能后完美的解决这个问题了。