Android Retrofit2和Kotlin结合上传文件

现在Retrofit2和RxJava2是很流行的框架,可能是我太闭塞的缘故,竟然没有用过这样的框架,请原谅我以前都是在用xUtils3
今天就来说一下Retrofit2和Kotlin结合上传文件
1、首先集成工具
(1)Kotlin就不用说了,Android Studio 3.0 以后自身就有
(2)Retrofit2集成 在项目文件build.gradle 里添加

dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.android.support:design:26.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
implementation 'com.squareup.okhttp3:okhttp:3.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.retrofit2:adapter-rxjava:2.3.0'
}

2、
(1)编写一个KtvApiService接口

 /**
 * 作者:Galen on 2017/12/16 13:56
 * 邮箱:1270430761@qq.com
 */
interface KtvApiService {
@Multipart
@POST(FACE_DETECT)
fun detectFace(
        @Part("api_key") api_key: RequestBody,
        @Part("api_secret") api_secret: RequestBody ,
        @Part("return_attributes") return_attributes: RequestBody ,
        @Part part: MultipartBody.Part ): Call<DetectFaceResult>
@FormUrlEncoded
@POST(FACE_SET_GETDETAIL)
fun getFaceSetDetail(@Field("api_key") api_key: String,
                     @Field("api_secret") api_secret: String,
                     @Field("outer_id") outer_id: String):Call<FaceSetDetailResult>
}

(2)、编写请求地址配置Constants(是一个静态的类)

/**
 * 作者:Galen on 2017/12/16 13:58
 * 邮箱:1270430761@qq.com
 */
object Constants {
val LOCAL_SAVE_FACE_IMAGE = Environment.getExternalStorageDirectory().absolutePath + "/face.jpg"
val FACE_BASE_URL = "https://api-cn.faceplusplus.com/facepp/v3/"
const val FACE_DETECT = "detect"
val FACE_FEATURE = "facequality,blur"
val FACE_COMPARE = FACE_BASE_URL + "compare"
val FACE_SEARCH = FACE_BASE_URL + "search"
val FACE_SET = FACE_BASE_URL + "faceset/"
val FACE_SET_CREATE = FACE_SET + "create"
val FACE_SET_ADDFACE = FACE_SET + "addface"
val FACE_SET_REMOVEFACE = FACE_SET + "removeface"
val FACE_SET_UPDATE = FACE_SET + "update"
const val FACE_SET_GETDETAIL ="faceset/getdetail"
val FACE_SET_DELETE = FACE_SET + "delete"
val FACE_SET_GETFACESETS = FACE_SET + "getfacesets"
}

(3)编写返回值 DetectFaceResult(我直接用的GsonFormat转的bean文件)

/**
 * 作者:Galen on 2017/12/13 19:31
 * 邮箱:1270430761@qq.com
 */

class DetectFaceResult {

/**
 * image_id : rMqAJcCPIa/et7wAJ4BLpw==
 * request_id : 1513164138,f175169b-58c5-43af-ba58-d9150cc72f5c
 * time_used : 404
 * faces : [{"attributes":{"facequality":{"threshold":70.1,"value":74.748},"blur":{"blurness":{"threshold":50,"value":21.626},"motionblur":{"threshold":50,"value":21.626},"gaussianblur":{"threshold":50,"value":21.626}}},"face_rectangle":{"width":338,"top":87,"left":182,"height":338},"face_token":"5e43726aa72d35e5e78040c6b819dfb1"}]
 */

var image_id: String? = null
var request_id: String? = null
var time_used: Int = 0
var faces: List<FacesBean>? = null

class FacesBean {
    /**
     * attributes : {"facequality":{"threshold":70.1,"value":74.748},"blur":{"blurness":{"threshold":50,"value":21.626},"motionblur":{"threshold":50,"value":21.626},"gaussianblur":{"threshold":50,"value":21.626}}}
     * face_rectangle : {"width":338,"top":87,"left":182,"height":338}
     * face_token : 5e43726aa72d35e5e78040c6b819dfb1
     */

    var attributes: AttributesBean? = null
    var face_rectangle: FaceRectangleBean? = null
    var face_token: String? = null

    class AttributesBean {
        /**
         * facequality : {"threshold":70.1,"value":74.748}
         * blur : {"blurness":{"threshold":50,"value":21.626},"motionblur":{"threshold":50,"value":21.626},"gaussianblur":{"threshold":50,"value":21.626}}
         */

        var facequality: FacequalityBean? = null
        var blur: BlurBean? = null

        class FacequalityBean {
            /**
             * threshold : 70.1
             * value : 74.748
             */

            var threshold: Double = 0.toDouble()
            var value: Double = 0.toDouble()
        }

        class BlurBean {
            /**
             * blurness : {"threshold":50,"value":21.626}
             * motionblur : {"threshold":50,"value":21.626}
             * gaussianblur : {"threshold":50,"value":21.626}
             */

