OkHTTP使用前步骤:
第一步:导入依赖:
compile 'com.squareup.okio:okio:1.5.0'
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
compile 'com.google.code.gson:gson:2.8.2'
第二部:导入Util工具包:
GsonArrayCallback(封装主线程UI更新并且解析Array类型json串)
NetWorkUtils(判断网络)
OkHttp3Utils(封装网络请求类 doget、dopost)
第三部:清单文件配置网络权限:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
给大家展示一下4个工具类,这四个工具类的功能有很多,可以供有时间的人学习:
第一个工具类
GsonArrayCallback:
- package Utils;
- import android.os.Handler;
- import com.google.gson.Gson;
- import com.google.gson.JsonArray;
- import com.google.gson.JsonElement;
- import com.google.gson.JsonParser;
- import java.io.IOException;
- import java.lang.reflect.ParameterizedType;
- import java.lang.reflect.Type;
- import java.util.ArrayList;
- import java.util.List;
- import okhttp3.Call;
- import okhttp3.Callback;
- import okhttp3.Response;
- /**
- * 1. 类的用途 如果要将得到的json直接转化为集合 建议使用该类
- * 该类的onUi() onFailed()方法运行在主线程
- * 2. @author forever
- * 3. @date 2017/9/24 18:47
- */
- public abstract class GsonArrayCallback<T> implements Callback {
- private Handler handler = OkHttp3Utils.getInstance().getHandler();
- //主线程处理
- public abstract void onUi(List<T> list);
- //主线程处理
- public abstract void onFailed(Call call, IOException e);
- //请求失败
- @Override
- public void onFailure(final Call call, final IOException e) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- onFailed(call, e);
- }
- });
- }
- //请求json 并直接返回集合 主线程处理
- @Override
- public void onResponse(Call call, Response response) throws IOException {
- final List<T> mList = new ArrayList<T>();
- String json = response.body().string();
- JsonArray array = new JsonParser().parse(json).getAsJsonArray();
- Gson gson = new Gson();
- Class<T> cls = null;
- Class clz = this.getClass();
- ParameterizedType type = (ParameterizedType) clz.getGenericSuperclass();
- Type[] types = type.getActualTypeArguments();
- cls = (Class<T>) types[0];
- for(final JsonElement elem : array){
- //循环遍历把对象添加到集合
- mList.add((T) gson.fromJson(elem, cls));
- }
- handler.post(new Runnable() {
- @Override
- public void run() {
- onUi(mList);
- }
- });
- }
- }
第二个工具类
GsonObjectCallback:
- package Utils;
- import android.os.Handler;
- import com.google.gson.Gson;
- import java.io.IOException;
- import java.lang.reflect.ParameterizedType;
- import java.lang.reflect.Type;
- import okhttp3.Call;
- import okhttp3.Callback;
- import okhttp3.Response;
- /**
- * 1. 类的用途 如果要将得到的json直接转化为集合 建议使用该类
- * 该类的onUi() onFailed()方法运行在主线程
- * 2. @author forever
- * 3. @date 2017/9/24 18:47
- */
- public abstract class GsonObjectCallback<T> implements Callback {
- private Handler handler = OkHttp3Utils.getInstance().getHandler();
- //主线程处理
- public abstract void onUi(T t);
- //主线程处理
- public abstract void onFailed(Call call, IOException e);
- //请求失败
- @Override
- public void onFailure(final Call call, final IOException e) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- onFailed(call, e);
- }
- });
- }
- //请求json 并直接返回泛型的对象 主线程处理
- @Override
- public void onResponse(Call call, Response response) throws IOException {
- String json = response.body().string();
- Class<T> cls = null;
- Class clz = this.getClass();
- ParameterizedType type = (ParameterizedType) clz.getGenericSuperclass();
- Type[] types = type.getActualTypeArguments();
- cls = (Class<T>) types[0];
- Gson gson = new Gson();
- final T t = gson.fromJson(json, cls);
- handler.post(new Runnable() {
- @Override
- public void run() {
- onUi(t);
- }
- });
- }
- }
我们请求的网络数据一般以JSon数据格式为主,而不同的Json数据格式,调用不同的类就可以
第三个工具类:
NetWorkUtils,用来判断是否有网络
- package Utils;
- import android.content.Context;
- import android.net.ConnectivityManager;
- import android.net.NetworkInfo;
- /**
- * 1. 类的用途 联网判断
- * 2. @author forever
- * 3. @date 2017/9/8 12:30
- */
- public class NetWorkUtils {
- //判断网络是否连接
- public static boolean isNetWorkAvailable(Context context) {
- //网络连接管理器
- ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- //网络信息
- NetworkInfo info = connectivityManager.getActiveNetworkInfo();
- if (info != null) {
- return true;
- }
- return false;
- }
- }
- package Utils;
- import android.content.Context;
- import android.content.Intent;
- import android.net.Uri;
- import android.os.Environment;
- import android.os.Handler;
- import android.os.Looper;
- import android.util.Log;
- import android.widget.Toast;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.Map;
- import java.util.concurrent.TimeUnit;
- import app.MyApp;
- import okhttp3.Cache;
- import okhttp3.CacheControl;
- import okhttp3.Call;
- import okhttp3.Callback;
- import okhttp3.FormBody;
- import okhttp3.Interceptor;
- import okhttp3.MediaType;
- import okhttp3.MultipartBody;
- import okhttp3.OkHttpClient;
- import okhttp3.Request;
- import okhttp3.RequestBody;
- import okhttp3.Response;
- import okhttp3.logging.HttpLoggingInterceptor;
- /**
- * 1. 类的用途 封装OkHttp3的工具类 用单例设计模式
- * 2. @author forever
- * 3. @date 2017/9/6 09:19
- */
- public class OkHttp3Utils {
- /**
- * 懒汉 安全 加同步
- * 私有的静态成员变量 只声明不创建
- * 私有的构造方法
- * 提供返回实例的静态方法
- */
- private static OkHttp3Utils okHttp3Utils = null;
- private OkHttp3Utils() {
- }
- public static OkHttp3Utils getInstance() {
- if (okHttp3Utils == null) {
- //加同步安全
- synchronized (OkHttp3Utils.class) {
- if (okHttp3Utils == null) {
- okHttp3Utils = new OkHttp3Utils();
- }
- }
- }
- return okHttp3Utils;
- }
- private static OkHttpClient okHttpClient = null;
- public synchronized static OkHttpClient getOkHttpClient() {
- if (okHttpClient == null) {
- //判空 为空创建实例
- // okHttpClient = new OkHttpClient();
- /**
- * 和OkHttp2.x有区别的是不能通过OkHttpClient直接设置超时时间和缓存了,而是通过OkHttpClient.Builder来设置,
- * 通过builder配置好OkHttpClient后用builder.build()来返回OkHttpClient,
- * 所以我们通常不会调用new OkHttpClient()来得到OkHttpClient,而是通过builder.build():
- */
- // File sdcache = getExternalCacheDir();
- //缓存目录
- File sdcache = new File(Environment.getExternalStorageDirectory(), "cache");
- int cacheSize = 10 * 1024 * 1024;
- //OkHttp3拦截器
- HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
- @Override
- public void log(String message) {
- Log.i("xxx", message.toString());
- }
- });
- //Okhttp3的拦截器日志分类 4种
- httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
- okHttpClient = new OkHttpClient.Builder().connectTimeout(15, TimeUnit.SECONDS)
- //添加OkHttp3的拦截器
- .addInterceptor(httpLoggingInterceptor)
- .addNetworkInterceptor(new CacheInterceptor())
- .writeTimeout(20, TimeUnit.SECONDS).readTimeout(20, TimeUnit.SECONDS)
- .cache(new Cache(sdcache.getAbsoluteFile(), cacheSize))
- .build();
- }
- return okHttpClient;
- }
- private static Handler mHandler = null;
- public synchronized static Handler getHandler() {
- if (mHandler == null) {
- mHandler = new Handler();
- }
- return mHandler;
- }
- /**
- * get请求
- * 参数1 url
- * 参数2 回调Callback
- */
- public static void doGet(String url, Callback callback) {
- //创建OkHttpClient请求对象
- OkHttpClient okHttpClient = getOkHttpClient();
- //创建Request
- Request request = new Request.Builder().url(url).build();
- //得到Call对象
- Call call = okHttpClient.newCall(request);
- //执行异步请求
- call.enqueue(callback);
- }
- /**
- * post请求
- * 参数1 url
- * 参数2 回调Callback
- */
- public static void doPost(String url, Map<String, String> params, Callback callback) {
- //创建OkHttpClient请求对象
- OkHttpClient okHttpClient = getOkHttpClient();
- //3.x版本post请求换成FormBody 封装键值对参数
- FormBody.Builder builder = new FormBody.Builder();
- //遍历集合
- for (String key : params.keySet()) {
- builder.add(key, params.get(key));
- }
- //创建Request
- Request request = new Request.Builder().url(url).post(builder.build()).build();
- Call call = okHttpClient.newCall(request);
- call.enqueue(callback);
- }
- /**
- * post请求上传文件
- * 参数1 url
- * 参数2 回调Callback
- */
- public static void uploadPic(String url, File file, String fileName) {
- //创建OkHttpClient请求对象
- OkHttpClient okHttpClient = getOkHttpClient();
- //创建RequestBody 封装file参数
- RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
- //创建RequestBody 设置类型等
- RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart("file", fileName, fileBody).build();
- //创建Request
- Request request = new Request.Builder().url(url).post(requestBody).build();
- //得到Call
- Call call = okHttpClient.newCall(request);
- //执行请求
- call.enqueue(new Callback() {
- @Override
- public void onFailure(Call call, IOException e) {
- }
- @Override
- public void onResponse(Call call, Response response) throws IOException {
- //上传成功回调 目前不需要处理
- }
- });
- }
- /**
- * Post请求发送JSON数据
- * 参数一:请求Url
- * 参数二:请求的JSON
- * 参数三:请求回调
- */
- public static void doPostJson(String url, String jsonParams, Callback callback) {
- RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonParams);
- Request request = new Request.Builder().url(url).post(requestBody).build();
- Call call = getOkHttpClient().newCall(request);
- call.enqueue(callback);
- }
- /**
- * 下载文件 以流的形式把apk写入的指定文件 得到file后进行安装
- * 参数一:请求Url
- * 参数二:保存文件的路径名
- * 参数三:保存文件的文件名
- */
- public static void download(final Context context, final String url, final String saveDir) {
- Request request = new Request.Builder().url(url).build();
- Call call = getOkHttpClient().newCall(request);
- call.enqueue(new Callback() {
- @Override
- public void onFailure(Call call, IOException e) {
- Log.i("xxx", e.toString());
- }
- @Override
- public void onResponse(Call call, final Response response) throws IOException {
- InputStream is = null;
- byte[] buf = new byte[2048];
- int len = 0;
- FileOutputStream fos = null;
- try {
- is = response.body().byteStream();
- //apk保存路径
- final String fileDir = isExistDir(saveDir);
- //文件
- File file = new File(fileDir, getNameFromUrl(url));
- fos = new FileOutputStream(file);
- while ((len = is.read(buf)) != -1) {
- fos.write(buf, 0, len);
- }
- fos.flush();
- //apk下载完成后 调用系统的安装方法
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
- context.startActivity(intent);
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if (is != null) is.close();
- if (fos != null) fos.close();
- }
- }
- });
- }
- /**
- * @param saveDir
- * @return
- * @throws IOException 判断下载目录是否存在
- */
- public static String isExistDir(String saveDir) throws IOException {
- // 下载位置
- if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- File downloadFile = new File(Environment.getExternalStorageDirectory(), saveDir);
- if (!downloadFile.mkdirs()) {
- downloadFile.createNewFile();
- }
- String savePath = downloadFile.getAbsolutePath();
- Log.e("savePath", savePath);
- return savePath;
- }
- return null;
- }
- /**
- * @param url
- * @return 从下载连接中解析出文件名
- */
- private static String getNameFromUrl(String url) {
- return url.substring(url.lastIndexOf("/") + 1);
- }
- /**
- * 为okhttp添加缓存,这里是考虑到服务器不支持缓存时,从而让okhttp支持缓存
- */
- private static class CacheInterceptor implements Interceptor {
- @Override
- public Response intercept(Chain chain) throws IOException {
- // 有网络时 设置缓存超时时间1个小时
- int maxAge = 60 * 60;
- // 无网络时,设置超时为1天
- int maxStale = 60 * 60 * 24;
- Request request = chain.request();
- if (NetWorkUtils.isNetWorkAvailable(MyApp.getInstance())) {
- //有网络时只从网络获取
- request = request.newBuilder().cacheControl(CacheControl.FORCE_NETWORK).build();
- } else {
- //无网络时只从缓存中读取
- request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
- /* Looper.prepare();
- Toast.makeText(MyApp.getInstance(), "走拦截器缓存", Toast.LENGTH_SHORT).show();
- Looper.loop();*/
- }
- Response response = chain.proceed(request);
- if (NetWorkUtils.isNetWorkAvailable(MyApp.getInstance())) {
- response = response.newBuilder()
- .removeHeader("Pragma")
- .header("Cache-Control", "public, max-age=" + maxAge)
- .build();
- } else {
- response = response.newBuilder()
- .removeHeader("Pragma")
- .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
- .build();
- }
- return response;
- }
- }
- }
接下来定义一个自己的类Myapp:作用就好比使用ImageLoader是一样的,不要忘了在清单文件中配置!
接下来就是MainActivity了,来请求网络数据,其中get请求成功后的方法是直接调用工具类中的方法,并利用JsonFromat对JSon字符串进行封装一个
- package app;
- import android.app.Application;
- import com.nostra13.universalimageloader.core.ImageLoader;
- import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
- /**
- * 1. 类的用途
- * 2. @author forever
- * 3. @date 2017/9/8 12:33
- */
- public class MyApp extends Application {
- public static MyApp mInstance;
- @Override
- public void onCreate() {
- super.onCreate();
- ImageLoaderConfiguration configuration = ImageLoaderConfiguration.createDefault(getApplicationContext());
- ImageLoader.getInstance().init(configuration);
- mInstance = this;
- }
- public static MyApp getInstance() {
- return mInstance;
- }
- }
类(Users)这个类就不占代码了,直接快捷键就可以了,
要将请求的数据一listview的形式展示出来,就要写适配器了:ListViewAdapter:,这之前我是将要展示的数据单独的有封装了一个类(MyNews),
- package com.eightgroup.http3text1;
- import android.os.Bundle;
- import android.support.v7.app.AppCompatActivity;
- import android.widget.ListView;
- import android.widget.TextView;
- import android.widget.Toast;
- import java.io.IOException;
- import java.util.ArrayList;
- import Adapter.ListViewBaseAdapter;
- import Bean.MyNews;
- import Bean.Users;
- import Utils.GsonObjectCallback;
- import Utils.NetWorkUtils;
- import Utils.OkHttp3Utils;
- import butterknife.BindView;
- import butterknife.ButterKnife;
- import okhttp3.Call;
- public class MainActivity extends AppCompatActivity {
- String URLPATH = "http://api.tianapi.com/social/?key=71e58b5b2f930eaf1f937407acde08fe&num=20";
- ListViewBaseAdapter adapter;
- ArrayList<MyNews> list;
- @BindView(R.id.listview)
- ListView listview;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- ButterKnife.bind(this);
- // 直接类名.方法名,判断网络
- boolean netWorkAvailable = NetWorkUtils.isNetWorkAvailable(MainActivity.this);
- if (!netWorkAvailable) {
- Toast.makeText(MainActivity.this, "连网" + netWorkAvailable, Toast.LENGTH_SHORT).show();
- }
- // get请求
- OkHttp3Utils.getInstance().doGet(URLPATH, new GsonObjectCallback<Users>() {
- // 请求成功
- @Override
- public void onUi(Users users) {
- list = new ArrayList<MyNews>();
- for (int i = 0; i<users.getNewslist().size(); i++){
- list.add(new MyNews(users.getNewslist().get(i).getPicUrl(),users.getNewslist().get(i).getTitle()));
- }
- adapter = new ListViewBaseAdapter(MainActivity.this,list);
- listview.setAdapter(adapter);
- String text = users.getNewslist().toString();
- }
- // 请求失败
- @Override
- public void onFailed(Call call, IOException e) {
- Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT).show();
- }
- });
- }
- }
这个类的代码就不展示了,自己可以根据自己的需求从而添加不同的数据
最后把布局展示一下,很简单的,普通的布局
- package Adapter;
- import android.content.Context;
- import android.content.pm.LabeledIntent;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.ImageView;
- import android.widget.TextView;
- import com.eightgroup.http3text1.R;
- import com.nostra13.universalimageloader.core.ImageLoader;
- import java.util.ArrayList;
- import Bean.MyNews;
- import Bean.Users;
- /**
- * Created by 笔片 on 2017/10/12.
- */
- public class ListViewBaseAdapter extends BaseAdapter{
- Context context;
- ArrayList<MyNews> list;
- public ListViewBaseAdapter(Context context, ArrayList<MyNews> list) {
- this.context = context;
- this.list = list;
- }
- @Override
- public int getCount() {
- return list == null ? 0 : list.size();
- }
- @Override
- public Object getItem(int position) {
- return list.get(position);
- }
- @Override
- public long getItemId(int position) {
- return position;
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- ViewHolder holder;
- if (convertView == null){
- convertView = LayoutInflater.from(context).inflate(R.layout.lixtview_item,parent,false);
- holder = new ViewHolder();
- holder.title = (TextView) convertView.findViewById(R.id.tv);
- holder.img = (ImageView) convertView.findViewById(R.id.img);
- convertView.setTag(holder);
- }else {
- holder = (ViewHolder) convertView.getTag();
- }
- MyNews myNews = (MyNews) getItem(position);
- holder.title.setText(myNews.getTitle());
- String imgURL = myNews.getPicURL();
- ImageLoader instance = ImageLoader.getInstance();
- instance.displayImage(imgURL,holder.img);
- return convertView;
- }
- static class ViewHolder{
- TextView title;
- ImageView img;
- }
- }
activity_main.xml:
listview_item.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/activity_main"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- tools:context="com.eightgroup.http3text1.MainActivity">
- <ListView
- android:id="@+id/listview"
- android:layout_width="match_parent"
- android:layout_height="match_parent"></ListView>
- </RelativeLayout>
好了,以上就是全部的代码了,由于我选的网络借口不是很好,所以,展示出来的第一印象不是很好,但是总体的效果是实现了,
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical" android:layout_width="match_parent"
- android:layout_height="match_parent">
- <TextView
- android:id="@+id/tv"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <ImageView
- android:id="@+id/img"
- android:layout_width="100dp"
- android:layout_height="100dp" />
- </LinearLayout>