Android中的网路与数据(二)
前情提要:在上一篇文章中,我们已经从0开始进行了几个尝试。并且成功的从网络中获取到了数据。
但是这个数据是以二进制的形式展现出来的。那么这篇博客就将数据进行处理并且封装成方法。
对网络流中数据进行处理
首先对数据处理之前,我们先看看数据是什么:
emmm,这种东西肯定不是我们想获取的数据吧。我们想要的数据至少也是给人看的。不管是什么东西,至少你得变成英文吧。
设置“阅读器”
而现在是用数组的方式展示的。那人自然是看不懂的。所以我们该怎么办呢?
很简单!设置编码格式就好了!
private void getData() { new Thread(new Runnable() { @Override public void run() { URL url = null; try { url = new URL("https://www.baidu.com"); HttpURLConnection conn = ((HttpURLConnection) url.openConnection()); conn.setRequestMethod("POST"); // 获取连接的输入流 InputStream inputStream = conn.getInputStream(); // 新建“阅读器”。可以为流设置编码格式 BufferedReader br = new BufferedReader( new InputStreamReader(inputStream, "utf-8") ); StringBuilder data = new StringBuilder(); // 一次读一行,读到空就跳出 while (br.readLine() != null) { data.append(br.readLine()); } // 在主线程中设置内容 runOnUiThread(new Runnable() { @Override public void run() { setData(data.toString()); } }); } catch (IOException e) { throw new RuntimeException(e); } } }).start(); }
如果你有不太明白的地方,请综合上一篇博客内容,或者给我留言
相比之前,我们只是为流添加了一个BufferReader。这个BufferReader就像一个阅读器。可以从流中读取二进制编码,然后将这个集按照设置的格式进行解码。
发生了什么?
就像是WPS一样。他能读取一个*.doc的文件,并且按照规则,设置字体的大小、粗细、颜色等等。
这个BufferReader就像一个WPS。而流就是一个Word文件。按照UTF-8的格式进行翻译。就这样我们得到了:
这下看懂了。哪怕我看不懂其他的,最中间的百度一下也是映入眼帘。这下至少是人能看懂的了。
一些思考
但是我们知道,直接访问www.baidu.com的话。看到的内容并不是这种吧。
当我们用浏览器访问时,浏览器会自动对HTML进行解析并进行更深的操作。而我们只是去读取到了一个HTML,如果没有解析看到的就是这样的效果。如果了解过web就会感到好理解的多。
总结与问题
至此,我们在MainActivity中进行了网络请求,并且获取数据,最后展示出来。我们经历了
-
设置网络权限(只用设置一次)
-
新建线程
-
在线程中进行网络请求
-
为数据创建“阅读器”,并进行翻译
-
在主线程中设置内容
这个过程不算困难,但可以说非常复杂了。如果我们在很多的活动中都需要网络请求,并在请求的基础上做了更深的操作,就要写很多相似甚至重复的代码。至少我是非常不爽的。因此我想要进行一下自己的尝试。
将网络请求进行封装
Java是一个面向对象的语言
如果我将网络请求封装成一个类。需要进行请求时,只需要调用,这样我就不用再走一遍那一套了。但是,我们该怎么做?
分析
既然我们要封装了,那就必须为这个方法设置一些形参与返回值,来适应各种各样的场合。
需要的数据
在各种请求中,不是所有请求都访问一个地址。操作也是各种各样。
比如,这里需要图片,那里需要文本,请求的地址肯定是不一样的。另外,获取到了数据,进行的处理也是各种各样。因此,一个简单的方法就出现了,我们需要的是一个地址(String)和操作(Runnable)
返回的数据
有需要就有返回。不同的类在不同的请求里,对不同的结果做不同的处理。
举个栗子:在登录界面,如果登录成功,我需要进行跳转;失败了,需要进行提示。而加载数据界面,成功了需要展示数据;失败,返回上一个界面。如此,我们就简单返回是否成功(boolean)
而且,大多时候,还需要从网络流中获取的数据。姑且认为数据是字符串类型。因此,传递一个参数data(StringBuilder)用来接受数据
封装
新建一个Java,就叫HttpUtil了。简单编写代码
public class HttpUtil { /** * 进行网络请求,封装数据 * * @param url 访问的地址 * @param toData 封装的参数 用数组封装下,以便在线程中访问数据并返回 * @param runnable 回调的行为 * @return 是否成功 */ public static boolean post(String url,StringBuilder[] toData, Runnable runnable) { try { // 新建一个线程 new Thread(new Runnable() { @Override public void run() { try { // 创建连接 URL httpUrl = new URL(url); HttpURLConnection connection = (HttpURLConnection) httpUrl.openConnection(); connection.setRequestMethod("POST"); // 获取连接的输入流 InputStream inputStream = connection.getInputStream(); // 创建“阅读器” BufferedReader br = new BufferedReader( new InputStreamReader(inputStream, "utf-8") ); // 处理数据 StringBuilder data = new StringBuilder("这是被封装处理的数据"); while (br.readLine() != null) { data.append(br.readLine()); } toData[0] = data; // 回调 runnable.run(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(); } } }).start(); return true; } catch (Exception e) { return false; } } }
此时我们的Main成了这样:
public class MainActivity extends AppCompatActivity { private TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = findViewById(R.id.textView); getData(); } private void getData() { // 封装数组 StringBuilder[] data = {new StringBuilder()}; // 直接调用(匿名内部类Runnable) boolean result = HttpUtil.post("https://www.baidu.com/", data, new Runnable() { @Override public void run() { // 别忘了在主线程中进行设置数据操作 runOnUiThread(new Runnable() { @Override public void run() { setData(data[0].toString()); } }); } }); } private void setData(String data) { tv.setText(data); } }
看效果:
这样,就做到了封装进行的操作啦