目前最新版本的是okhttp:3.4.1,也称为Okhttp3。 OkHttp是一个精巧的网络请求库,不仅在接口封装做的简单易用,在底层实现上也自成一派。比起原生的HttpURLConnection有过之而无不及,现在已经成为广大开发者的首选网络通讯库。
Android Studio添加上述依赖后会自动下载两个库,一个是Okhttp,另一个是Okio。
之前写了一篇博客简单讲解了MVP模式的使用,MVP模式&简单实例,实现的效果不明显,MVP模式的好处也没有体现。 今天结合Okhttp3框架,实现多种网络请求,并从侧面表现MVP模式数据传递的巧妙之处。
主要包含以下几个内容:
Okhttp的具体用法将Okhttp方法封装在MVP模式的Model层 get异步请求:京东获取单个商品价格接口post异步带参数请求:阿里云根据地区名获取经纬度接口文件下载:下载一张图片保存并显示事实上Android开发过程中在主线程进行网络同步请求是一件极其危险的事情,如果耗时太多会造成主线程阻塞,进而进程崩溃,所以本文的所有方法都采用异步请求。
其实也可以开辟一条新线程去使用execute()方法完成整个同步请求操作,避免线程阻塞。 /** * 创建新线程实现同步get请求 * @param context * @param url * @return * @throws Exception */ public String getSysn(final Context context, final String url) throws Exception { FutureTask<String> task = new FutureTask<String>(new Callable<String>() { @Override public String call() throws Exception { Request request = new Request.Builder().url(url).build(); Response response = client.newCall(request).execute(); String result = response.body().string(); return result; } }); new Thread(task).start(); return task.get(); } Response对象就是服务器返回的数据: response.body().string();//String类型数据 response.body().byteStream();//文件输入流数据 response.body().bytes();//二进制字节数组具体获取的数据,要看服务器返回的数据类型。
如果你仔细看完Okhttp的具体用法,那么看懂Model类就不是难事。
/** * 方法模型层 * Created by D&LL on 2017/3/13. */ public class Model { private static Model instance = new Model();//单例 public static Model getInstance() { return instance; } private ProgressDialog dialog;//显示下载的进度条 public OkHttpClient client = OkHttp3.getClient(); /** * 异步get请求 * 使用ICallBack接口传递返回数据 * @param context * @param url * @return * @throws Exception */ public void getSynchronized(final Context context, final String url, final ICallBack callback) { Request request = new Request.Builder().url(url).build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { callback.result(e.toString()); } @Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful()) { callback.result(response.body().string()); } else { callback.result("请求失败!"); } } }); } /** * post方式提交Map * 使用ICallBack接口传递返回数据 * @param url * @param map * @return * @throws Exception */ public void postMap(final Context context, final String url, Map<String, String> map, final ICallBack callback) { FormBody.Builder builder = new FormBody.Builder(); if (map != null) { //增强for循环遍历 for (Map.Entry<String, String> entry : map.entrySet()) { builder.add(entry.getKey(), entry.getValue()); } } FormBody formBody = builder.build(); Request request = new Request.Builder().post(formBody).url(url).build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { callback.result(e.toString()); } @Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful()) { callback.result(response.body().string()); } else { callback.result("请求失败!"); } } }); } /** * 异步下载文件 * BitmapCallBack接口进行数据传递 * @param context * @param url * @param name */ public void downAsynFile(final Context context, String url, final String name, final BitmapCallBack callback) { dialog = DialogUtil.getProgressDialog(context); dialog.show(); final Request request = new Request.Builder().url(url).build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { System.out.println(e); } @Override public void onResponse(Call call, Response response) { if (response.isSuccessful()) { InputStream inputStream = response.body().byteStream();//获取文件输入流 Bitmap bitmap = FileUtil.saveFile(name, inputStream);//获取的流进行文件操作 callback.imgBitmap(bitmap); System.out.println("下载成功!"); } else { System.out.println("下载失败!"); } response.close();//下载文件耗时较久,完成后需要手动关闭请求 dialog.dismiss(); } }); } }布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/get" android:layout_width="wrap_content" android:layout_height="100dp" android:textSize="20sp" /> <TextView android:id="@+id/post" android:layout_width="wrap_content" android:layout_height="100dp" android:textSize="20sp" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="down_img" /> <ImageView android:id="@+id/img" android:layout_width="100dp" android:layout_height="100dp" android:scaleType="fitXY" /> </LinearLayout>Activity:
public class MainActivity extends AppCompatActivity implements MainView { String geturl = "http://p.3.cn/prices/mgets?skuIds=J_954086&type=1";//京东获取单个商品价格接口: String posturl = "http://gc.ditu.aliyun.com/geocoding";//阿里云根据地区名获取经纬度接口 @BindView(R.id.button) Button button; @BindView(R.id.get) TextView get; @BindView(R.id.post) TextView post; @BindView(R.id.img) ImageView img; private MainPresenter presenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this);//butterknife initData(); } private void initData() { Map<String, String> map = new HashMap<>(); map.put("a", "苏州市"); presenter = new MainPresenter(this, this); presenter.getRequest(geturl); presenter.postMap(posturl, map); } @OnClick(R.id.button) public void onClick() { presenter.downFile("http://images.csdn.net/20150817/1.jpg", "demo.jpg");//下载并显示图片 } @Override public void getView(final String s) {//显示get请求返回值 runOnUiThread(new Runnable() { @Override public void run() { get.setText(s); } }); } @Override public void postView(final String s) {//显示post请求返回值 runOnUiThread(new Runnable() { @Override public void run() { post.setText(s); } }); } @Override public void imgView(final Bitmap bitmap) {//显示下载的图片 runOnUiThread(new Runnable() { @Override public void run() { img.setImageBitmap(bitmap); } }); } } 调用MainView接口,重写方法,显示传递的数据。重写方法的参数,就是我们请求的结果。无论多少次接口传递,即使传递到了activity中,这些数据仍在异步线程中,我们仍无法在主线程中使用。Android提供了runOnUiThread()方法,为我们解决在异步线程中更新UI的方法: runOnUiThread(new Runnable(){ @Override public void run() { }}); 也可以使用Handler机制,发送一个消息给主线程的Handler(取决于Looper,使用 Looper.getMainLooper() 创建的Handler就是主线程Handler): private Handler mHandler; private TextView mTxt; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); mTxt = (TextView) findViewById(R.id.txt); mHandler = new Handler(Looper.getMainLooper()){ @Override public void handleMessage(Message msg) { mTxt.setText((String) msg.obj); } }; OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url("https://github.com").build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { Message msg = new Message(); msg.what=0; msg.obj = response.body().string(); mHandler.sendMessage(msg); } }); } 至此整个demo完成,MVP模式巧妙的利用接口的特性进行数据传递,解决了数据传递的困难,降低了耦合。下载: https://download.csdn.net/download/demonliuhui/10755566 GitHub下载:https://github.com/MyAndroidDemo/OkhttpMVP
API免费测试接口:http://www.bejson.com/knownjson/webInterface/
http://www.tuicool.com/articles/6FjAJnV http://www.qingpingshan.com/rjbc/az/110232.html http://blog.csdn.net/lmj623565791/article/details/47911083