学习Android过程中遇到的问题及解决方法——网络请求

在学习Android的网络连接时遇到崩溃或IOException异常(出现的问题就这两个,但是不稳定)的问题,先上代码,看看哪里错了(答案在文末)

activity_main.xml:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:app="http://schemas.android.com/apk/res-auto"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent"
 7     tools:context=".MainActivity">
 8 
 9     <LinearLayout
10         android:layout_width="match_parent"
11         android:layout_height="match_parent"
12         android:orientation="vertical">
13 
14 
15         <EditText
16             android:id="@+id/et_path"
17             android:layout_width="match_parent"
18             android:layout_height="wrap_content"
19             android:hint="请输入网址"
20             android:text="https://www.baidu.com/" />
21 
22         <Button
23             android:layout_width="wrap_content"
24             android:layout_height="wrap_content"
25             android:onClick="click"
26             android:text="查看" />
27 
28         <ScrollView
29             android:layout_width="match_parent"
30             android:layout_height="match_parent">
31 
32             <TextView
33                 android:id="@+id/tv_result"
34                 android:layout_width="match_parent"
35                 android:layout_height="match_parent" />
36         </ScrollView>
37 
38     </LinearLayout>
39 
40 </android.support.constraint.ConstraintLayout>

MainActivity.xml:

 1 import android.content.Context;
 2 import android.os.Handler;
 3 import android.os.Message;
 4 import android.support.v7.app.AppCompatActivity;
 5 import android.os.Bundle;
 6 import android.view.View;
 7 import android.widget.EditText;
 8 import android.widget.TextView;
 9 import android.widget.Toast;
10 
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.net.HttpURLConnection;
14 import java.net.MalformedURLException;
15 import java.net.ProtocolException;
16 import java.net.URL;
17 
18 public class MainActivity extends AppCompatActivity {
19 
20     private EditText et_path;
21     private TextView tv_result;
22 
23     @Override
24     protected void onCreate(Bundle savedInstanceState) {
25         super.onCreate(savedInstanceState);
26         setContentView(R.layout.activity_main);
27 
28         et_path = findViewById(R.id.et_path);
29         tv_result = findViewById(R.id.tv_result);
30 
31            }
32 
33     //点检就进行查看指定路径的源码
34     public void click(View view) {
35 
36         try {
37             //获取源码路径
38             String path = et_path.getText().toString().trim();
39             //创建url对象制定我们要访问的路径
40             URL url = new URL(path);
41             //拿到httpUrlConnection对象
42             HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
43             //设置请求方法
44             httpURLConnection.setRequestMethod("GET");//GET要求大写,默认get请求
45             //设置请求时间
46             httpURLConnection.setConnectTimeout(5000);
47             //获取服务器返回的状态码
48              int code = httpURLConnection.getResponseCode();
49             //如果code = 200,说明请求成功
50             if (code == 200) {
51                 //获取服务器返回的数据,是以流的形式返回的
52                 InputStream in = httpURLConnection.getInputStream();
53                 System.out.println();
54 
55                 //将流转换成字符串
56                 String content = StreamTools.readStreamToString(in);
57 
58                 //展示到指定控件中
59                 tv_result.setText(content);
60 
61             } 
62         } catch (ProtocolException e) {
63             e.printStackTrace();
64             System.out.println("异常1");
65         } catch (MalformedURLException e) {
66             e.printStackTrace();
67             System.out.println("异常2");
68         } catch (IOException e) {
69             e.printStackTrace();
70             System.out.println("异常3");
71         }
72 
73 
74     }
75 }


新建一个工具类来将Stream流转换成String

SrreamTools.java:

 1 import android.content.Context;
 2 
 3 import java.io.ByteArrayOutputStream;
 4 import java.io.IOException;
 5 import java.io.InputStream;
 6 
 7 public class StreamTools {
 8     //把inStream转换成String
 9     public static String readStreamToString(InputStream in) throws IOException {
10         //定义一个内存输出流
11         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
12         int len = -1;
13         byte[] buffer = new byte[1024];//1kb
14         while ((len = in.read(buffer)) != -1) {
15             byteArrayOutputStream.write(buffer, 0, len);
16         }
17         in.close();
18         String content = new String(byteArrayOutputStream.toByteArray());
19         return content;
20     }
21 }

加权限

<?xml version="1.0" encoding="utf-8"?>
<manifest ……>

    <uses-permission android:name="android.permission.INTERNET"/>

    <application>
        ……
    </application>

</manifest>

以上就是出现错误的全部代码。虽然在有一些情况下会运行成功,但不久你就会发现,会崩的或者是出现异常3(不要学我写System.out.println("异常3"),要用Log,这里边与小白参考)。
上网查询问题,通过课本查询,都没有发现解决方法。网上有很多人问,有人说要在新的线程中写,有人说权限(其实一般不会发生这种低级问题),感觉回答的也是一些小白。很多并没有参考性。其中回答线程的应该是有些功底的了,下面我就发一下解决方法。

因为在4.0之后谷歌强制要求连接网络不能在主线程进行访问,所以以上的代码时不能上网的,即使加了权限也不行。此时我们为您将联网的逻辑写在新的线程中。

获取了网络信息后需要将信息展示在控件上(比如TextView),此时遇到了新的问题:更新UI异常。

