Upload picture with retrofit android kotlin - android

in my project i have to send a picture to a Rest Api, am using Retrofit 2.0.9 with kotlin coroutine
the problem when i send the request i get 201 as response code that mean is Successful but the server i
cant find the picture, i find only : file name , file id .
take picture code in my fragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
updatePagesAppBarrTitle()
if (ActivityCompat.checkSelfPermission(
requireActivity(),
android.Manifest.permission.CAMERA
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
requireActivity(),
arrayOf(android.Manifest.permission.CAMERA),
111
)
} else {
val i = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(i, 101)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
Log.d("sara1997", "$requestCode")
if (requestCode == 101) {
try {
val picture: Bitmap? = data?.getParcelableExtra("data")
if (picture != null) {
saveImageState(picture)
val file = convertBitmapToFile("imageName", picture)
val requestBody = file.asRequestBody("multipart/form-data".toMediaTypeOrNull())
val image =
MultipartBody.Part.createFormData("userImage", file.name, requestBody)
Picasso.get().load(file.toURL().toString()).into(Takeimageview)
_Takepicturebinding.ShowAlertDialogbtn.setOnClickListener {
takePictureViewModel.uploadPhoto(
image,
ImageUploadModel(
"page",
"ImageCreated",
"dfdd0daf-87ae-4cb3-9181-5cb1e240c3e7",
"478c60dc-329d-475b-81a3-fbe1a5a118b4",) )
} }
my repository Code
suspend fun uploadPhoto(
image: MultipartBody.Part,
imageUploadModel: ImageUploadModel
): Response<ImageUploadModel> {
val name: RequestBody =
imageUploadModel.name.toRequestBody("multipart/form-data".toMediaTypeOrNull())
val corpus: RequestBody = imageUploadModel.corpus.toString()
.toRequestBody("multipart/form-data".toMediaTypeOrNull())
val parent: RequestBody = imageUploadModel.parent.toString()
.toRequestBody("multipart/form-data".toMediaTypeOrNull())
val type: RequestBody =
imageUploadModel.type.toRequestBody("multipart/form-data".toMediaTypeOrNull())
return ApiService.APIBody.uploadPhoto(type, name, corpus, parent, image)
}
my request call code :
#Multipart
#POST("elements/create/")
suspend fun uploadPhoto(
#Part("type") type: RequestBody,
#Part("name") name: RequestBody,
#Part("corpus") corpus: RequestBody,
#Part("parent") parent: RequestBody,
#Part image: MultipartBody.Part
): Response<ImageUploadModel>

To post / put MultiPart.Parts we need to do this
Make sure the WebService / method is annotated correctly
#Multipart
#PUT("/api/profile-picture")
fun putProfilePicture(#Part imagePart: MultipartBody.Part): Single<Response<ResponseBody>>
Create the form data
val imagePart = MultipartBody.Part.createFormData(
name = "file",
filename = image.name,
body = image.asRequestBody("image/*".toMediaTypeOrNull())
)
Send the request
return webService.putProfilePicture(imagePart)

at First store your image
private fun saveToInternalStorage(bitmapImage: Bitmap, imageName: String): String? {
val cw = ContextWrapper(context)
// path to /data/data/yourapp/app_data/imageDir
val directory: File = cw.getDir("profile_image", Context.MODE_PRIVATE)
// Create imageDir
val mypath = File(directory, imageName)
var fos: FileOutputStream? = null
try {
fos = FileOutputStream(mypath)
// Use the compress method on the BitMap object to write image to the OutputStream
bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos)
} catch (e: java.lang.Exception) {
e.printStackTrace()
} finally {
try {
fos?.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
return directory.getAbsolutePath()}
then use OkHttpClient
saveToInternalStorage(imageView.drawable.toBitmap(), "profile.png")
val cw = ContextWrapper(context)
// path to /data/data/yourapp/app_data/imageDir
val path: File = cw.getDir("profile_image", Context.MODE_PRIVATE)
val file = File(path, "profile.png")
val requestBody =
MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("id", ID)
// Upload parameters
.addFormDataPart(
"user_image",
file?.name,
file.asRequestBody("multipart/form-data".toMediaTypeOrNull())
) // Upload files
.build()
var request = Request.Builder().url("https://www.yoururl.com").post(requestBody).build()
var client = OkHttpClient()
client
.newCall(request)
.enqueue(
object : Callback {
override fun onFailure(call: Call, e: IOException) {}
override fun onResponse(call: Call, response: Response) {}
}
)
https://gist.github.com/samiullahazizi/e2f6e01253ec0a9fe998d4d4b32d67e4

Related

Kotlin retrofit Multipart problem with send file on server(server work on laravel)

i have a problem with sending files over using retrofit to my API server. When i send data over using the #Body anotation but without a file the data gets added. When i use #multipart i keep getting response.code()==401, with me using postman sending data with files through my API it works perfectly fine. The issue lies within the kotlin app and retrofit.
i used every possible way. I used multipart without file, same problem. i tried sending just the file and it was the same thing. I don't have a clue where the problem is or what it could be. using body allows me to send data over while with #multipart it looks like as if they just didn't want to transfer over. any recommendations on what to do would be very much appreciated.
myCode:
interface FarmSpaceApi {
#POST("auth/register")
fun RegisterUserApi(#Body user: User):Call<User>
#POST("auth/login")
fun LoginUserApi(#Body user: Userlogin):Call<LoginData>
//#POST("fields/create")
#Headers("Content-Type: application/json;charset=UTF-8")
#POST("fields/show")
fun getFields(#Body userId: UserId,#Header("Authorization")token:String):Call<Field2>
#Multipart
#Headers("Content-Type: application/json;charset=UTF-8")
#POST("fields/create")
fun addfield(#Header("Authorization") token:String,
#Part image:MultipartBody.Part,
#Part("fieldstype") fieldstype: RequestBody,
#Part("field_size_in_ha") field_size_in_ha: RequestBody,
#Part("harvest_in_this_year") harvest_in_this_year: RequestBody,
#Part("user_id") user_id: RequestBody):Call<FieldNewResponse>
}
clicker.setOnClickListener {
val tokenManager=TokenManager(this)
val filepath=tokenManager.getfilename()
val file= File(filepath)
Log.d("File ", file.name.toString())
Log.d("fieldname ",fieldname.toString())
Log.d("fieldsize ",fieldsize.toString())
Log.d("fieldcurrent ",fieldcurrentyear.toString())
val request=RequestBody.create(MediaType.parse("image/*"),file)
val filepart=MultipartBody.Part.createFormData("file",file.name,request)
viewModel.sendfield(
tokenManager.getTokenfromManager()
,filepart
,fieldname.toString()
,fieldsize.toString().toDouble()
,fieldcurrentyear.toString().toDouble()
,tokenManager.getidentyficator()!!.toInt())
}
#Deprecated("Deprecated in Java")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && requestCode == 100) {
imageuri = data?.data!!
Log.d("Uri", imageuri.toString())
imagepreview.setImageURI(imageuri)
val name: String = getNameFile(this, imageuri)
Log.d("name: ", name)
val tokenManager=TokenManager(this)
tokenManager.addfilename(name)
}
}
fun getNameFile(context: Context, uri: Uri): String {
val projection: Array<String> = (arrayOf(MediaStore.Images.Media.DATA))
val cursor = context.contentResolver.query(uri, projection, null, null, null)
val index: Int = cursor!!.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
cursor.moveToFirst()
val name: String = cursor.getString(index)
return name
//.substring(name.lastIndexOf("/")+1)
}
fun sendfield(token:String,filepart:MultipartBody.Part,name:String,size:Double,year:Double,id:Int) {
viewModelScope.launch {
Log.d("token ", token)
val retro = InstanceApi.getInstanceApiRetrofit().create(FarmSpaceApi::class.java)
val newname= RequestBody.create(MediaType.parse("text/plain"),name)
val newsize= RequestBody.create(MediaType.parse("text/plain"),size.toString())
val newyear= RequestBody.create(MediaType.parse("text/plain"),year.toString())
val newid= RequestBody.create(MediaType.parse("text/plain"),id.toString())
retro.addfield("Bearer " + token,filepart,newname,newsize,newyear,newid).enqueue(object : Callback<FieldNewResponse> {
override fun onResponse(call: Call<FieldNewResponse>, response: Response<FieldNewResponse>) {
Log.d("Git ", response.message().toString())
Log.d("Test ", response.body().toString())
Log.d("Testcode ", response.code().toString())
Log.d("Testerror ", response.errorBody().toString())
}
override fun onFailure(call: Call<FieldNewResponse>, t: Throwable) {
Log.d("Nie Git ", t.message.toString())
}
})
}
}

Send image and form data at the same time using Retrofit in android kotlin

can you help me guys what's wrong with my code? So I need to send an image and form data into the database with retrofit. it drives me into OnResponse, but there is no change in my database. I tried using multipart and requestbody but it still doesn't work
btn_Verifikasi.setOnClickListener {
val file = File(tv.text.toString())
val requestFile = file.asRequestBody("multipart/form-data".toMediaType())
val body = MultipartBody.Part.createFormData("foto_reseller", file.name, requestFile);
val sharedPreferences = getSharedPreferences("sharedPrefs", android.content.Context.MODE_PRIVATE)
val savednohp = sharedPreferences.getString("nohp",null)
val savedpin = sharedPreferences.getString("pin",null)
val savednama = sharedPreferences.getString("namaReseller",null)
val alamatReseller = sharedPreferences.getString("alamatReseller",null)
val nohpreseller = savednohp!!.toRequestBody("text/plain".toMediaType())
val pinreseller = savedpin!!.toRequestBody("text/plain".toMediaType())
val emailreseller = "".toRequestBody("text/plain".toMediaType())
val namareseller = savednama!!.toRequestBody("text/plain".toMediaType())
val alamatreseller = alamatReseller!!.toRequestBody("text/plain".toMediaType())
val isverified = "".toRequestBody("text/plain".toMediaType())
val apiService = ApiService.getInstance().create(ApiEndpoint::class.java)
apiService.registerReseller(nohpreseller,namareseller,emailreseller,body,alamatreseller, pinreseller,isverified)
.enqueue(object : Callback<ResellerResponse>{
override fun onResponse(
call: Call<ResellerResponse>, response: Response<ResellerResponse>) {
Toast.makeText(this#RegisterFotoResellerActivity, "bisa", Toast.LENGTH_SHORT).show()
Log.d("TAG","bisa yuhhh")
}
override fun onFailure(call: Call<ResellerResponse>, t: Throwable) {
Log.d("TAG","durung bisa kyeeehhh")
}
})
}
#Multipart
#POST("../api/reseller/creates.php")
fun registerReseller(
#Part("no_hp") no_hpreseller:RequestBody,
#Part("nama") nama_reseller:RequestBody,
#Part("email") email_reseller:RequestBody,
#Part foto_reseller:MultipartBody.Part,
#Part("alamat") alamat_reseller:RequestBody,
#Part("password") pin_reseller:RequestBody,
#Part("is_verified") is_verified:RequestBody,
): Call<ResellerResponse>

Android upload files to s3 bucket - Bad Request

I am trying to upload files to s3 bucket but I am getting 400 Bad Request or file not found.
I have tried various solutions but still no luck.
Solution 1:
I followed this instructions
class InputStreamRequestBody(
private val contentResolver: ContentResolver,
private val uri: Uri
): RequestBody() {
override fun contentType(): MediaType? =
contentResolver.getType(uri)?.toMediaTypeOrNull()
override fun writeTo(sink: BufferedSink) {
contentResolver.openInputStream(uri)?.source()?.use(sink::writeAll)
}
override fun contentLength(): Long =
contentResolver.query(uri, null, null, null, null)?.use { cursor ->
val sizeColumnIndex: Int = cursor.getColumnIndex(OpenableColumns.SIZE)
cursor.moveToFirst()
cursor.getLong(sizeColumnIndex)
} ?: super.contentLength()
}
Used it like
#Multipart
#PUT
fun uploadFile(#Url url: String, #Part file: MultipartBody.Part): Single<Response<Any>>
val file = File(uri.path)
val requestBody = InputStreamRequestBody(contentResolver!!, uri)
val filePart = MultipartBody.Part.createFormData("file", file.name, requestBody)
packageApi.uploadFile(url, filePart)
This results in Bad Request
Solution 2:
Same as previous but this time without Multipart
#PUT
fun uploadFile(#Url url: String, #Body file: RequestBody): Single<Response<Any>>
val requestBody = InputStreamRequestBody(contentResolver!!, uri)
packageApi.uploadFile(url, requestBody)
This also results in Bad Request
Solution 3:
Now I abandoned InputStreamRequestBody class and used the traditional way mentioned here
#Multipart
#PUT
fun uploadFile(#Url url: String, #Part file: MultipartBody.Part): Single<Response<Any>>
val file = File(uri.path)
val requestFile = file.asRequestBody("multipart/form-data".toMediaTypeOrNull())
val body = MultipartBody.Part.createFormData("file", file.name, requestFile)
packageApi.uploadFile(url, body)
This results in java.io.FileNotFoundException: /document/image:95: open failed: ENOENT (No such file or directory)
Any suggestion/solution is appreciated!
i did this in my project like
val key: String = AWS_DIRECTORY + fileFullName
var transferUtility: TransferUtility? = null
private var s3Client: AmazonS3? = null
val region = Region.getRegion(Regions.AP_SOUTH_1)
s3Client = AmazonS3Client(awsCredentials, region)
transferUtility=TransferUtility.builder().s3Client(s3Client).context(activityContext)
.defaultBucket(AWS_BUCKET)
.build()
val uploadObserver = transferUtility?.upload(
AWS_BUCKET,
key,
file,
CannedAccessControlList.PublicRead
)
uploadObserver?.setTransferListener(object : TransferListener {
override fun onStateChanged(id: Int, state: TransferState) {
if (TransferState.COMPLETED == state) {
} else if (TransferState.FAILED == state) {
}
}
override fun onProgressChanged(id: Int, bytesCurrent: Long, bytesTotal: Long) {
}
override fun onError(id: Int, ex: Exception) {
}
})

How can I solve this error :Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $

How can I solve this problem?
class InformationActivity : AppCompatActivity() {
private val _tag = SplashActivity::class.java.simpleName
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_information)
val uniqueId = SharedPreference.getidInfo(this)
val token = SharedPreference.getUserInfo(this)
Client.retrofitService.profile(uniqueId, token)
.enqueue(object : Callback<LoginResponse> {
override fun onFailure(call: Call<LoginResponse>, t: Throwable) {
}
override fun onResponse(
call: Call<LoginResponse>,
response: Response<LoginResponse>
) {
if (response?.isSuccessful == false) { val er = Gson().fromJson(response.errorBody()?.charStream(), ErrorResponse::class.java)
Log.d(_tag, "${er.code}:${er.message}")
if (er.code == 60203) {
Toast.makeText(this#InformationActivity, "", Toast.LENGTH_SHORT).show()
}
} else if (response?.isSuccessful == true) {
Glide.with(applicationContext).asBitmap().load("https://s3.amazonaws.com/appsdeveloperblog/micky.gif").into(imageView)
Toast.makeText(this#InformationActivity, "", Toast.LENGTH_LONG).show()
val file=File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),"micky.gif")
var fileName="micky.gif"
val token = SharedPreference.getUserInfo(applicationContext)
val uniqueId= SharedPreference.getidInfo(applicationContext)
var requestBody: RequestBody = RequestBody.create(MediaType.parse("image/*"), file)
val body: MultipartBody.Part = MultipartBody.Part.createFormData("profile",fileName,requestBody)
if (uniqueId != null) {
Client.retrofitService.updateProfile(token,uniqueId,body)
.enqueue(object : Callback<List<LoginResponse>> {
override fun onFailure(
call: Call<List<LoginResponse>>,
t: Throwable) { Log.d("", t.message) }
override fun onResponse(
call: Call<List<LoginResponse>>,
response: Response<List<LoginResponse>>) { if (response?.isSuccessful)
{ Toast.makeText(this#InformationActivity, "File Uploaded Successfully...", Toast.LENGTH_LONG).show()
Log.d("", "" + response?.body().toString())
} else {
Toast.makeText(this#InformationActivity, "Some error occurred...", Toast.LENGTH_LONG).show()
}
} }) }
}
}
}) }
}
interface API {
#Headers("Content-Type: application/json", "Authorization:token:String")
#Multipart
#PUT("/user/profile/{userId}")
fun updateProfile(#Header("Authorization") token: String?, #Path("userId") userID: String, #Part file: MultipartBody.Part): Call<List<Loginresponse>>
}
object Client {
var retrofitService: API
init {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val logger: OkHttpClient = OkHttpClient.Builder().addInterceptor(interceptor).readTimeout(20, TimeUnit.SECONDS).writeTimeout(20, TimeUnit.SECONDS).build()
val retrofit = Retrofit.Builder()
.baseUrl("myurl")
.addConverterFactory(GsonConverterFactory.create())
.client(logger)
.build()
retrofitService = retrofit.create(API::class.java)
}
}
#SerializedName("uniqueId")
val user:String?=null
#SerializedName("nickname")
val nickname: String?=null
#SerializedName("birth")
val birth: String?=null
#SerializedName("profileImage")
val profileImage: String?=null
#SerializedName("profileThumbnail")
val profileThumbnails: String?=null
#SerializedName("gender")
val gender: Int?=null
#SerializedName("token")
val token: String? = null
}
Your json return as JSON object. But you are trying to convert into Json array
Call<List<Loginresponse>> - you try to convert result as JSON Array (list)
Solution
Get the raw json result & convert the pojo using http://www.jsonschema2pojo.org/ and try again
You are trying to store json object in list that's why you are getting error .
check your JSON response start with { curly bracket it means it is object not an array . array start with [ square bracket .
#PUT("/user/profile/{userId}")
fun updateProfile(#Header("Authorization") token: String?, #Path("userId") userID: String, #Part file: MultipartBody.Part): Call<List<Loginresponse>>
replace Call<List<Loginresponse>> with Call<Loginresponse> all over where you using updateProfile method

Uploading images to server using retrofit

I' trying to upload an image to server using retrofit2. I think that the way I send data is not correct but I haven't figure out yet where is my problem.
I should send the data in this format: {"file": image, "userID": userId}
This is my code in retrofit interace: #POST("avatar")
fun uploadImage(#Body data: Data ) : Call<ResponseBody>
I have created an object Data with file and userID I don't know if this is the right way. I have seen also this example
ublic interface UploadAPIs {
#Multipart
#POST("/upload")
Call<ResponseBody> uploadImage(#Part MultipartBody.Part file, #Part("name") RequestBody requestBody);
}
But I really don't understand well, how can I sen an object with part multipart
This is how I create image file that I get from gallery in my fragment
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK)
when(requestCode){
GALLERY -> {
val selectedImage= data!!.data
val file = File(selectedImage.path)
val data = Data(file, userID)
val call = api!!.uploadImage(data)
call.enqueue(object: Callback<ResponseBody>{
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
Toast.makeText(context, t.message, Toast.LENGTH_SHORT).show()
}
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
val response = response.body()!!.string()
println("Response " + response)
//response says user does not exist because the way I send data is not correct
}
})
}
CAMERA -> {
//code here
}
}
}
This is the class that I create for Data object
class Data (val file: File, userID: Int)
I would be grateful if anyone can help me :)
Updated code:
#Multipart
#POST("avatar")
fun uploadImage(
#Part("userID") user_ID: RequestBody,
#Part image: MultipartBody.Part) : Call<ResponseBody>
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK)
when(requestCode){
GALLERY -> {
val selectedImage= data!!.data
val bitmap = MediaStore.Images.Media.getBitmap(context!!.contentResolver, selectedImage)
avatar.setImageBitmap(bitmap)
val file = File(getRealPathFromURI(selectedImage))
val id = RequestBody.create(MediaType.parse("text/plain"), userID.toString())
//val reqBody = RequestBody.create(MediaType.parse(activity!!.contentResolver.getType(selectedImage)!!), file)
val reqBody = RequestBody.create(MediaType.parse("image/*"), file)
val body = MultipartBody.Part.createFormData("file", file.name, reqBody)
val call = api!!.uploadImage(id, body)
call.enqueue(object: Callback<ResponseBody>{
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
Toast.makeText(context, t.message, Toast.LENGTH_SHORT).show()
println("Failure")
}
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
if (response.isSuccessful){
println("Successful " + response.body()?.string())
}else{
response.errorBody()?.string()
println("Error " + response.headers().toString())
}
}
})
}
CAMERA -> {
//code
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK)
when(requestCode){
GALLERY -> {
val selectedImage= data!!.data
val bitmap = MediaStore.Images.Media.getBitmap(context!!.contentResolver, selectedImage)
avatar.setImageBitmap(bitmap)
val file = File(getRealPathFromURI(selectedImage))
val id = RequestBody.create(MediaType.parse("text/plain"), userID.toString())
val reqBody = RequestBody.create(MediaType.parse("image/jpeg"), file)
val body = MultipartBody.Part.createFormData("file", file.name, reqBody)
val api = RetrofitClient.getInstance().apiService
val call = api!!.uploadImage(id, body)
call.enqueue(object: Callback<ResponseBody>{
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
Toast.makeText(context, t.message, Toast.LENGTH_SHORT).show()
println("Failure")
}
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
if (response.isSuccessful){
println("Successful " + response.body()?.string())
}else{
response.errorBody()?.string()
println("Error " + response.headers().toString())
}
}
})
}
CAMERA -> {
//code here
}
}
}
And in API interface:
#Multipart
#POST("avatar")
fun uploadImage(
#Part("userID") user_ID: RequestBody,
/*#Part("file") name: RequestBody*/
#Part image: MultipartBody.Part) : Call<ResponseBody>

Categories

Resources