// 2.点击按钮进行查看,指定路径的源码
public void click(View v) {
try {
// 2.1获取源码路径
String path = et_path.getText().toString().trim();
// 2.2创建URL对象,指定我们要访问的网址(路径)
URL url = new URL(path);
// 2.3拿到httpurlconnection对象,用于发送或者接收数据
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 2.4设置发送get请求
conn.setRequestMethod("GET"); // get要求大写,默认是get请求
// 2.5设置请求超时时间
conn.setConnectTimeout(5000);
// 2.6获取服务器返回的状态码
int code = 0;
code = conn.getResponseCode();
// 2.7如果code==200说明请求成功
Log.d(TAG, code + "====================================");
if (code == 200) {
// 2.8获取服务器返回的数据,是以流的形式返回的,由于把流转换成字符串是很常见的操作
// 所以抽出一个工具类Utils
InputStream in = conn.getInputStream();
// 2.9使用定义的工具类把in转换城String
String content = StreamTools.readStream(in);
tv_result.setText(content);
}
} catch (MalformedURLException e) {
Toast.makeText(MainActivity.this, "协议未找到", Toast.LENGTH_SHORT).show();
e.printStackTrace();
} catch (IOException e) {
Toast.makeText(MainActivity.this, "您输入的网址有误", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
抛异常:Caused by: android.os.NetworkOnMainThreadException
解决方案:在OnCreate()方法加上两句:
方案一:
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog().penaltyDeath().build());
方案二:
开启一个新线程运行,如下:
new Thread() {
public void run() {
try {
// 2.1获取源码路径
String path = et_path.getText().toString().trim();
// 2.2创建URL对象,指定我们要访问的网址(路径)
URL url = new URL(path);
// 2.3拿到httpurlconnection对象,用于发送或者接收数据
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 2.4设置发送get请求
conn.setRequestMethod("GET"); // get要求大写,默认是get请求
// 2.5设置请求超时时间
conn.setConnectTimeout(5000);
// 2.6获取服务器返回的状态码
int code = 0;
code = conn.getResponseCode();
// 2.7如果code==200说明请求成功
Log.d(TAG, code + "====================================");
if (code == 200) {
// 2.8获取服务器返回的数据,是以流的形式返回的,由于把流转换成字符串是很常见的操作
// 所以抽出一个工具类Utils
InputStream in = conn.getInputStream();
// 2.9使用定义的工具类把in转换城String
String content = StreamTools.readStream(in);
tv_result.setText(content);
}
} catch (MalformedURLException e) {
Toast.makeText(MainActivity.this, "协议未找到", Toast.LENGTH_SHORT).show();
e.printStackTrace();
} catch (IOException e) {
Toast.makeText(MainActivity.this, "您输入的网址有误", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
}.start();
点击按钮出现结果,但是闪退,抛异常android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.说明在错误的线程更新UI。
Android中相关的view和控件操作都不是线程安全的,所以Android才会禁止在非UI线程更新UI,对于显式的非法操作,比如说直接在Activity里创建子线程,然后直接在子线程中操作UI等,Android会直接异常退出,并提示should run on UIThread之类的错误日志信息。而对于隐式的非法操作,App不会直接简单粗暴地异常退出,只是出现奇怪的结果,Only the original thread that created a view hierarchy can touch its views便是一个例子,字面意思是只有创建视图层次结构的原始线程才能操作它的View,明显是线程安全相关的。
总结点:
不能在主线程(UI线程)进行耗时的操作,比如连接网络,拷贝大数据,睡眠等操作。
比如连接谷歌网络。warning:java.net.SocketTimeoutException: connect timed out
只要主线程超时 info:The application may be doing too much work on its main thread.
在4.0之后谷歌强制要求连接网络不能在主线程进行访问
只有主线程(UI线程)才可以更新UI
=================================Talk is cheap, show me the code===============================