Android入門之使用OKHttp組件訪問網絡資源
簡介
今天的課程開始進入高級課程類瞭,我們要開始接觸網絡協議、設備等領域編程瞭。在今天的課程裡我們會使用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訪問網絡資源內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Android 中 WebView 的基本用法詳解
- Android WebView控件基本使用示例
- Android文本視圖TextView實現跑馬燈效果
- Android簡單實現文件下載
- Android 使用RecycleView列表實現加載更多的示例代碼