Android入门之使用OKHttp组件访问网络资源

2022-12-27 15:46:08
目录
简介课程目标代码菜单res\menu\pop_menu.xml主UI界面MainActivity

简介

今天的课程开始进入高级课程类了,我们要开始接触网络协议、设备等领域编程了。在今天的课程里我们会使用OKHttp组件来访问网络资源而不是使用Android自带的URLConnection。一个是OKHttp组件更方便二个是OKHttp组件本身就带有异步回调功能。

下面就进入课程。

课程目标

我们的课程目标有4个点:

    使用OKHttp组件;使用OKHttp组件加载网络图片显示在APP的ImgView里;使用OKHttp组件加载给定网页代码显示在ScrollView里;使用OKHttp组件加载给定网页显示在WebView里;

    以上过程都为异步加载。

    代码前在gradle里要先声明对于OKHttp组件的引用

    要使用OKHttp组件,我们必须要在build.gradle中加入以下语句:

    implementation 'com.squareup.okhttp3:okhttp:3.10.0'
    

    以下是加完上述语句后的build.gradle。

    访问网络资源需要给到APP以权限

    我们因为要访问网络资源,因此我们需要给到APP以相应的权限。编辑AndroidManifest.xml文件,并加入以下两行声明。

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

    加完后的AndroidManifest.xml长这样

    代码

    菜单res\menu\pop_menu.xml

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/menuItemDisplayPic" android:title="加载图片" />
        <item android:id="@+id/menuItemDisplayHtmlCode" android:title="加载网页代码" />
        <item android:id="@+id/menuItemDisplayHtmlPage" android:title="加载网页" />
    </menu>

    主UI界面

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">
     
        <Button
            android:id="@+id/buttonShowMenu"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/textColor"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="10dp"
            android:text="展示弹出菜单" />
     
        <ImageView
            android:id="@+id/imgPic"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone" />
     
        <ScrollView
            android:id="@+id/scroll"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone">
     
            <TextView
                android:id="@+id/htmlTxt"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </ScrollView>
        <WebView
            android:id="@+id/webView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
     
    </LinearLayout>

    MainActivity

    package org.mk.android.demo.http;
     
    import androidx.annotation.NonNull;
    import androidx.appcompat.app.AppCompatActivity;
     
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.util.Log;
    import android.view.MenuItem;
    import android.view.View;
    import android.webkit.WebView;
    import android.widget.Button;
    import android.widget.ImageView;
    import android.widget.PopupMenu;
    import android.widget.ScrollView;
    import android.widget.TextView;
     
    import java.io.IOException;
    import java.io.InputStream;
    import java.nio.charset.Charset;
    import okhttp3.OkHttpClient;
    import okhttp3.Call;
    import okhttp3.Callback;
    import okhttp3.Request;
    import okhttp3.Response;
    import okhttp3.ResponseBody;
    import okio.Buffer;
    import okio.BufferedSource;
    public class MainActivity extends AppCompatActivity {
     
        private String TAG = "DemoOkHttp";
        private Button buttonShowMenu;
        private TextView htmlTxt;
        private ImageView imgPic;
        private WebView webView;
        private ScrollView scroll;
        private Bitmap bitmap;
        private String htmlContents;
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            buttonShowMenu = (Button) findViewById(R.id.buttonShowMenu);
            htmlTxt = (TextView) findViewById(R.id.htmlTxt);
            imgPic = (ImageView) findViewById(R.id.imgPic);
            webView = (WebView) findViewById(R.id.webView);
            scroll = (ScrollView) findViewById(R.id.scroll);
            buttonShowMenu.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    PopupMenu popup = new PopupMenu(MainActivity.this, buttonShowMenu);
                    popup.getMenuInflater().inflate(R.menu.pop_menu, popup.getMenu());
                    popup.setOnMenuItemClickListener(new MenuItemClick());
                    popup.show();
                }
            });
        }
     
        // 定义一个隐藏所有控件的方法:
        private void hideAllWidget() {
            imgPic.setVisibility(View.GONE);
            scroll.setVisibility(View.GONE);
            webView.setVisibility(View.GONE);
        }
     
        private class MenuItemClick implements PopupMenu.OnMenuItemClickListener {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                String imgPath = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.alicdn.com%2Fi2%2F2542318073%2FO1CN01fJvTi029VTwR16EvP_%21%212542318073.jpg&refer=http%3A%2F%2Fimg.alicdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1673938156&t=69e5ee87fbf4b81b5f6eea53ed5b5158";
                String htmlPagePath = "https://www.baidu.com";
                switch (item.getItemId()) {
                    case R.id.menuItemDisplayPic:
                        downLoadImgFromPath(imgPath);
                        break;
                    case R.id.menuItemDisplayHtmlCode:
                        getHtmlAsync(htmlPagePath, 102);
                        break;
                    case R.id.menuItemDisplayHtmlPage:
                        getHtmlAsync(htmlPagePath, 103);
     
                        break;
                }
                return true;
            }
        }
     
        private Handler httpHandler = new Handler(new Handler.Callback() {
            @Override
            public boolean handleMessage(@NonNull Message msg) {
                Log.i(TAG, ">>>>>>receive handler Message msg.what is: " + msg.what);
                switch (msg.what) {
                    case 101:
                        hideAllWidget();
                        imgPic.setVisibility(View.VISIBLE);
                        Log.i(TAG, "begin to show img from bitmap type's data");
                        imgPic.setImageBitmap(bitmap);
                        break;
                    case 102:
                        hideAllWidget();
                        Log.i(TAG, "begin to show html contents");
                        scroll.setVisibility(View.VISIBLE);
                        Log.d(TAG, ">>>>>>htmlContents->\n" + htmlContents);
                        htmlTxt.setText(htmlContents);
                        break;
                    case 103:
                        hideAllWidget();
                        Log.i(TAG, "begin to show html page in webview");
                        webView.setVisibility(View.VISIBLE);
                        Log.d(TAG, ">>>>>>htmlContents->\n" + htmlContents);
                        webView.loadDataWithBaseURL("", htmlContents, "text/html", "UTF-8", "");
                        break;
                }
                return false;
            }
        });
        /**
         * 使用okhttp 异步下载图片
         */
        private void downLoadImgFromPath(String path) {
     
            OkHttpClient client = new OkHttpClient();
     
            Request request = new Request.Builder()
                    .url(path)
                    .build();
            Log.i(TAG, ">>>>>>into doanloadImgFromPath method");
            try {
                Call call = client.newCall(request); // 使用client去请求
     
                call.enqueue(new Callback() { // 回调方法,>>> 可以获得请求结果信息
                    InputStream inputStream = null;
     
                    @Override
                    public void onFailure(Call call, IOException e) {
                        Log.e(TAG, ">>>>>>下载失败", e);
                    }
     
                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        Log.i(TAG, ">>>>>>into onResponse method");
                        try {
                            inputStream = response.body().byteStream();
                            Log.i(TAG, ">>>>>>the response code is: " + response.code());
                            if (200 == response.code()) {
                                bitmap = BitmapFactory.decodeStream(inputStream);
                                Log.i(TAG, ">>>>>>sendEmptyMessage 101 to handler");
                                httpHandler.sendEmptyMessage(101);
                            } else {
                                Log.i(TAG, ">>>>>>下载失败");
                            }
                        } catch (Exception e) {
                            Log.e(TAG, ">>>>>>okHttp onResponse error: " + e.getMessage(), e);
                        } finally {
                            try {
                                inputStream.close();
                            } catch (Exception e) {
                            }
                        }
                    }
                });
     
            } catch (Exception e) {
                Log.e(TAG, ">>>>>>OkHttp调用失败", e);
            }
        }
     
        //异步不需要创建线程
        private void getHtmlAsync(String path, int handlerCode) {
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder().url(path).build();
            //请求的call对象
            Call call = client.newCall(request);
            //异步请求
            call.enqueue(new Callback() {
     
                //失败的请求
                @Override
                public void onFailure(@NonNull Call call, @NonNull IOException e) {
                    Log.e(TAG, ">>>>>>加载path失败", e);
                }
     
                //结束的回调
                @Override
                public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                    //响应码可能是404也可能是200都会走这个方法
                    Log.i(TAG, ">>>>>>the response code is: " + response.code());
                    if (200 == response.code()) {
                        try {
                            ResponseBody responseBody = response.body();
                            BufferedSource source = responseBody.source();
                            source.request(Long.MAX_VALUE);
                            Buffer buffer = source.buffer();
                            Charset UTF8 = Charset.forName("UTF-8");
                            htmlContents = buffer.clone().readString(UTF8);
                            Log.i(TAG, ">>>>>>sendEmptyMessage " + handlerCode + " to handler");
                            httpHandler.sendEmptyMessage(handlerCode);
                            Log.i(TAG, "getAsyncHtmlGet成功");
                        } catch (Exception e) {
                            Log.e(TAG, ">>>>>>read htmlPage error: " + e.getMessage(), e);
                        }
                    }
                }
            });
        }
    }

    核心代码导读

    我们使用的是

    Call call = client.newCall(request);
    

    它本身就是支持异步的一个调用。 然后在得到相应的Http报文后使用一个Handler向APP主界面发起改变界面中内容的调用。

    这边有一点需要注意的是OKHttp在返回的response.body()这个API,在一次请求里只能被使用一次。即如果你已经有以下一句类似的调用:

    inputStream = response.body().byteStream();
    

    你就不能再在它以下的语句中调用一次response.body()了。

    自己动一下手试试看效果吧。

    到此这篇关于Android入门之使用OKHttp组件访问网络资源的文章就介绍到这了,更多相关Android OKHttp访问网络资源内容请搜索易采站长站以前的文章或继续浏览下面的相关文章希望大家以后多多支持易采站长站!