Advertisement

Android入门第55天-在Android里使用OKHttp组件访问网络资源

阅读量:

简介

今天我们的课程即将深入学习高级课程模块。今天我们将深入学习网络协议以及相关领域的编程技术,在今天的课堂上我们主要采用的是OKHttp组件来进行网络资源的访问操作作为主要原因之一是该组件操作更加简便;另一个原因是该组件内置了异步回调机制以提高处理效率和响应速度。

下面就进入课程。

课程目标

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

  1. 该组件可被用于...
  2. 通过OKHttp组件能够将网络图片加载至APP中的ImgView字段中。
  3. 该组件允许将指定网页的代码片段展示于ScrollView界面中。
  4. 通过该组件可将任意网页内容嵌入到WebView元素中。

以上过程都为异步加载。

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

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

复制代码
    implementation 'com.squareup.okhttp3:okhttp:3.10.0'
    
    
    AI助手

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

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

我们因为需要访问网络资源而必须将相应的权限授权给APP。请编辑AndroidManifest.xml文件并在其中添加以下代码片段:

复制代码
     <uses-permission android:name="android.permission.INTERNET" />

    
     <uses-permission android:name="android.permission.WAKE_LOCK" />
    
    
    
    
    AI助手

加完后的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>
    
    
    
    
    AI助手

主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>
    
    
    
    
    AI助手

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);
    
                 }
    
             }
    
         }
    
     });
    
     }
    
 }
    
    
    
    
    AI助手

核心代码导读

我们使用的是

复制代码
    Call call = client.newCall(request);
    
    AI助手

该操作本身是异步操作。
在收到相应的Http报文后,通过一个Handler向APP主界面发起改变界面中内容的请求。

这边需要特别注意的是,在使用OKHttp时,在同一个响应体(response.body())这个API接口中只能进行一次数据读取操作。具体来说,请注意以下类似的行为:

如果已经在代码中存在以下类似的行为:

复制代码
    inputStream = response.body().byteStream();
    
    
    AI助手

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

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

全部评论 (0)

还没有任何评论哟~