Search code examples
androidkotlinbase64retrofitretrofit2

how do i post Long encoded string of base64 image to server using retrofit?


I'm trying to post encoded string of image to retrofit post method...after debugging i got very long string on debug of image chosen from gallery.....after submitting i can see long string encoded of image in debugger....in postman when i check i shows profile_pic: " " that is null ...

If I used endpoint like this im not getting crash:

   @FormUrlEncoded
@POST("update")
fun useredit(
    @Header("access_token") token: String,
    @Field("first_name") first_name:String,

    @Field("last_name") last_name:String,
    @Field("email") email:String,

    @Field("dob") dob:String,
    @Field("phone_no") phone_no: String,
    @Field("profile_pic") profile_pic:String

):Call<LoginResponse>

response code:

profile = findViewById<View>(R.id.profilepic) as ImageView

    profile?.setOnClickListener(View.OnClickListener {

        val intent = Intent()
        intent.type = "image/*"
        intent.action = Intent.ACTION_GET_CONTENT
        startActivityForResult(intent, IMAGE)
    })
    editsubmit.setOnClickListener {

        val first_name = firstname.text.toString().trim()
        val last_name = lastname.text.toString().trim()

        val email = emailregister.text.toString().trim()
        val phone = phoneno.text.toString().trim()

        val profile =convertToString()!!
        val token: String =
            SharedPrefManager.getInstance(
                applicationContext
            ).user.access_token.toString()

        RetrofitClient.instance.useredit(token,first_name,last_name,email,edittext1.text.toString(),phone,profile)
            .enqueue(object : Callback<LoginResponse> {
                override fun onFailure(call: Call<LoginResponse>, t: Throwable) {
                    Log.d("res", "" + t)
                }
                override fun onResponse(
                    call: Call<LoginResponse>,
                    response: Response<LoginResponse>
                ) {
                    var res = response
                    Log.d("response check ", "" + response.body()?.status.toString())
                    if (res.body()?.status==200) {
                        Toast.makeText(
                            applicationContext,
                            res.body()?.message,
                            Toast.LENGTH_LONG
                        ).show()
                        Log.d("kjsfgxhufb",response.body()?.status.toString())
                    }
                    else
                    {
                        try {
                            val jObjError =
                                JSONObject(response.errorBody()!!.string())
                            Toast.makeText(
                                applicationContext,
                                jObjError.getString("message")+jObjError.getString("user_msg"),
                                Toast.LENGTH_LONG
                            ).show()
                        } catch (e: Exception) {
                            Toast.makeText(applicationContext, e.message, Toast.LENGTH_LONG).show()
                            Log.e("errorrr",e.message)
                        }
                    }

                }
            })
    }
}
private fun convertToString(): String? {
      val byteArrayOutputStream = ByteArrayOutputStream()
    bitmap?.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream)
    val imgByte: ByteArray = byteArrayOutputStream.toByteArray()

    return android.util.Base64.encodeToString(imgByte, android.util.Base64.NO_WRAP )
}

