Приложение вылетает при загрузке изображения, снятого с камеры, с помощью модифицированной мультичасти в KitKat 4.4.4 API 19 - PullRequest
2 голосов
/ 30 апреля 2019

Согласно требованию, пользователь приложения щелкает изображение с камеры устройства, а затем загружает его на сервер.Все работает нормально, когда я тестирую свой APK на Lollipop и выше, но когда я тестирую его на Lollipop ниже (особенно на KitKat 4.4.4 API 19), приложение вылетает с исключением java.io.FileNotFoundException: /: open failed: EISDIR (Is a directory).

Перед передачейintent до Camera Я создаю File и передаю ему Uri. Также при создании File Я сохраняю путь к файлу в некоторой переменной.

Позже onActivityResult(),Я создаю новый файл с путем (сохраненный в переменной), а затем передаю его на сервер, используя модификацию multipart.

Так я передаю Intent Camera

Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
                        takePictureIntent.resolveActivity(packageManager)?.also {
                            val photoFile = try {
                                createImageFile()
                            } catch (e: Exception) {
                                null
                            }

                            Log.e("file tag", photoFile!!.absolutePath)

                            photoFile?.also {
                                val photoUri = FileProvider.getUriForFile(this@PrintActivity, "$packageName.fileprovider", it)
                                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri)
                                if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
                                    takePictureIntent.clipData = ClipData.newRawUri("", photoUri)
                                    takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                                }
                                startActivityForResult(takePictureIntent, REQUEST_CAMERA)
                            }
                        }
                    }

Метод createImageFile() выглядит следующим образом:

@Throws(IOException::class)
    private fun createImageFile(): File {
        val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(Date())
        val storageDir = getExternalFilesDir("Allocation")
        return File.createTempFile("JPEG_${timeStamp}_", ".jpg", storageDir).apply {
            printImageFilePath = absolutePath
        }
    }

Это file_paths, которое я предоставил

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="Android/data/$packageName/files/Allocation" />
</paths>

Так я объявил Provider в своем AndroidManifest подapplication tag

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="$packageName.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

Это метод OnActivityResult()

 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_CAMERA && resultCode == Activity.RESULT_OK) {
            try {
                val printedImageFile = File(printImageFilePath)
                doImageUpload(printedImageFile)
            } catch (e: Throwable) {
                e.stackTrace
            }
        }
}

Это мой doImageUpload() метод

private fun doImageUpload(printedImageFile: File?) {
        if (networkUtil.isConnected()) {
            try {
                launch(UI) {
                    val response = dataManager.uploadImage(printedImageFile)
                    Log.v("ImageUploadSuccess", response.body())

}catch(e:Exception){

}

    }

Это мой dataManager.uploadImage(printedImageFile) method

suspend fun uploadImage(printImageFile: File?): Response<String> {

        val printImageBody: RequestBody
        val printImagePart: MultipartBody.Part

            printImageBody = 
 RequestBody.create(MediaType.parse("multipart/formdata"),printImageFile)
            printImagePart = MultipartBody.Part.createFormData("my_file1", printImageFile.name, printImageBody)
            restService.uploadImage(printImagePart).await()
}

И, наконец, это мой метод многокомпонентного интерфейса модернизации,

@Multipart
    @POST
    fun uploadImage(@Part myFile2: MultipartBody.Part?): Deferred<Response<String>>

Это журнал сбоев, который я получаю

E/AndroidRuntime: FATAL EXCEPTION: main
Process: $packageName, PID: 24339
java.io.FileNotFoundException: /: open failed: EISDIR (Is a directory)
    at libcore.io.IoBridge.open(IoBridge.java:409)
    at java.io.FileInputStream.<init>(FileInputStream.java:78)
    at okio.Okio.source(Okio.java:168)
    at okhttp3.RequestBody$3.writeTo(RequestBody.java:119)
    at okhttp3.MultipartBody.writeOrCountBytes(MultipartBody.java:173)
    at okhttp3.MultipartBody.writeTo(MultipartBody.java:114)
    at com.readystatesoftware.chuck.ChuckInterceptor.intercept(ChuckInterceptor.java:154)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
    at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:254)
    at okhttp3.RealCall$AsyncCall.execute(RealCall.java:200)
    at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
    at java.lang.Thread.run(Thread.java:841)
 Caused by: libcore.io.ErrnoException: open failed: EISDIR (Is a directory)
    at libcore.io.IoBridge.open(IoBridge.java:398)
    at java.io.FileInputStream.<init>(FileInputStream.java:78) 
    at okio.Okio.source(Okio.java:168) 
    at okhttp3.RequestBody$3.writeTo(RequestBody.java:119) 
    at okhttp3.MultipartBody.writeOrCountBytes(MultipartBody.java:173) 
    at okhttp3.MultipartBody.writeTo(MultipartBody.java:114) 
    at com.readystatesoftware.chuck.ChuckInterceptor.intercept(ChuckInterceptor.java:154) 
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) 
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) 
    at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:254) 
    at okhttp3.RealCall$AsyncCall.execute(RealCall.java:200) 
    at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
    at java.lang.Thread.run(Thread.java:841)

1 Ответ

0 голосов
/ 07 мая 2019

После долгих проб и ошибок и с некоторой помощью моего старшего и этого я наконец решил соответствующую проблему.

Проблема заключалась в том, что как только я снимал фотографию с задней камеры, система Android убивала мой соответствующий класс Activity, чтобы сэкономить ресурсы. Когда камера была закрыта и вернулась к моему Activity, Activity создавался заново, из-за чего переменная экземпляра, которая использовалась для сохранения пути к файлу захваченного изображения, была нулевой. В результате приложение использовалось для сбоя.

Таким образом, чтобы сохранить переменную экземпляра, я использовал метод onSaveInstanceState(outState: Bundle?) следующим образом, в моем классе PrintActivity (Activity, из которого был запущен Camera Intent),

override fun onSaveInstanceState(outState: Bundle?) {
    super.onSaveInstanceState(outState)
    outState?.putString(Constants.PRINT_IMAGE_FILE_PATH,printImageFilePath) 
  // printImageFilePath is the path of the image file , 
 //  Constants.PRINT_IMAGE_FILE_PATH is my key for the bundle

}

А затем в моем PrintActivity внутри onCreate(savedInstanceState: Bundle?) я переназначаю переменную экземпляра следующим образом:

override fun onCreate(savedInstanceState: Bundle?) {
    if(savedInstanceState?.get(Constants.PRINT_IMAGE_FILE_PATH)!=null){
    printImageFilePath = 
    savedInstanceState.get(Constants.PRINT_IMAGE_FILE_PATH)
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...