출처 https://onedaycodeing.tistory.com/168
build.gradle dependencies 추가할것
특히 이부분 주의
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.5.0'
implementation 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
package opg.pp.server1
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.converter.scalars.ScalarsConverterFactory
object RetrofitSetting {
val API_BASE_URL = "서버주소"
val httpClient = OkHttpClient.Builder()
val baseBuilder = Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
fun <S> createBaseService(serviceClass: Class<S>?): S {
val retrofit = baseBuilder.client(httpClient.build()).build()
return retrofit.create(serviceClass)
}
}
아래 캡처 참고
\
2.인터페이스 설정 (나는 이미지를 보내는 목적으로 이미지만 설정)
RetrofitPath.kt
package opg.pp.server1
import okhttp3.MultipartBody
import retrofit2.Call
import retrofit2.http.Multipart
import retrofit2.http.POST
import retrofit2.http.Part
interface RetrofitPath {
@Multipart
@POST("서버주소")
fun profileSend(
@Part imageFile : MultipartBody.Part
): Call<String>
}
\
package opg.pp.server1
import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.database.Cursor
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.constraintlayout.widget.Constraints.TAG
import okhttp3.MediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.io.File
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val btn = findViewById<Button>(R.id.load_image)
btn.setOnClickListener {getProFileImage()}
}
fun getProFileImage(){
Log.d(ContentValues.TAG,"사진변경 호출")
val chooserIntent = Intent(Intent.ACTION_CHOOSER)
val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
intent.type = "image/*"
chooserIntent.putExtra(Intent.EXTRA_INTENT, intent)
chooserIntent.putExtra(Intent.EXTRA_TITLE,"사용할 앱을 선택해주세요.")
launcher.launch(chooserIntent)
}
fun absolutelyPath(path: Uri?, context : Context): String {
var proj: Array<String> = arrayOf(MediaStore.Images.Media.DATA)
var c: Cursor? = context.contentResolver.query(path!!, proj, null, null, null)
var index = c?.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
c?.moveToFirst()
var result = c?.getString(index!!)
return result!!
}
/////////////////////////////////////////////////
var launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) {
val imagePath = result.data!!.data
val file = File(absolutelyPath(imagePath, this))
val requestFile = RequestBody.create(MediaType.parse("image/*"), file)
val body = MultipartBody.Part.createFormData("file", file.name, requestFile)
Log.d(TAG,file.name)
sendImage(body)
}
}
fun sendImage(image : MultipartBody.Part) {
val service = RetrofitSetting.createBaseService(RetrofitPath::class.java) //레트로핏 통신 설정
val call = service.profileSend(image)!! //통신 API 패스 설정
call.enqueue(object : Callback<String>{
override fun onResponse(call: Call<String>, response: Response<String>) {
if (response?.isSuccessful) {
Log.d("로그 ",""+response?.body().toString())
Toast.makeText(applicationContext,"통신성공",Toast.LENGTH_SHORT).show()
}
else {
Toast.makeText(applicationContext,"통신실패",Toast.LENGTH_SHORT).show()
}
}
override fun onFailure(call: Call<String>, t: Throwable) {
Log.d("로그 ",t.message.toString())
}
})
}
}
import io
from flask import Flask, jsonify, request
import torch
import torch.nn as nn
import torch.optim as optim
import os
import torchvision
from torchvision import datasets, models, transforms
from PIL import Image
import numpy as np
import time
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/', methods=['POST','GET'])
def predict():
if request.method == 'POST':
# 이미지 바이트 데이터 받아오기
file = request.files['file']
#image_bytes = file.read()
file.save('파일저장위치' + (file.filename))
return 'ok'
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8000, debug=True)
잘되지 않았던 통신부분
서버 통신에 대해 잘알지 못했던 분야라 오랜시간 실패를 거듭했다
안드로이드 스튜디오에서 서버로 보내는데 계속 통신오류가 났다
그러다 우연히 블로그를 통해 나와 비슷한 상황이신 분에게 아이디어를 얻어 고쳤더니 잘되었다
flask 서버 코드
@app.route('/', methods=['POST','GET'])
def predict():
if request.method == 'POST':
# 이미지 바이트 데이터 받아오기
file = request.files['file'] #이부분!!!
#image_bytes = file.read()
안드로이드 mainactivity.kt
var launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) {
val imagePath = result.data!!.data
val file = File(absolutelyPath(imagePath, this))
val requestFile = RequestBody.create(MediaType.parse("image/*"), file)
val body = MultipartBody.Part.createFormData("file", file.name, requestFile) #이부분!!!
Log.d(TAG,file.name)
sendImage(body)
}
}
flask서버 코드인 file 이름 부분과
mainactivity.kt의 MultipartBody.Part.createFormData("file")
의 이름이 일치하지 않아서 생긴 오류였다
이것때문에 3일을 찾아봤다.. 결국 원리를 이해하지 못한 나의 잘못으로 삽질을 한것이였다.. 막상 오류 찾았더니 굉장히 허탈 ㅜㅜ
다음번엔 틀리지 않기 위해 이글을 남긴다
이렇게 이미지가 잘 넘어오는것을 볼수있다 !!!