欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android Retrofit实现多图片/文件、图文上传功能

程序员文章站 2023-12-03 22:35:52
什么是 retrofit ? retrofit是square开发的一个android和java的rest客户端库。这个库非常简单并且具有很多特性,相比其他的网络库...

什么是 retrofit ?

retrofit是square开发的一个android和java的rest客户端库。这个库非常简单并且具有很多特性,相比其他的网络库,更容易让初学者快速掌握。它可以处理get、post、put、delete…等请求,还可以使用picasso加载图片。

一、再次膜拜下retrofit

retrofit无论从性能还是使用方便性上都很屌!!!,本文不去介绍其运作原理(虽然很想搞明白),后面会出专题文章解析retrofit的内部原理;本文只是从使用上解析retrofit实现多图片/文件、图文上传的功能。

二、概念介绍

1)注解@multipart

从字面上理解就是与多媒体文件相关的,没错,图片、文件等的上传都要用到该注解,其中每个部分需要使用@part来注解。。看其注释

/** 
 * denotes that the request body is multi-part. parts should be declared as parameters and 
 * annotated with {@link part @part}. 
 */ 

2)注解@partmap

当然可以理解为使用@partmap注释,传递多个part,以实现多文件上传。注释

/** 
 * denotes name and value parts of a multi-part request. 
 * <p> 
 * values of the map on which this annotation exists will be processed in one of two ways: 
 * <ul> 
 * <li>if the type is {@link okhttp3.requestbody requestbody} the value will be used 
 * directly with its content type.</li> 
 * <li>other object types will be converted to an appropriate representation by using 
 * {@linkplain converter a converter}.</li> 
 * </ul> 
 * <p> 
 * <pre><code> 
 * @multipart 
 * @post("/upload") 
 * call<responsebody> upload( 
 * @part("file") requestbody file, 
 * @partmap map<string, requestbody> params); 
 * </code></pre> 
 * <p> 
 * a {@code null} value for the map, as a key, or as a value is not allowed. 
 * 
 * @see multipart 
 * @see part 
 */ 

3)requestbody

从上面注释中就可以看到参数类型是requestbody,其就是请求体。文件上传就需要参数为requestbody。官方使用说明如下

multipart parts use one of retrofit's converters or they can implement requestbody to handle their own serialization. 

四、基本实现

了解了以上概念,下面就一一实现

1)接口定义

public interface ihttpservice { 
@multipart 
 @post("nocheck/file/agree.do") 
 call<basebean> uploadagree(@partmap map<string, requestbody>params); 
} 

basebean是根据服务端返回数据进行定义的,这个使用时可以根据自有server定义。

2)retrofit实现

/** 
 * created by dell on 2017/3/16. 
 * 上传文件用(包含图片) 
 */ 