override fun onActivityResult(
    requestCode: Int,
    resultCode: Int,
    data: Intent?
) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == IMAGE && resultCode == Activity.RESULT_OK && data != null) {
        val path: Uri? = data.data
        try {
            bitmap = MediaStore.Images.Media.getBitmap(contentResolver, path)
            profile?.setImageBitmap(bitmap)
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
}

im seeing long string on debugger but not on postman

Later i tried this-->

my endpoint:

   @Multipart
@POST("update")
fun useredit(
    @Header("access_token") token: String,
    @Part("first_name") first_name:String,

    @Part("last_name") last_name:String,
    @Part("email") email:String,

    @Part("dob") dob:String,
    @Part("phone_no") phone_no: String,
    @Part ("profile_pic")profile_pic: MultipartBody.Part?

):Call<LoginResponse>

activity response code:-

profile?.setOnClickListener(View.OnClickListener {

        val intent = Intent()
        intent.type = "image/*"
        intent.action = Intent.ACTION_GET_CONTENT
        startActivityForResult(intent, IMAGE)
    })
    editsubmit.setOnClickListener {

        val first_name = firstname.text.toString().trim()
        val last_name = lastname.text.toString().trim()

        val email = emailregister.text.toString().trim()
        val phone = phoneno.text.toString().trim()

        val profile =convertToString()!!
        val token: String =
            SharedPrefManager.getInstance(
                applicationContext
            ).user.access_token.toString()
        val requestFile: RequestBody =
            RequestBody.create(MediaType.parse("image/jpeg"), profile)

        val body: MultipartBody.Part =
            MultipartBody.Part.createFormData("image", "image.jpg", requestFile)
        RetrofitClient.instance.useredit(token,first_name,last_name,email,edittext1.text.toString(),phone,body)
            .enqueue(object : Callback<LoginResponse> {
                override fun onFailure(call: Call<LoginResponse>, t: Throwable) {
                    Log.d("res", "" + t)
                }
                override fun onResponse(
                    call: Call<LoginResponse>,
                    response: Response<LoginResponse>
                ) {
                    var res = response
                    Log.d("response check ", "" + response.body()?.status.toString())
                    if (res.body()?.status==200) {
                        Toast.makeText(
                            applicationContext,
                            res.body()?.message,
                            Toast.LENGTH_LONG
                        ).show()
                        Log.d("kjsfgxhufb",response.body()?.status.toString())
                    }
                    else
                    {
                        try {
                            val jObjError =
                                JSONObject(response.errorBody()!!.string())
                            Toast.makeText(
                                applicationContext,
                                jObjError.getString("message")+jObjError.getString("user_msg"),
                                Toast.LENGTH_LONG
                            ).show()
                        } catch (e: Exception) {
                            Toast.makeText(applicationContext, e.message, Toast.LENGTH_LONG).show()
                            Log.e("errorrr",e.message)
                        }
                    }

                }
            })
    }
}
private fun convertToString(): String? {
      val byteArrayOutputStream = ByteArrayOutputStream()
    bitmap?.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream)
    val imgByte: ByteArray = byteArrayOutputStream.toByteArray()

    return android.util.Base64.encodeToString(imgByte, android.util.Base64.NO_WRAP )
}

override fun onActivityResult(
    requestCode: Int,
    resultCode: Int,
    data: Intent?
) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == IMAGE && resultCode == Activity.RESULT_OK && data != null) {
        val path: Uri? = data.data
        try {
            bitmap = MediaStore.Images.Media.getBitmap(contentResolver, path)
            profile?.setImageBitmap(bitmap)
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
}
}

well im getting crash from above code:

java.lang.IllegalArgumentException: @Part parameters using the MultipartBody.Part must not include a part name in the annotation. (parameter #7)


Solution

  • Can you try to change something like below since all you are sending string so multipart file won't be ideal. just send it using request body let's see how server responds.

    @Multipart
    @POST("update")
    fun useredit(
        @Header("access_token") token: String,
        @PartMap Map<String, RequestBody> partMap
    ):Call<LoginResponse>
    

    and wherever you are calling do like this.

    // create a map of data to pass along
    RequestBody first_name = RequestBody.create(MediaType.parse("text/plain"),"your name here"); 
    RequestBody last_name = RequestBody.create(MediaType.parse("text/plain"),"your last name here");
    RequestBody email = RequestBody.create(MediaType.parse("text/plain"),"your email here");
    RequestBody dob = RequestBody.create(MediaType.parse("text/plain"),"your dob here");
    RequestBody phone_no = RequestBody.create(MediaType.parse("text/plain"),"your phone no here");
    RequestBody profile_pic = RequestBody.create(MediaType.parse("text/plain"),"your picture base64 string here");
        
    Map<String, RequestBody> map = new HashMap<>();  
    map.put("first_name", first_name);  
    map.put("last_name", last_name);  
    map.put("email", email);
    map.put("dob", dob);
    map.put("phone_no", phone_no);
    map.put("profile_pic", profile_pic);
    

    and then pass it to the calling function

     RetrofitClient.instance.useredit(token, map)//some code follows
    

    Edit:

    also need to send the image base64 in correct format like

    data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ.........
    

    or convert it to base64 encoding by using following method.

    private fun convertToString(): String? {
    val byteArrayOutputStream = ByteArrayOutputStream()
    bitmap?.compress(Bitmap.CompressFormat. JPEG, 100, byteArrayOutputStream)
    val imgByte: ByteArray = byteArrayOutputStream.toByteArray()
    
    return android.util.Base64.encodeToString(imgByte, android.util.Base64.NO_WRAP )
    }
    

    change your map from java to kotlin implementation as shown below in the code

    val map: MutableMap<String, RequestBody> = HashMap() 
    map["first_name"] = first_name
    map["last_name"] = last_name
    map["email"] = email
    map["dob"] = dob
    map["phone_no"] = phone_no
    map["profile_pic"] = profile_pic