            var blurness: BlurnessBean? = null
            var motionblur: MotionblurBean? = null
            var gaussianblur: GaussianblurBean? = null

            class BlurnessBean {
                /**
                 * threshold : 50.0
                 * value : 21.626
                 */

                var threshold: Double = 0.toDouble()
                var value: Double = 0.toDouble()
            }

            class MotionblurBean {
                /**
                 * threshold : 50.0
                 * value : 21.626
                 */

                var threshold: Double = 0.toDouble()
                var value: Double = 0.toDouble()
            }

            class GaussianblurBean {
                /**
                 * threshold : 50.0
                 * value : 21.626
                 */

                var threshold: Double = 0.toDouble()
                var value: Double = 0.toDouble()
            }
        }
    }

    class FaceRectangleBean {
        /**
         * width : 338
         * top : 87
         * left : 182
         * height : 338
         */

        var width: Int = 0
        var top: Int = 0
        var left: Int = 0
        var height: Int = 0
    }
}
}

(4)调用

   fun faceDetect() {
  //创建Okhttp
    val builder = OkHttpClient.Builder()
  //添加日志拦截器(自定义日志拦截器)也可以不添加
  //builder.addInterceptor(LoggingInterceptor())
    val client = builder.build() 
    val retrofit = Retrofit.Builder()
    .client(client)
    .baseUrl(FACE_BASE_URL)
    .addConverterFactory(GsonConverterFactory.create())
    .build()
           
    val service = retrofit.create(KtvApiService::class.java)
    val file = File(LOCAL_SAVE_FACE_IMAGE)
    val photoRequestBody = RequestBody.create(MediaType.parse("image/jpg"), file)
    val photoPart = MultipartBody.Part.createFormData("image_file", file.name, photoRequestBody)
    val api_key = RequestBody.create(MediaType.parse("text/plain"), API_KEY)
    val api_secret = RequestBody.create(MediaType.parse("text/plain"), API_SECRET)
    val return_attributes = RequestBody.create(MediaType.parse("text/plain"), FACE_FEATURE)
    if (file.exists()) {
        val repos = service.detectFace(api_key, api_secret, return_attributes, photoPart)
        repos.enqueue(object : Callback<DetectFaceResult> {
            override fun onResponse(call: Call<DetectFaceResult>?, response: Response<DetectFaceResult>?) {
                if (response != null) {
                    Log.e("ScanActivity 成功", response.body().toString())
                }

            }

            override fun onFailure(call: Call<DetectFaceResult>?, t: Throwable?) {
                Log.e("ScanActivity  失败", t.toString())

            }
        })

    }
}

重点内容
上传图片要携带参数时必须要以这样的格式

     @Multipart
@POST(FACE_DETECT)
fun detectFace(
        @Part("api_key") api_key: RequestBody,
        @Part("api_secret") api_secret: RequestBody ,
        @Part("return_attributes") return_attributes: RequestBody ,
        @Part part: MultipartBody.Part ): Call<DetectFaceResult>

而不是

@Multipart
@POST(FACE_DETECT)
fun detectFace(
        @Part("api_key") api_key: String,
        @Part("api_secret") api_secret: String,
        @Part("return_attributes") return_attributes: String,
        @Part part: MultipartBody.Part ): Call<DetectFaceResult>

这样上传是错误的
调用的时候
携带的参数应该这样写
上传照片的参数应该这样

    val photoRequestBody = RequestBody.create(MediaType.parse("image/jpg"), file)
    val photoPart = MultipartBody.Part.createFormData("image_file", file.name, photoRequestBody)

其他参数

val api_key = RequestBody.create(MediaType.parse("text/plain"), API_KEY)
val api_secret = RequestBody.create(MediaType.parse("text/plain"), API_SECRET)
val return_attributes = RequestBody.create(MediaType.parse("text/plain"), FACE_FEATURE)

到此完工
本人第一次在简书写文章,请多多关照,如需帮助,求留言,也请大家多多指教

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,424评论 25 707
  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    passiontim阅读 15,396评论 2 45
  • 杠铃操一直是健身房里人气居高不下的运动之一,特别是深受办公室一族的欢迎,因为这项运动能让久坐的你,适时的锻...
    健身塑形师李永波阅读 2,005评论 5 6
  • 撕掉了过去却残留追忆 没有一滴眼泪是为悔恨和痛苦而流 没有一片绿叶是为敷衍和脆弱而生 物竟天择适者生存 喜爱淡泊的...
    狼眼阅读 266评论 6 8
  • 每次和家里关于金钱上有交流的时候,都会万分意识到自己是座孤岛这件事。去年提出去日本需要跟他们借款时,被断然拒绝。这...
    耕吧阅读 197评论 0 1