这是因为更新UI必须在主线程中进行,所以引入新的API——Handler,重写Handler.handlerMessage()方法来进行更新UI;来要注意一个细节,Toast也是一个View,所以也不能在子线程中运行,也需要放在handlerMessage()中。

又有问题了:如何将在子线程要进行的逻辑在handlerMessage()中进行呢?也就是说主线程和子线程需要一个联系,不然怎么更新UI。所以新建Message对象,用Handler的sendMessage()向主线程发送Message对象,在主线程中接收,这样zhuxiancheng 就可以根据子线程发来的信息来进行应做的逻辑了。

说了这么多,不知同没听懂,还是代码实在

只需要修改MainActivity.java:

  1 package com.lgqchinese.httphaha;
  2 
  3 import android.content.Context;
  4 import android.os.Handler;
  5 import android.os.Message;
  6 import android.support.v7.app.AppCompatActivity;
  7 import android.os.Bundle;
  8 import android.view.View;
  9 import android.widget.EditText;
 10 import android.widget.TextView;
 11 import android.widget.Toast;
 12 
 13 import java.io.IOException;
 14 import java.io.InputStream;
 15 import java.net.HttpURLConnection;
 16 import java.net.MalformedURLException;
 17 import java.net.ProtocolException;
 18 import java.net.URL;
 19 
 20 public class MainActivity extends AppCompatActivity {
 21 
 22     private EditText et_path;
 23     private TextView tv_result;
 24     private static final int REQUESTSUEECSS = 0;
 25     private static final int REQUESTNOTFOUNT = 1;
 26 
 27     //在主线程中定义Handler
 28     private Handler handler = new Handler() {
 29         //重写方法
 30 
 31         @Override
 32         public void handleMessage(Message msg) {
 33 
 34             //区分发来的消息时哪一条
 35             switch (msg.what){
 36                 case REQUESTSUEECSS://代表请求成功
 37                     String content = (String) msg.obj;
 38                     tv_result.setText(content);
 39                     break;
 40                 case REQUESTNOTFOUNT://请求失败
 41                     Toast.makeText(getApplicationContext(), "请求资源不存在", Toast.LENGTH_SHORT).show();
 42                     break;
 43 
 44 
 45             }
 46 
 47         }
 48     };
 49 
 50 
 51     @Override
 52     protected void onCreate(Bundle savedInstanceState) {
 53         super.onCreate(savedInstanceState);
 54         setContentView(R.layout.activity_main);
 55 
 56         et_path = findViewById(R.id.et_path);
 57         tv_result = findViewById(R.id.tv_result);
 58 
 59         //打印当前线程的名字
 60         System.out.println("当前线程的名字" + Thread.currentThread().getName());
 61 
 62 
 63     }
 64 
 65     //点检就进行查看指定路径的源码
 66     public void click(View view) {
 67 
 68         //创建一个子线程
 69         new Thread() {
 70             @Override
 71             public void run() {
 72                 try {
 73                     //获取源码路径
 74                     String path = et_path.getText().toString().trim();
 75                     //创建url对象制定我们要访问的路径
 76                     URL url = new URL(path);
 77                     //拿到httpUrlConnection对象
 78                     HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
 79                     //设置请求方法
 80                     httpURLConnection.setRequestMethod("GET");//GET要求大写,默认get请求
 81                     //设置请求时间
 82                     httpURLConnection.setConnectTimeout(5000);
 83                     //获取服务器返回的状态码
 84                     int code = httpURLConnection.getResponseCode();
 85                     //如果code = 200,说明请求成功
 86                     if (code == 200) {
 87                         //获取服务器返回的数据,是以流的形式返回的
 88                         InputStream in = httpURLConnection.getInputStream();
 89                         System.out.println();
 90 
 91                         //将流转换成字符串
 92                         String content = StreamTools.readStreamToString(in);
 93 
 94                         //创建Message对象
 95                         Message msg = new Message();
 96                         msg.what = REQUESTSUEECSS;
 97                         msg.obj = content;
 98                         //用创建的Handler(助手)告诉系统要更新UI
 99                         handler.sendMessage(msg);
100 
101                         //展示到指定控件中
102 //                        tv_result.setText(content);
103 
104                     } else {
105                         //请求资源不存在,Toast是一个view,也不能再子线程更新UI
106                         Message msg = new Message();
107                         msg.what = REQUESTNOTFOUNT;
108                         handler.sendMessage(msg);
109 //                        Toast.makeText(getApplicationContext(), "请求资源不存在", Toast.LENGTH_SHORT).show();
110                     }
111 
112                 } catch (ProtocolException e) {
113                     e.printStackTrace();
114                     System.out.println("异常1");
115                 } catch (MalformedURLException e) {
116                     e.printStackTrace();
117                     System.out.println("异常2");
118                 } catch (IOException e) {
119                     e.printStackTrace();
120                     System.out.println("异常3");
121                 }
122             }
123         }.start();
124 
125 
126     }
127 }

可以在异常处再向主线程发信息,来提示用户加载失败,这里不再赘述,自练即可。

以上就是今天遇到的问题,个人感觉就是

因为在4.0之后谷歌强制要求连接网络不能在主线程进行访问

 

猜你喜欢

转载自www.cnblogs.com/lgqrlchinese/p/9937160.html