查看: 451|回复: 0

[Android教程] Android使用OkHttp上传图片的实例代码

发表于 2017-11-28 08:00:01

简介

上传图片是一个APP的常见功能,可以是通过OOS上传到阿里云,也可以直接上传到Server后台,OOS有提供相应的SDK,此处忽略。下面通过OkHttp来实现图片的上传

代码

直接上代码UploadFileHelper.kt

  1. object UploadFileHelper {
  2. //--------ContentType
  3. private val MEDIA_OBJECT_STREAM = MediaType.parse("multipart/form-data")
  4. //--------上传延时时间
  5. private val WRITE_TIME_OUT:Long = 50
  6. private val mOkHttpClient by lazy { OkHttpClient() }
  7. //------基本参数----------
  8. val version = AppConstant.API_VERSION
  9. val platform = AppConstant.API_PLATFORM
  10. val methodName = AppConstant.API_UPLOADFILE_METHOD
  11. val token = ignoreException("") { UserModel.token() }
  12. val userId = ignoreException(0) { UserModel.id() }
  13. //------------------------
  14. //不带参数同步上传文件
  15. fun syncUploadFile(actionUrl: String = "",file: File,maxW: Int = 256,maxH: Int = 256):String?{
  16. val uploadFile = optionFileSize(file,maxW,maxH,null)
  17. if(uploadFile!=null){
  18. val response = createNoParamsOkHttpCall(actionUrl,uploadFile).execute()
  19. if(uploadFile.exists())
  20. uploadFile.delete()
  21. return getResponseToPath(response.body()!!.string())
  22. }
  23. return null
  24. }
  25. //不带参数异步上传文件
  26. fun asyncUploadFile(actionUrl:String = "", file: File,maxW: Int = 256,maxH: Int = 256,
  27. uploadCallBackListener: UploadCallBackListener? = null){
  28. val uploadFile = optionFileSize(file,maxW,maxH,uploadCallBackListener)
  29. if(uploadFile!=null)
  30. createNoParamsOkHttpCall(actionUrl,uploadFile).enqueue(object: Callback{
  31. override fun onFailure(c: Call, e: IOException) {
  32. uploadCallBackListener?.onUploadFailure(e.toString())
  33. }
  34. override fun onResponse(c: Call, response: Response) {
  35. if(uploadFile.exists())
  36. uploadFile.delete()
  37. uploadCallBackListener?.onUploadSuccess(getResponseToPath(response.body()!!.string()))
  38. response.body()!!.close()
  39. }
  40. })
  41. }
  42. //带参数同步上传文件
  43. fun syncParamsUploadFile(actionUrl: String= "",file: File,params:HashMap<String,Any>,
  44. maxW: Int = 256,maxH: Int = 256):String?{
  45. val uploadFile = optionFileSize(file,maxW,maxH,null)
  46. if(uploadFile!=null){
  47. params.put("filename",uploadFile)
  48. val response = createParamsOkHttpCall(actionUrl,params,null,false).execute()
  49. if(uploadFile.exists())
  50. uploadFile.delete()
  51. return getResponseToPath(response.body()!!.string())
  52. }
  53. return null
  54. }
  55. //带参数异步上传文件
  56. fun asyncParamsUploadFile(actionUrl: String= "",file: File,params:HashMap<String,Any>,maxW: Int = 256,maxH: Int = 256,
  57. uploadCallBackListener: UploadCallBackListener? = null, isProgress:Boolean = true){
  58. val uploadFile = optionFileSize(file,maxW,maxH,uploadCallBackListener)
  59. if(uploadFile!=null){
  60. params.put("filename",uploadFile)
  61. createParamsOkHttpCall(actionUrl,params,uploadCallBackListener,isProgress).enqueue(object :Callback{
  62. override fun onFailure(c: Call, e: IOException) {
  63. uploadCallBackListener?.onUploadFailure(e.toString())
  64. }
  65. override fun onResponse(c: Call, response: Response) {
  66. if(uploadFile.exists())
  67. uploadFile.delete()
  68. uploadCallBackListener?.onUploadSuccess(getResponseToPath(response.body()!!.string()))
  69. response.body()!!.close()
  70. }
  71. })
  72. }
  73. }
  74. //------创建一个没有带参数的Call
  75. fun createNoParamsOkHttpCall(actionUrl: String,file: File):Call{
  76. val requestUrl = "${AppConstant.HOST}/$actionUrl"
  77. val requestBody = RequestBody.create(MEDIA_OBJECT_STREAM,file)
  78. val request = Request.Builder().url(requestUrl).post(requestBody).build()
  79. return mOkHttpClient.newBuilder().writeTimeout(WRITE_TIME_OUT,TimeUnit.SECONDS).build().newCall(request)
  80. }
  81. //------创建一个带参数的Call
  82. fun createParamsOkHttpCall(actionUrl: String,params:Map<String,Any>,
  83. uploadCallBackListener: UploadCallBackListener? = null,
  84. isProgress:Boolean = true):Call{
  85. //-----AppConstant.HOST 上传图片的Server的BASE_URL http://xxx.com
  86. val requestUrl = "${AppConstant.HOST}/$actionUrl"
  87. val builder = MultipartBody.Builder()
  88. builder.setType(MultipartBody.FORM)
  89. val newParams = mutableMapOf(
  90. "version" to version,
  91. "platform" to platform,
  92. "methodName" to methodName,
  93. "token" to token,
  94. "user_id" to userId)
  95. newParams.putAll(params)
  96. newParams.forEach( action = {
  97. if(it.value is File){
  98. builder.addFormDataPart(it.key, (it.value as File).name,
  99. if(isProgress) createProgressRequestBody(MEDIA_OBJECT_STREAM!!,(it.value as File),uploadCallBackListener)
  100. else RequestBody.create(null, (it.value as File)))
  101. }else{
  102. builder.addFormDataPart(it.key,it.value.toString())
  103. }
  104. })
  105. val body = builder.build()
  106. val request = Request.Builder().url(requestUrl).post(body).build()
  107. return mOkHttpClient.newBuilder().writeTimeout(WRITE_TIME_OUT,TimeUnit.SECONDS).build().newCall(request)
  108. }
  109. //创建带进度RequestBody
  110. fun createProgressRequestBody(contentType:MediaType,file:File,
  111. uploadCallBackListener: UploadCallBackListener? = null):RequestBody{
  112. return object:RequestBody(){
  113. override fun contentType(): MediaType = contentType
  114. override fun contentLength() = file.length()
  115. override fun writeTo(sink: BufferedSink) {
  116. ignoreException {
  117. val source = Okio.source(file)
  118. val buf = Buffer()
  119. val remaining = contentLength()
  120. var current: Long = 0
  121. var readCount: Long = source.read(buf, 2048)
  122. while (readCount != -1L) {
  123. sink.write(buf, readCount)
  124. current += readCount
  125. uploadCallBackListener?.onUploadProgress(current,remaining)
  126. readCount = source.read(buf, 2048)
  127. }
  128. }
  129. }
  130. }
  131. }
  132. //根据图片大小简单压缩
  133. fun optionFileSize(file: File,maxW:Int,maxH:Int,uploadCallBackListener: UploadCallBackListener?):File?{
  134. try {
  135. val uploadFile = File(AppBridge.AppContext().externalCacheDir, file.hashCode().toString())
  136. ImageUtils.resize(file, maxW, maxH, uploadFile)
  137. return uploadFile
  138. } catch (e: Exception) {
  139. uploadCallBackListener?.onUploadFailure("压缩图片失败")
  140. return null
  141. }
  142. }
  143. //解析Server返回的数据获取图片路径,
  144. /*
  145. {"code":200,"msg":"上传成功","data":{"path":""}}
  146. */
  147. fun getResponseToPath(response:String):String{
  148. val dataJsonObj = JSONObject(response).get("data") as JSONObject
  149. return dataJsonObj.get("path") as String
  150. }
  151. //回调方法
  152. interface UploadCallBackListener{
  153. fun onUploadFailure(error:String)
  154. fun onUploadProgress(currentSize:Long,totalSize:Long)
  155. fun onUploadSuccess(path:String)
  156. }
  157. }
