Android入门第55天-在Android里使用OKHttp组件访问网络资源
Posted TGITCIC
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android入门第55天-在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入门第55天-在Android里使用OKHttp组件访问网络资源的主要内容,如果未能解决你的问题,请参考以下文章
Android入门第44天-Android里使用动态BroadCast
Android入门第25天-Android里使用SimpleAdapter实现复杂的界面布局
Android入门第53天-在Android手机里使用SQLite内嵌式数据库
Android入门第56天-在Android里使用OKHttp多线程下载文件并展示其进度