03_主线程联网问题&ANR&子线程不能修改UI
如果不使用HAXM,恐怕网页源码查看器无法获取servlet的源码。初步猜测是安卓模拟器运行速度太慢了。如果CPU不支持VT-x的话,HAXM是安装不上的。所以可以先开启VT-x.
可以参考几篇文章https://jingyan.baidu.com/article/ed15cb1b7586011be2698140.html http://www.cnblogs.com/lijc1990/archive/2013/02/07/2908969.html来解决安卓模拟器慢的问题。
安装intel的虚拟硬件加速软件“intelhaxm”,如D:\BaiduNetdiskDownload\adt-bundle-windows-x86_64_20140101\adt-bundle-windows-x86_64_20140101\sdk\extras\intel\Hardware_Accelerated_Execution_Manager
程序死了。
实际上在4.0以上的设备上它默认联网一定要开一个子线程。联网必须要开子线程。由于现在2.0以上4.0以下的设备基本上绝迹了。所以可以默认地认为联网一定要开子线程。主线程被阻塞住了,联网之后这是一个耗时的操作,联网之后经常会出现这样的问题,你这个网络环境不是很好,不是很好的话就一直在那里等,一直在那里等呢你这个线程被阻塞住之后你什么都不做不了这个用户体验是非常差的。
程序一运行起来默认它跑起来的这个线程就是主线程。所以在主线程里面不能做这种耗时的操作。所以咱们要开一个子线程。
4.0之后的设备你再做类似的操作马上就会抛出一个错误。因为它不允许在主线程当中访问网络。必须要开一个子线程。在4.0的设备也部署一下工程。
为什么没反应?因为它实际上抛异常咱们在这抓了一个大个的。有异常就都被抓住了。
多次出现ANR那你就会流失很多用户,大部分人都会把你的东西卸载掉。避免ANR异常,就是要把耗时的操作放到子线程去做。4.0之后联网必须要在子线程中否则会抛出异常。
又来异常了,程序之所以没挂是因为被catch住了。这个代码从一个错误的线程进行调用了。只有创建这个view结构的最初始的这个线程可以去操作这一个view。TextView是在主线程里面创建的。所以说想操作TextView这一个东西只能在主线程里面做不能在子线程里面做。
所以做安卓开发的第二个常识是:子线程不能修改UI/界面。未来的一周之内写代码的时候把这个忘了是无所谓的。但是两周之后敲了一两个应用程序之后联网还不开子线程或者是在子线程里面修改UI那这就说不过去了。
子线程不能修改UI这就涉及到一个多线程的问题了。你丢给子线程去做,究竟哪个线程先执行?这你就管不着了,这是CPU自己去控制。可能时间上是他先喝了一口血,然后对手按了一下打他,那究竟是这个血先喝呢还是这个对手先打他呢这就不好说了。这就涉及到线程同步的问题了。但是如果你操作这个界面的话如果是丢给线程的话这就不好说了,究竟是哪一个线程先操作这个界面让这个人倒下或者说这个血补上来那这个就很难判定了。有可能是说这个人没问题血补上了,也有可能说这个人被打倒下了然后血补上了又蹦起来了。如果多个线程操作这个界面你想让它没问题就得写这个锁,加锁,如果涉及到加锁的问题一旦这个程序员加锁处理不好可能会造成死锁的情况。所以干脆只有一个线程操作。所以强制修改UI必须在主线程进行。所以主线程又叫UI线程。
主线程叫UI线程又涉及到一个问题,我这个数据是从网上获取的,我要把这个内容交给UI线程,对TextView的持有进行操作。数据是从网上来的,但是也开子线程,所以我这个数据肯定是从子线程里获取到,但是我拿到数据还不能直接改,我还得在主线程里面进行修改。所以这个时候就出现一点悖论了。你联网必须得开子线程,子线程还不让改UI,我还要去修改这个UI.这就涉及到一个新的API:Handler。
package com.itheima.htmlcodeviewer; import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection; import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast; public class MainActivity extends Activity { private EditText et_url;
private Button btn_show;
private TextView tv_code; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); et_url = (EditText) findViewById(R.id.et_url);
btn_show = (Button) findViewById(R.id.btn_show);
tv_code = (TextView) findViewById(R.id.tv_code);
et_url.setText("http://10.0.2.2:8080/day07_01_servlethello/hello");
btn_show.setOnClickListener(new MyOnClickListenr());
String name = Thread.currentThread().getName();
Toast.makeText(this, name, Toast.LENGTH_SHORT).show();
}
private class MyOnClickListenr implements OnClickListener{ @Override
public void onClick(View v) {
// TODO Auto-generated method stub
//获取url
String path = et_url.getText().toString().trim();
try {
URL url = new URL(path);
//URLConnection openConnection = url.openConnection();
HttpURLConnection openConnection = (HttpURLConnection) url.openConnection();
//} catch (MalformedURLException e) {
//设置请求的方法 方法要大写 默认采用的是GET方式请求
openConnection.setRequestMethod("GET");
//如果联网之后网络信号不是太好,那就涉及到一直在等,一直在等
//有的时候可能会等的时间很长,等的时间很长的话那就有问题了,我究竟等到什么时候算是个结束
//设置超时的时间,一旦超过这个时间默认就是连接失败,让它停止下来
openConnection.setConnectTimeout(10000);//设置一个连接超时的时间
//获取响应码
int responseCode = openConnection.getResponseCode();
if(responseCode==200){
//联网后获得响应内容 响应是通过流的方式去返回回来的 //通过textview 展示对应的内容 InputStream inputStream = openConnection.getInputStream();//InputStream其实放的就是跟咱们HTML代码相关的内容
String stringFromStream = Utils.getStringFromStream(inputStream);
//不能直接修改界面 而是要通知主线程 获取到了数据 并且把数据丢给主线程 在主线程中显示
//修改textview内容展示数据
tv_code.setText(stringFromStream);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //拿着url联网
//判断响应码 如果是200 } } }
package com.itheima.htmlcodeviewer; import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection; import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast; public class MainActivity extends Activity { private EditText et_url;
private Button btn_show;
private TextView tv_code; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); et_url = (EditText) findViewById(R.id.et_url);
btn_show = (Button) findViewById(R.id.btn_show);
tv_code = (TextView) findViewById(R.id.tv_code);
//et_url.setText("http://10.0.2.2:8080");
et_url.setText("http://10.0.2.2:8080/day07_01_servlethello/hello");
btn_show.setOnClickListener(new MyOnClickListenr());
String name = Thread.currentThread().getName();
Toast.makeText(this, name, Toast.LENGTH_SHORT).show();
} private class MyOnClickListenr implements OnClickListener{ @Override
public void onClick(View v) {
// TODO Auto-generated method stub
new Thread(){
public void run() {
//获取url
String path = et_url.getText().toString().trim();
try {
URL url = new URL(path);
//拿着url联网
//URLConnection openConnection = url.openConnection();
HttpURLConnection openConnection = (HttpURLConnection) url.openConnection();
//} catch (MalformedURLException e) {
//设置请求的方法 方法要大写 默认采用的是GET方式请求
openConnection.setRequestMethod("GET");
//如果联网之后网络信号不是太好,那就涉及到一直在等,一直在等
//有的时候可能会等的时间很长,等的时间很长的话那就有问题了,我究竟等到什么时候算是个结束
//设置超时的时间,一旦超过这个时间默认就是连接失败,让它停止下来
openConnection.setConnectTimeout(10000);//设置一个连接超时的时间
//获取响应码
int responseCode = openConnection.getResponseCode();
//判断响应码 如果是200 获取流
if(responseCode==200){
//联网后获得响应内容 响应是通过流的方式去返回回来的
//通过textview 展示对应的内容
InputStream inputStream = openConnection.getInputStream();//InputStream其实放的就是跟咱们HTML代码相关的内容
String stringFromStream = Utils.getStringFromStream(inputStream);
//不能直接修改界面 而是要通知主线程 获取到了数据 并且把数据丢给主线程 在主线程中显示
//修改textview内容展示数据
tv_code.setText(stringFromStream);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} };
}.start(); } } }
package com.itheima.htmlcodeviewer; import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream; public class Utils {
//从这个流里面把它内容读出来,读出来之后把它转化成一个String类型的数据
public static String getStringFromStream(InputStream inputStream) {
// TODO Auto-generated method stub
//把流转化为字符串
ByteArrayOutputStream baso = new ByteArrayOutputStream();
int len = -1;
byte[] buffer = new byte[1024];
try {
while((len=inputStream.read(buffer))!=-1){
baso.write(buffer, 0, len);
}
inputStream.close();
byte[] byteArray = baso.toByteArray();
return new String(byteArray);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
} }
03_主线程联网问题&ANR&子线程不能修改UI的更多相关文章
- 有主线程发送message给子线程
通常我们在处理耗时任务时候都会通过新建线程来处理,当任务处理完后通过Handler将结果发送回主线程.比如下面示例: package com.example.testlistener; import ...
- android4.0以上访问网络不能在主线程中进行以及在线程中操作UI的解决方法
MONO 调用一个线程操作UI 然后报Only the original thread that created a view hierarchy can touch its views.错误 goo ...
- Android开发UI之在子线程中更新UI
转自第一行代码-Android Android是不允许在子线程中进行UI操作的.在子线程中去执行耗时操作,然后根据任务的执行结果来更新相应的UI控件,需要用到Android提供的异步消息处理机制. 代 ...
- 为什么子线程不能做UI操作
在子线程中是不能进行UI 更新的,而可以更新的结果只是一个幻像:因为子线程代码执行完毕了,又自动进入到了主线程,执行了子线程中的UI更新的函数栈,这中间的时间非常的短,就 让大家误以为分线程可以更新U ...
- Android在子线程中更新UI(二)
MainActivity如下: package cc.testui2; import android.os.Bundle; import android.view.View; import andro ...
- 关于Handler的理解,子线程不能更新UI的纠正和回调的思考
开发Android这么久了,总会听到有人说:主线程不能访问网络,子线程不能更新UI.Android的主线程的确不能长时间阻塞,但是子线程为什么不能更新UI呢?今天把这些东西整理,顺便在子线程更新UI. ...
- android 不能在子线程中更新ui的讨论和分析
问题描写叙述 做过android开发基本都遇见过 ViewRootImpl$CalledFromWrongThreadException,上网一查,得到结果基本都是仅仅能在主线程中更改 ui.子线程要 ...
- 使用Handler在子线程中更新UI
Android规定仅仅能在主线程中更新UI.假设在子线程中更新UI 的话会提演示样例如以下错误:Only the original thread that created a view hierach ...
- Android多线程之(一)View.post()源码分析——在子线程中更新UI
提起View.post(),相信不少童鞋一点都不陌生,它用得最多的有两个功能,使用简便而且实用: 1)在子线程中更新UI.从子线程中切换到主线程更新UI,不需要额外new一个Handler实例来实现. ...
随机推荐
- 还在为不停build 烦恼么?看这里~~
如果你是一名开发者,还在为偶尔改一个坐标或者颜色值 就要重新build 好久,然后如果层次深 还要一步步进去看效果么?下面 为大家介绍一个很好的开源库 DYCI 他的github地址,首先下载到本 ...
- 实现uitable cell中点击button设置当前cell为选中状态
- (void)buttonClick:(id)senser{ NSInteger tag = [senser tag]; NSLog(@"the button tag is % ...
- 【转载】究竟啥才是互联网架构“高可用”
一.什么是高可用 高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间. 假设系统一直能够提供服务,我们说系统的可用 ...
- nextSibling和previousSibling
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...
- 网络请求--Retrofit2用法
欢迎Follow我的GitHub, 关注我的CSDN. Retrofit是Square开发的网络请求库, 简化了网络请求的使用, 这个库太知名了, 优点我就不多说了. 让我们看看怎样使用吧? 注意: ...
- UVA 11246 - K-Multiple Free set(数论推理)
UVA 11246 - K-Multiple Free set 题目链接 题意:一个{1..n}的集合.求一个子集合.使得元素个数最多,而且不存在有两个元素x1 * k = x2,求出最多的元素个数是 ...
- break 用法
// break 在循环中的功能测试 # include <stdio.h> int main(void){ int i, j; for (i = 0; i<3; ++i) { j ...
- mt7620 wifi driver
<*> Ralink RT2860 802.11n AP support [*] LED Support [*] WSC (WiFi Simple Config) [*] WSC 2.0( ...
- NAND flash坏区
计算容量 厂家所说的4G指的是4 000 000 000字节,是按1000进制计算的,而电脑是按照1024进制计算的,所以标称为4G的NAND Flash理论容量是4 000 000 000 / 10 ...
- 关于用HOOK拦截键盘的一些问题
因为MSDN上说要这样做,所以我就这样做的,读懂MSDN是关键,下面来仔细阅读一下MSDN,看它到底是怎样描述的.阅读的时候我先给出原文,再进行自己的一些翻译或描述. 先看回调函数KeyboardPr ...