复制代码
  1. inline fun <T> ignoreException(def: T, f: () -> T): T {
  2. try {
  3. return f()
  4. } catch(e: Exception) {
  5. Timber.e(e, "")
  6. return def
  7. }
  8. }
复制代码

最后根据是否要带参数、同步或异步调用其中对应的方法可以了

  1. syncUploadFile(xxx)
  2. asyncUploadFile(xxx)
  3. syncParamsUploadFile(xxx)
  4. asyncParamsUploadFile(xxx)
复制代码

总结

首先根据是否要带参数上传,如果不带参数上传,直接创建RequestBody;如果带参数上传,创建MultipartBody.Builder(),然后把所有参数addFormDataPart进去,其中addFormDataPart方法有个RequestBody参数通过是否要监听进度创建,如果需要进度,需重写RequestBody的writeTo()方法,如果不监听进度,直接创建RequestBody,最后builder.build()得到RequestBody

通过上步骤得到的RequestBody以及上传图片的Server路径,可以配置出一个Request对象。

把Request对象通过.newCall(request)配置在OkHttpClient得到Call对象

最后Call调用同步.execute()或者异步.enqueue(callBack),在回调里面处理返回的数据。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持程序员之家。



回复

使用道具 举报

关闭

站长推荐上一条 /1 下一条