Android中的网络与数据(一)

Android中的网络与数据(一)

前言:在写项目的时候,由于将网络请求简单封装成了一个类,因此出了很多问题。所以简单写了这个博客

并不想系统的介绍。想用更简单能理解的方式说明可能发生的问题

背景

在Android中,我们需要大量的数据,而那些数据不能永远保存在手机本地。试想一下,当你打开淘宝的时候,你只能浏览已经写死的数据。那自然就没有了那么琳琅满目的商品。所以,大多数的数据都是从网络中获取到的。于是,就需要在程序中去访问互联网(服务器)并且请求数据。

网络与数据

不得不说,Android是一个非常全面的工具。她为网络请求基本没有要求,又到处限制。说简单,可以用原生工具类解决问题;说难,使用的条条框框又比较复杂……

简单的开始

在Android中使用网络的开始,不妨先直接在Activity中写一个试试?这里用原生的net工具类:

public class MainActivity extends AppCompatActivity {
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
​
        URL url = null;
        try {
            // 可能报IO异常
            url = new URL("https://www.baidu.com");
            HttpURLConnection conn = ((HttpURLConnection) url.openConnection());
            conn.setRequestMethod("POST");
​
            OutputStream outputStream = conn.getOutputStream();
​
            // 在这里进行网络请求、获取数据
            
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

于是就可以发现,他真的没跑起来……:

NetworkOnMainThreadException 翻译过就是在MainTread中使用网络,也就是说,android是不允许在主线程(UI线程)中访问网络的。

有的同学可能会问:为什么不呢?

可以想一下,如果我请求操作的时候界面直接卡死了(因为主线程在等待网络的过程中,而这个过程很有可能非常长),那这时候叫天天不灵,叫地地不应,这时候整个系统都挺蒙圈的,到底要不要继续等呢?

直接放弃吧,万一一下就好了呢;继续等吧,万一耽误其他功能了呢。所以当然不能再主线程使用了呀。那我们该怎么用呢

基本使用

不能在主线程用,那我新建一个线程呗:

public class MainActivity extends AppCompatActivity {
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 新建了一个线程
        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");
​
                    OutputStream outputStream = conn.getOutputStream();
​
                    // 进行网络请求、获取数据
                    
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();
    }
}

编译,运行:

Permission denied (missing INTERNET permission?) 也就是 权限缺失(缺少网络权限?)

感慨一句:Android实在是太细啦。

权限问题其实非常简单,也很好理解:你在我的手机里就像我的一个宠物。你要的所有东西都得问问我,我不同意,你就什么也干不了。这样也能保护一些隐私数据,非常好用。

怎么解决?找到Manifast文件,在manifast标签下加入:

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

最终效果:

再次运行,这下终于没报错了。

更深一步

虽然这下没报错,但是似乎还没什么效果。看着界面上的Hello Word陷入了沉思。请求的数据当然不能白白请求。能看到才是真的成功。于是先对界面和请求做一些简单改造好了

界面:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
​
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="这里会放着请求来的数据"
        android:id="@+id/textView"/>
​
</LinearLayout>

界面效果:

MainActivity

public class MainActivity extends AppCompatActivity {
    
    private TextView tv;
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 得到textView控件
        tv = findViewById(R.id.textView);
        // 从网络中请求数据
        getData();
    }
​
    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();
                    
                    byte[] buffer = new byte[1024];
                    StringBuilder data = new StringBuilder();
                    // 从输入流中不断的读取数据并拼接
                    while (inputStream.read(buffer) > 0) {
                        data.append(Arrays.toString(buffer));
                    }
                    
                    setData(data.toString());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();
    }
​
    // 为控件设置内容
    private void setData(String data) {
        tv.setText(data);
    }
}

ok, 编译运行:

fine, 这次又出什么幺蛾子了:

Only the original thread that created a view hierarchy can touch its views.

也很好理解:只有在主线程(UI线程)中才能访问到主线程中控件

上边其实提到了很多次UI线程。其实可以简单理解成UI线程就是主线程。他们是一个东西

那怎么办呢?只有在主线程中才能设置控件,而主线程中又没办法进行网络请求。看上去已经没有解决方法的?

别急,Android早就想到了这个问题,于是,runOnUiThread方法出现:

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();
​
                    byte[] buffer = new byte[1024];
                    StringBuilder data = new StringBuilder();
                    // 从输入流中不断的读取数据并拼接
                    while (inputStream.read(buffer) > 0) {
                        data.append(Arrays.toString(buffer));
                    }
                    // 在主线程中执行方法
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            setData(data.toString());
                        }
                    });
​
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();
    }

runOnUiThread:翻译过来就是在UI线程中执行。编译运行试试:

OK,姑且不论这是什么。总之我们终于是得到了数据啦!

总结一下

那么我们获取数据一共需要几步呢?

  1. 设置网络权限
  2. 创建新线程
  3. 新线程中获取数据
  4. 在UI线程中展示数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飛_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值