1

在实验的安卓界面完成后,下一步就是对接后台了。在实际的应用中,通常需要从后台接口中获取或修改数据库数据,展示在安卓界面中。为了完成这样的功能,学习了安卓的网络编程实例。

使用网络获取数据

使用网络技术也很简单,无非是发送http请求并解析返回数据,在这里使用了android的网络通信库OkHttp,它能更加简化网络请求的步骤。
首先在app/build.gradle文件中声明OkHttp依赖:

implementation("com.squareup.okhttp3:okhttp:4.2.1")

AndroidMainfest.xml中声明网络权限:

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

创建一个OkHttpClient对象,再创建一个request请求发起一个http请求:

OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url("http://192.168.2.234:8080/city").build();
Response response = okHttpClient.newCall(request).execute();

其中返回来的json数据,可以从response.string()中获取到返回流的json字符串,再用相应的json解析工具,类似gson解析json就可以获取到我们想要的数据了。

// 使用gson解析json数据
City[] cities = gson.fromJson(response.body().string(), City[].class);

子线程请求数据

当请求服务器获取数据时,考虑到网络原因,服务器往往不能立刻响应我们的网络请求,如果在主线程中使用网络请求,会造成主线程堵塞,给用户带来不好的体验,甚至会因为长时间未响应被关闭。因此,网络请求应该在子线程中进行。

 new Thread(new Runnable() {
            @Override
            public void run() {
                // 使用http请求
                ....
            }
        }).start();

获取到数据以后,应该把获取到的数据更新到界面上。但是,安卓并不允许在子线程中更新ui,因为多线程更新ui会产生许多的线程同步和线程安全问题。要在子线程中解决ui更新问题,还得使用安卓的异步消息处理机制。

异步消息处理

因为之前一直在写web,说到异步处理就想起了JavaScript。与安卓一样,js也是频繁的修改dom,为此,js设计为单线程的语言。js处理异步的方式就是采用事件循环,当主线程跑完代码后,就会不断循环从消息队列中读取消息执行。安卓的异步消息处理与js的类似,主要由四个部分组成:Message、Handler、MessageQueue、Looper。

Message

Message表示在线程之间传递的消息,它可以携带少量的信息在不同的线程中交换数据。通过Message的what、arg1、arg2、obj字段来携带数据。

Handler

处理者,用于发送和处理消息。通过Handler的sendMessage()方法发送消息,被looper回调后通过handleMessage处理消息。

MessageQueue

消息队列,存放所有通过handler发送的消息。每个线程只有一个消息队列。

Looper

Lopper相当于每个线程中MessageQueue的管家,它会处于无限循环中,每当发现MessageQueue存在一条消息,就会将它取出,并传递到Handler的handlerMessage()方法中,每个线程也只有一个looper。

他们之间的协作关系如下图:
image.png

使用异步消息发送http请求:

public class MainActivity extends AppCompatActivity {
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            Object message = msg.obj; // 获取携带的数据
            // 这里可以更新ui
        }
    };
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                // 发送http请求
                OkHttpClient okHttpClient = new OkHttpClient();
                Request request = new Request.Builder().url("http://192.168.2.234:8080/city").build();
                Response response = okHttpClient.newCall(request).execute();
                City[] cities = gson.fromJson(response.body().string(), City[].class);
                Message message = new Message();
                message.obj = cities; // 这里可以携带数据
                handler.sendMessage(message);
                }
        }).start();

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

}

来梳理以下具体的流程:我们创建了一个Handler对象并覆写了它的handlerMessage方法,然后在子线程中发送http请求,等请求返回数据后,创建一个Message对象,将请求回来的数据放入Message对象的obj字段中,然后通过handler.sendMessage()方法将消息放入消息队列中。因为handler对象是在主线程中创建的,所以消息被放在了主线程的消息队列中。在主线程的looper对象发现消息队列中存在消息时,就会把消息取出,执行Message的Hanler的handlerMessage方法。因为handlerMessage方法是在主线程中运行的,所以可以对ui进行操作。

基于安卓的异步消息的处理机制,我们就可以在子线程发送http请求数据,然后在主线程中更新ui了。


鲸冬香
456 声望27 粉丝