Okhttp是一个处理网络请求的开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献(该公司还贡献了Picasso),用于替代HttpUrlConnection和Apache HttpClient(android API23 6.0里已移除HttpClient,现在已经打不出来)。
下面就对Okhttp的单独使用做一个简单的封装(在App版本更新的例子里抽取出来的,里面的一些名字可能跟版本更新有关,使用的是时候注意适当更改一下):
1.添加依赖
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
2.添加网络权限
<uses-permission android:name="android.permission.INTERNET"/>
3.开始写类内容
(1)新建类AppUpdater。
我们在做一个可以独立模块功能的时候,我们尽可能有一个对外的类,,这里面对外的类就是AppUpdater。其他的一些操作都放到这个类的内部或者其他类里面,对使用者是不可见的;也就是说,使用者所有的操作都是通过AppUpdater进行调用。所以要把这个类写成一个单例。他还需要一个网络模块,通过接口隔离实现,所以要建立一个接口,INetManager。
package com.wjy.myupdateapp.updater;
import com.wjy.myupdateapp.updater.net.INetManager;
import com.wjy.myupdateapp.updater.net.OkhttpNetManager;
/**
* created by WangJinyong
*/
public class AppUpdater {
//单例
private static AppUpdater sInstance = new AppUpdater();
//网络请求,下载的能力
//okhttp,volley,httpclient,httpurlconn
/**
* 接口隔离 具体实现 可以随意使用哪一种网路请求,只要改变一下NetManager就可以了,
* 这里使用的是OkhttpNetManager,如果使用其他网路请求,则将OkhttpNetManager改成其他网路请求
*
*/
private INetManager mNetManager = new OkhttpNetManager();
public void setNetManager(INetManager manager){
mNetManager = manager;
}
public INetManager getNetManager(){
return mNetManager;
}
//对外提供一个static方法
public static AppUpdater getInstance(){
return sInstance;
}
}
(2)上面用到一个网络接口INetManager,所以新建一个INetManager接口,这个接口里面有get请求、post请求、upload上传、download下载以及cancel关闭。
get请求:需要传递url,异步的Callback
post请求:需要传递url,RequestBody请求体,异步的Callback
upload上传:可以跟post一样
download下载:需要传递url,上传的文件File,异步的Callback
cancel关闭
(3)新建get请求里的Callback,这里起名叫INetCallBack,里面返回成功和失败
package com.wjy.myupdateapp.updater.net;
/**
* Created by wjy.
* Date: 2019/11/19
* Time: 11:20
* Describe: 网络请求 get
*/
public interface INetCallBack {
void success(String response);
void failed(Throwable throwable);
}
(4)新建download下载里面的Callback,这里起名叫INetDownloadCallBack,需要返回成功、失败、下载进度。
package com.wjy.myupdateapp.updater.net;
import java.io.File;
/**
* Created by wjy.
* Date: 2019/11/19
* Time: 11:20
* Describe: 下载接口 回调
*/
public interface INetDownloadCallBack {
void success(File apkFile);
void progress(int progress);
void failed(Throwable throwable);
}
(5)在上面(1)AppUpdater中,接口隔离网络模块,来具体实现,新建了一个OkhttpNetManager来实现INetManager,这样写的好处是可以随意使用哪一种网路请求,只要改变一下NetManager就可以了,这里使用的是OkhttpNetManager,如果使用其他网路请求,则将OkhttpNetManager改成其他网路请求。
package com.wjy.myupdateapp.updater.net;
import android.os.Handler;
import android.os.Looper;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* Created by wjy.
* Date: 2019/11/19
* Time: 11:33
* Describe: ${describe}
*/
public class OkhttpNetManager implements INetManager {
private static OkHttpClient sOkhttpClient;
private static Handler sHandler = new Handler(Looper.getMainLooper());
static {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(5*1000, TimeUnit.SECONDS);
sOkhttpClient = builder.build();
//http
//https 自签名,Okhttp握手错误
// builder.sslSocketFactory();
}
@Override
public void get(String url, final INetCallBack callBack,Object tag) {
//requestbuilder -> Request -> Call -> execute/enqueue
Request.Builder builder = new Request.Builder();
Request request = builder.url(url).get().tag(tag).build();
Call call = sOkhttpClient.newCall(request);
// Response response = call.execute();//同步
call.enqueue(new Callback() {//异步
@Override
public void onFailure(Call call, final IOException e) {
//非 ui 线程
sHandler.post(new Runnable() {
@Override
public void run() {
callBack.failed(e);//把异常传过去
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try {//可能会产生异常
final String string = response.body().string();
sHandler.post(new Runnable() {
@Override
public void run() {
callBack.success(string);
}
});
} catch (Exception e) {
e.printStackTrace();
callBack.failed(e);//把异常传过去
}
}
});
}
@Override
public void post(String url,RequestBody requestBody, final INetCallBack callBack) {
Request.Builder builder = new Request.Builder();
Request request = builder
.url(url)
.post(requestBody)//传递请求体 //与get的区别在这里
.build();
Call call = sOkhttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, final IOException e) {
//非 ui 线程
sHandler.post(new Runnable() {
@Override
public void run() {
callBack.failed(e);//把异常传过去
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try {//可能会产生异常
final String string = response.body().string();
sHandler.post(new Runnable() {
@Override
public void run() {
callBack.success(string);
}
});
} catch (Exception e) {
e.printStackTrace();
callBack.failed(e);//把异常传过去
}
}
});
}
@Override
public void upload(String url, RequestBody requestBody, final INetCallBack callBack) {
Request.Builder builder = new Request.Builder();
Request request = builder
.url(url)
.post(requestBody)//传递请求体 //与get的区别在这里
.build();
Call call = sOkhttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, final IOException e) {
//非 ui 线程
sHandler.post(new Runnable() {
@Override
public void run() {
callBack.failed(e);//把异常传过去
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try {//可能会产生异常
final String string = response.body().string();
sHandler.post(new Runnable() {
@Override
public void run() {
callBack.success(string);
}
});
} catch (Exception e) {
e.printStackTrace();
callBack.failed(e);//把异常传过去
}
}
});
}
@Override
public void download(String url, final File targetFile, final INetDownloadCallBack callback,Object tag) {
if (targetFile.exists()){//判断是否存在
targetFile.getParentFile().mkdirs();
}
Request.Builder builder = new Request.Builder();
Request request = builder.url(url).get().tag(tag).build();
Call call = sOkhttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
callback.failed(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
InputStream is = null;
OutputStream os = null;
try {
final long totalLen = response.body().contentLength();
is = response.body().byteStream();
os = new FileOutputStream(targetFile);
byte[] buffer = new byte[8*1024];
long curLen = 0;
int bufferLen = 0;
while (!call.isCanceled() && (bufferLen = is.read(buffer)) !=-1){
os.write(buffer,0,bufferLen);
curLen += bufferLen;
final long finalCurLen = curLen;
sHandler.post(new Runnable() {
@Override
public void run() {
callback.progress((int) (finalCurLen * 1.0f / totalLen * 100));
//*1.0f 原因:一个小的数字除以一个大的数字,正常除的话始终为0,* 1.0f就会转化为float对象
//这样除完就是个零点几的小数,再乘以100就是一个几十的数字
}
});
}
if (call.isCanceled()){
return;
}
try {
targetFile.setExecutable(true,false);//可执行
targetFile.setReadable(true,false);//可读
targetFile.setWritable(true,false);//可写
} catch (Exception e) {
e.printStackTrace();
}
sHandler.post(new Runnable() {
@Override
public void run() {
callback.success(targetFile);
}
});
} catch (final Throwable e) {
if (call.isCanceled()){
return;
}
e.printStackTrace();
sHandler.post(new Runnable() {
@Override
public void run() {
callback.failed(e);
}
});
}finally {
if (is != null){
is.close();
}
if (os != null){
os.close();
}
}
}
});
}
@Override
public void cancel(Object tag) {
//排队的
List<Call> queuedCalls = sOkhttpClient.dispatcher().queuedCalls();
if (queuedCalls != null){
for (Call call : queuedCalls){
if (tag.equals(call.request().tag())){
call.cancel();
}
}
}
//正在执行的(正在下载的)
List<Call> runningCalls = sOkhttpClient.dispatcher().runningCalls();
if (runningCalls != null){
for (Call call : runningCalls){
if (tag.equals(call.request().tag())){
call.cancel();
}
}
}
}
}
4.每种请求的使用
(1)post请求的使用
btn_post.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
RequestBody requestBody = new FormBody.Builder()//创建表单请求体
.add("version",String.valueOf(AppUtils.getVersionCode(MainActivity.this)))
.build();
AppUpdater.getInstance().getNetManager().post(URL_HOST, requestBody, new INetCallBack() {
@Override
public void success(String response) {
Log.e("tag","请求成功response="+response);
}
@Override
public void failed(Throwable throwable) {
throwable.printStackTrace();
Toast.makeText(MainActivity.this,"请求失败!",Toast.LENGTH_SHORT).show();
}
});
}
});
(2)文件上传
btn_upload.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String filePath = "/sdcard/UVCCamera/img_goods.png";//文件地址
File file = new File(filePath);
Log.e("tag","file.getName()="+file.getName());
RequestBody fileBody = RequestBody.create(MediaType.parse("image/jpeg"),file);//MediaType.parse("image/*")参考https://www.w3school.com.cn/media/media_mimeref.asp
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file",file.getName(),fileBody)
.build();
AppUpdater.getInstance().getNetManager().upload(URL, requestBody, new INetCallBack() {
@Override
public void success(String response) {
Log.e("tag","response="+response);
}
@Override
public void failed(Throwable throwable) {
Log.e("tag","failed");
}
});
}
});
(3)base64图片上传,就是post请求
btn_uploadImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String stream = null;
String filePath = "/sdcard/UVCCamera/img_goods.png";//图片地址
stream = Base64StringTool.getcomImageBase64(Base64StringTool.getSmallBitmap(filePath));
if (TextUtils.isEmpty(stream)) {
Toast.makeText(MainActivity.this,"图片上传失败!",Toast.LENGTH_SHORT).show();
return;
}
RequestBody requestBody = new FormBody.Builder()//创建表单请求体
.add("file",stream)
.build();
AppUpdater.getInstance().getNetManager().post(URL, requestBody, new INetCallBack() {
@Override
public void success(String response) {
Log.e("tag","请求成功response="+response);
}
@Override
public void failed(Throwable throwable) {
throwable.printStackTrace();
Toast.makeText(MainActivity.this,"请求失败!",Toast.LENGTH_SHORT).show();
}
});
}
});
(4)get请求,这里以App下载更新为例
btn_updater.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AppUpdater.getInstance().getNetManager().get(url, new INetCallBack() {
@Override
public void success(String response) {
Log.e("tag","response="+response);
//1.解析json
DownloadBean downloadBean = DownloadBean.parse(response);
if (downloadBean == null){
Toast.makeText(MainActivity.this,"版本检测接口返回数据异常!",Toast.LENGTH_SHORT).show();
return;
}
//2.检测:是否需要弹窗
try {
long versinCode = Long.parseLong(downloadBean.versionCode);
if (versinCode <= AppUtils.getVersionCode(MainActivity.this)){
Toast.makeText(MainActivity.this,"已经是最新版本,无需更新!",Toast.LENGTH_SHORT).show();
return;
}
} catch (NumberFormatException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this,"版本检测接口返回版本号异常!",Toast.LENGTH_SHORT).show();
return;
}
//3.弹窗
UpdateVersionShowDialog.show(MainActivity.this,downloadBean);
//4.下载
}
@Override
public void failed(Throwable throwable) {
throwable.printStackTrace();
Toast.makeText(MainActivity.this,"版本更新失败!",Toast.LENGTH_SHORT).show();
}
},MainActivity.this);
}
});
在请求成功返回Json数据解析时候,放到实体类里解析,Json数据解析成对象,不暴露在外面
DownloadBean downloadBean = DownloadBean.parse(response);
package com.wjy.myupdateapp.updater.bean;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.Serializable;
/**
* Created by wjy.
* Date: 2019/11/19
* Time: 14:24
* Describe: ${describe}
*/
public class DownloadBean implements Serializable {
public String title;
public String content;
public String url;
public String md5;
public String versionCode;
//Json数据解析成对象
public static DownloadBean parse(String response) {
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(response);
String title = jsonObject.optString("title");
String content = jsonObject.optString("content");
String url = jsonObject.optString("url");
String md5 = jsonObject.optString("md5");
String versionCode = jsonObject.optString("versionCode");
DownloadBean downloadBean = new DownloadBean();
downloadBean.title = title;
downloadBean.content = content;
downloadBean.url = url;
downloadBean.md5 = md5;
downloadBean.versionCode = versionCode;
return downloadBean;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
5.在onDestroy里将网络请求关闭
@Override
protected void onDestroy() {
super.onDestroy();
AppUpdater.getInstance().getNetManager().cancel(this);
}
6.附下载弹窗、AppUtils工具类和base64工具类
(1)下载弹窗
package com.wjy.myupdateapp.updater.ui;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.TextView;
import android.widget.Toast;
import com.wjy.myupdateapp.R;
import com.wjy.myupdateapp.updater.AppUpdater;
import com.wjy.myupdateapp.updater.bean.DownloadBean;
import com.wjy.myupdateapp.updater.net.INetDownloadCallBack;
import com.wjy.myupdateapp.updater.utils.AppUtils;
import java.io.File;
/**
* Created by wjy.
* Date: 2019/11/19
* Time: 15:21
* Describe: ${describe}
*/
public class UpdateVersionShowDialog extends DialogFragment {
private static final String KEY_DOWNLOAD_BEAN = "download_bean";
private DownloadBean downloadBean;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle arguments = getArguments();
if (arguments != null){
downloadBean = (DownloadBean) arguments.getSerializable(KEY_DOWNLOAD_BEAN);
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_updater,container,false);
bindEvents(view);
return view;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
private void bindEvents(View view) {
TextView tv_title = view.findViewById(R.id.tv_title);
TextView tv_content = view.findViewById(R.id.tv_content);
final TextView tv_update = view.findViewById(R.id.tv_update);
tv_title.setText(downloadBean.title);
tv_content.setText(downloadBean.content);
tv_update.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
v.setEnabled(false);//点完 将按钮设置为不可点,不然每次点击都会重复的下载
final File targetFile = new File(getActivity().getCacheDir(),"target.apk");
//4.下载
AppUpdater.getInstance().getNetManager().download(downloadBean.url, targetFile, new INetDownloadCallBack() {
@Override
public void success(File apkFile) {
v.setEnabled(true);
//安装的代码
Log.e("tag","success="+apkFile.getAbsolutePath());
dismiss();
String fileMd5 = AppUtils.getFileMd5(targetFile);
Log.e("tag","fileMd5="+fileMd5);
if (fileMd5 != null && fileMd5.equals(downloadBean.md5)){
AppUtils.installApk(getActivity(),apkFile);
}else {
Toast.makeText(getActivity(),"md5 检测失败!",Toast.LENGTH_SHORT).show();
}
AppUtils.installApk(getActivity(),apkFile);
}
@Override
public void progress(int progress) {
//更新界面的代码
Log.e("tag","progress="+progress);
tv_update.setText(progress+"%");
}
@Override
public void failed(Throwable throwable) {
v.setEnabled(true);
Toast.makeText(getActivity(),"文件下载失败!",Toast.LENGTH_SHORT).show();
}
},UpdateVersionShowDialog.this);
}
});
}
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
Log.e("tag","onDismiss");
AppUpdater.getInstance().getNetManager().cancel(this);
}
public static void show(FragmentActivity activity, DownloadBean bean){
Bundle bundle = new Bundle();
bundle.putSerializable(KEY_DOWNLOAD_BEAN,bean);
UpdateVersionShowDialog dialog = new UpdateVersionShowDialog();
dialog.setArguments(bundle);
dialog.show(activity.getSupportFragmentManager(),"updateVersionShowDialog");
}
}
(2)AppUtils工具类
package com.wjy.myupdateapp.updater.utils;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.support.v4.content.FileProvider;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
/**
* Created by wjy.
* Date: 2019/11/19
* Time: 15:13
* Describe: ${describe}
*/
public class AppUtils {
/**
* 获取版本号
* @param context
* @return
*/
public static long getVersionCode(Context context) {
PackageManager packageManager = context.getPackageManager();
try {
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
return packageInfo.getLongVersionCode();
}else {
return packageInfo.versionCode;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return -1;
}
/**
* 下载完安装apk文件 并做了适配
* 1.Android N 做FileProvider适配 在AndroidManifest里写 provider
* 2.Android O 做INSTALL PERMISSION的适配 在AndroidManifest里添加REQUEST_INSTALL_PACKAGES权限
* @param activity
* @param apkFile
*/
public static void installApk(Activity activity, File apkFile) {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
Uri uri = null;
//1.Android N 做FileProvider适配
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
uri = FileProvider.getUriForFile(activity,activity.getPackageName()+".fileprovider",apkFile);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}else {
uri = Uri.fromFile(apkFile);
}
intent.setDataAndType(uri,"application/vnd.android.package-archive");
activity.startActivity(intent);
//这是一个非常早期的installApk的写法,现在就会遇到很多问题
//1.Android N 就要做FileProvider适配
//2.Android O 就要做INSTALL PERMISSION的适配
}
/**
* 获取文件MD5的算法
* @param targetFile
* @return
*/
public static String getFileMd5(File targetFile) {
if (targetFile == null || !targetFile.isFile()){
return null;
}
MessageDigest digest = null;
FileInputStream in = null;
byte[] buffer = new byte[1024];
int len = 0;
try {
digest = MessageDigest.getInstance("MD5");
in = new FileInputStream(targetFile);
while ((len = in.read(buffer)) != -1){
digest.update(buffer,0,len);
}
}catch (Exception e){
e.printStackTrace();
return null;
}finally {
if (in != null){
try {
in.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
byte[] result = digest.digest();
BigInteger bigInteger = new BigInteger(1,result);
return bigInteger.toString(16);
}
}
(3)base64工具类
package com.wjy.myupdateapp.updater.tools;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Base64;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import static com.lidroid.xutils.bitmap.core.BitmapDecoder.calculateInSampleSize;
public class Base64StringTool {
/**
* 文件转Base64
* @param filepath
* @return
*/
public static String fileToBase64(String filepath){
// 获得输入流
FileInputStream inStream = null;
try {
inStream = new FileInputStream(filepath);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
// new一个缓冲区
byte[] buffer = new byte[1024];
int len = 0;
// 使用ByteArrayOutputStream类来处理输出流
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
try {
while ((len = inStream.read(buffer)) != -1) {
// 写入数据
outStream.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
// 得到文件的二进制数据
byte[] data = outStream.toByteArray();
// 关闭流
try {
outStream.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
inStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return Base64.encodeToString(data, Base64.DEFAULT);
}
//将图片压缩成100k以下上传 使用方法getcomImageBase64(getSmallBitmap(filePath))
public static String getcomImageBase64(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 100是压缩率不压缩,如果是30就是压缩70%,压缩后的存放在baos中
int options = 100;
while (baos.toByteArray().length / 1024 > 100) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
baos.reset();// 重置baos即清空baos
options -= 10;// 每次都减少10
bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中
}
byte[] bytes = baos.toByteArray();
try {
baos.flush();
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
return Base64.encodeToString(bytes, Base64.DEFAULT);
}
//将图片路径转化成bitmap
public static Bitmap getSmallBitmap(String filePath) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, 480, 800);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(filePath, options);
}
}
最后附上整理例子的下载地址:
git地址:https://gitee.com/AlaYu/MyUpdateApp
CSDN地址:https://download.csdn.net/download/u013184970/11997915