public class retrofithttpupload { 
 /** 
 * 超时时间60s 
 */ 
 private static final long default_timeout = 60; 
 private volatile static retrofithttpupload minstance; 
 public retrofit mretrofit; 
 public ihttpservice mhttpservice; 
 private map<string, requestbody> params = new hashmap<string, requestbody>(); 
 private retrofithttpupload() { 
 mretrofit = new retrofit.builder() 
  .baseurl(urlconfig.root_url) 
  .client(genericclient()) 
  .addconverterfactory(gsonconverterfactory.create()) 
  .build(); 
 mhttpservice = mretrofit.create(ihttpservice.class); 
 } 
 public static retrofithttpupload getinstance() { 
 if (minstance == null) { 
  synchronized (retrofithttpupload.class) { 
  if (minstance == null) 
   minstance = new retrofithttpupload(); 
  } 
 } 
 return minstance; 
 } 
 /** 
 * 添加统一超时时间,http日志打印 
 * 
 * @return 
 */ 
 public static okhttpclient genericclient() { 
 httplogginginterceptor logging = new httplogginginterceptor(); 
 logging.setlevel(httplogginginterceptor.level.body); 
 okhttpclient httpclient = new okhttpclient.builder() 
  .addinterceptor(logging) 
  .connecttimeout(default_timeout, timeunit.seconds) 
  .writetimeout(default_timeout, timeunit.seconds) 
  .readtimeout(default_timeout, timeunit.seconds) 
  .build(); 
 return httpclient; 
 } 
 /** 
 * 将call加入队列并实现回调 
 * 
 * @param call  调入的call 
 * @param retrofitcallback 回调 
 * @param method  调用方法标志,回调用 
 * @param <t>  泛型参数 
 */ 
 public static <t> void addtoenqueue(call<t> call, final retrofitcallback retrofitcallback, final int method) { 
 final context context = myapplication.getcontext(); 
 call.enqueue(new callback<t>() { 
  @override 
  public void onresponse(call<t> call, response<t> response) { 
  logutil.d("retrofit back code ====" + response.code()); 
  if (null != response.body()) { 
   if (response.code() == 200) { 
   logutil.d("retrofit back body ====" + new gson().tojson(response.body())); 
   retrofitcallback.onresponse(response, method); 
   } else { 
   logutil.d("toenqueue, onresponse fail:" + response.code()); 
   toastutil.makeshorttext(context, "网络连接错误" + response.code()); 
   retrofitcallback.onfailure(response, method); 
   } 
  } else { 
   logutil.d("toenqueue, onresponse fail m:" + response.message()); 
   toastutil.makeshorttext(context, "网络连接错误" + response.message()); 
   retrofitcallback.onfailure(response, method); 
  } 
  } 
  @override 
  public void onfailure(call<t> call, throwable t) { 
  logutil.d("toenqueue, onresponse fail unknown:" + t.getmessage()); 
  t.printstacktrace(); 
  toastutil.makeshorttext(context, "网络连接错误" + t.getmessage()); 
  retrofitcallback.onfailure(null, method); 
  } 
 }); 
 } 
 /** 
 * 添加参数 
 * 根据传进来的object对象来判断是string还是file类型的参数 
 */ 
 public retrofithttpupload addparameter(string key, object o) { 
 if (o instanceof string) { 
  requestbody body = requestbody.create(mediatype.parse("text/plain;charset=utf-8"), (string) o); 
  params.put(key, body); 
 } else if (o instanceof file) { 
  requestbody body = requestbody.create(mediatype.parse("multipart/form-data;charset=utf-8"), (file) o); 
  params.put(key + "\"; filename=\"" + ((file) o).getname() + "", body); 
 } 
 return this; 
 } 
 /** 
 * 构建requestbody 
 */ 
 public map<string, requestbody> bulider() { 
 return params; 
 } 
} 

其中定义了retrofit实例、还用拦截器定义了统一的超时时间和日志打印;将call加入队列并实现回调。最重要的就是添加参数:

/** * 添加参数 
 * 根据传进来的object对象来判断是string还是file类型的参数 
 */ 
 public retrofithttpupload addparameter(string key, object o) { 
 if (o instanceof string) { 
  requestbody body = requestbody.create(mediatype.parse("text/plain;charset=utf-8"), (string) o); 
  params.put(key, body); 
 } else if (o instanceof file) { 
  requestbody body = requestbody.create(mediatype.parse("multipart/form-data;charset=utf-8"), (file) o); 
  params.put(key + "\"; filename=\"" + ((file) o).getname() + "", body); 
 } 
 return this; 
 } 

这里就是根据传入的参数,返回不同的requestbody。

3)使用

private void uploadagree() { 
 showwaitdialog(); 
 retrofithttpupload retrofithttpupload = retrofithttpupload.getinstance(); 
 if (!stringutil.isempty(pathimage[0])){ 
  retrofithttpupload = retrofithttpupload.addparameter("pic1",new file(pathimage[0])); 
 } 
 if (!stringutil.isempty(pathimage[1])){ 
  retrofithttpupload = retrofithttpupload.addparameter("pic2", new file(pathimage[1])); 
 } 
 if (!stringutil.isempty(pathimage[2])){ 
  retrofithttpupload = retrofithttpupload.addparameter("zip", new file(pathimage[2])); 
 } 
 map<string, requestbody> params = retrofithttpupload 
  .addparameter("status", "4") 
  .addparameter("pickupid", tv_orderquality_pid.gettext().tostring()) 
  .addparameter("cause", reason) 
  .addparameter("connectname", et_orderquality_lxrname.gettext().tostring()) 
  .addparameter("connectphone", et_orderquality_lxrphone.gettext().tostring()) 
  .addparameter("details", et_orderquality_xqms.gettext().tostring()) 
  .bulider(); 
 retrofithttpupload.addtoenqueue(retrofithttpupload.getinstance().mhttpservice.uploadagree(params), 
  this, httpstaticapi.http_uploadagree); 
 } 

需要注意的是要对图片及文件路径进行判空操作,负责会报异常w/system.err: java.io.filenotfoundexception: /: open failed: eisdir (is a directory)

以上所述是小编给大家介绍的android基于retrofit实现多图片/文件、图文上传功能,希望对大家有所帮助