【问题标题】:App crashes after storage permission is granted only on first-time launch仅在首次启动时授予存储权限后应用程序崩溃
【发布时间】:2018-08-27 05:47:38
【问题描述】:

当我的app 首次启动时,我转到一个要求storage permission 的选项卡,它崩溃了。之后,它工作得很好。基本上,在授予storage permission 后,它应该在external storage 上创建一个文件夹,其中包含我在项目中assets folder 中的文件。第一次崩溃并重新打开后,它不会崩溃并正确放置目录和文件。 如果该文件夹已经在external storage 上,它在第一次启动时不会崩溃。此外,我后来意识到我可以通过定位SDK version 21 来完全摆脱崩溃,但如果我这样做了,我将无法更新Play Store 上的应用程序,因为我已经提交了它,希望稍后修复这个崩溃。这是崩溃期间的 logcat:

    --------- beginning of crash
08-27 01:16:58.548 17674-17674/com.thirdeclarity.rcmloader E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.thirdeclarity.rcmloader, PID: 17674
java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=65661, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {com.thirdeclarity.rcmloader/com.pavelrekun.rekado.screens.main_activity.MainActivity}: java.io.FileNotFoundException: /storage/emulated/0/RCM Loader/hekate-4.0.bin (No such file or directory)
    at android.app.ActivityThread.deliverResults(ActivityThread.java:4269)
    at android.app.ActivityThread.handleSendResult(ActivityThread.java:4313)
    at android.app.ActivityThread.-wrap19(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1645)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6499)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:440)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
 Caused by: java.io.FileNotFoundException: /storage/emulated/0/RCM Loader/hekate-4.0.bin (No such file or directory)
    at java.io.FileOutputStream.open0(Native Method)
    at java.io.FileOutputStream.open(FileOutputStream.java:287)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:223)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:110)
    at com.pavelrekun.rekado.services.utils.MemoryUtils.copyAsset(MemoryUtils.kt:15)
    at com.pavelrekun.rekado.screens.payload_fragment.PayloadsView.initList(PayloadsView.kt:47)
    at com.pavelrekun.rekado.screens.payload_fragment.PayloadsView.onRequestPermissionsResult(PayloadsView.kt:81)
    at com.pavelrekun.rekado.screens.payload_fragment.PayloadsFragment.onRequestPermissionsResult(PayloadsFragment.kt:33)
    at android.support.v4.app.FragmentActivity.onRequestPermissionsResult(FragmentActivity.java:804)
    at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:7429)
    at android.app.Activity.dispatchActivityResult(Activity.java:7280)
    at android.app.ActivityThread.deliverResults(ActivityThread.java:4265)
    at android.app.ActivityThread.handleSendResult(ActivityThread.java:4313) 
    at android.app.ActivityThread.-wrap19(Unknown Source:0) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1645) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:164) 
    at android.app.ActivityThread.main(ActivityThread.java:6499) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:440) 
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) 
  08-27 01:16:58.689 17674-17689/com.thirdeclarity.rcmloader I/zygote: Background concurrent copying GC freed 22378(1560KB) AllocSpace objects, 2(104KB) LOS objects, 50% free, 2MB/4MB, paused 2.770ms total 145.331ms

我是 Android 开发新手,我正在使用的代码来自一个开源项目,但我相信这是崩溃选项卡的相关代码:

package com.pavelrekun.rekado.screens.payload_fragment

import android.Manifest
import android.content.pm.PackageManager
import android.support.v4.app.Fragment
import android.support.v7.widget.LinearLayoutManager
import android.widget.Toast
import com.pavelrekun.konae.Konae
import com.pavelrekun.konae.filters.ExtensionFileFilter
import com.pavelrekun.rang.utils.ColorsHelper
import com.pavelrekun.rekado.R
import com.pavelrekun.rekado.base.BaseActivity
import com.pavelrekun.rekado.data.Payload
import com.pavelrekun.rekado.screens.payload_fragment.adapters.PayloadsAdapter
import com.pavelrekun.rekado.services.eventbus.Events
import com.pavelrekun.rekado.services.logs.LogHelper
import com.pavelrekun.rekado.services.payloads.PayloadHelper
import com.pavelrekun.rekado.services.utils.MemoryUtils
import com.pavelrekun.rekado.services.utils.PermissionsUtils
import kotlinx.android.synthetic.main.fragment_payloads.*
import org.greenrobot.eventbus.EventBus
import java.io.File
import java.io.IOException


class PayloadsView(private val activity: BaseActivity, private val fragment: Fragment) : PayloadsContract.View {

    private lateinit var adapter: PayloadsAdapter

    override fun initViews() {
        activity.setTitle(R.string.navigation_payloads)

        prepareList()
        initClickListeners()
        initDesign()
    }

    override fun prepareList() {
        if (!PermissionsUtils.checkPermissionGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            PermissionsUtils.showPermissionDialog(activity, fragment, PermissionsUtils.PERMISSIONS_READ_REQUEST_CODE)
        } else {
            initList()
        }
    }

    override fun initList() {
        MemoryUtils.copyAsset()

        adapter = PayloadsAdapter(PayloadHelper.getAll())

        activity.payloadsList.setHasFixedSize(true)
        activity.payloadsList.layoutManager = LinearLayoutManager(activity)
        activity.payloadsList.adapter = adapter
    }

    override fun initDesign() {
        activity.payloadsAdd.setColorFilter(ColorsHelper.getContrastColor(activity, ColorsHelper.resolveAccentColor(activity)))
    }

    override fun updateList() {
        if (this::adapter.isInitialized) {
            adapter.updateList()
        }
    }

    override fun initClickListeners() {
        activity.payloadsAdd.setOnClickListener { addPayload() }
    }

    override fun addPayload() {
        if (!PermissionsUtils.checkPermissionGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            PermissionsUtils.showPermissionDialog(activity, fragment, PermissionsUtils.PERMISSIONS_WRITE_REQUEST_CODE)
        } else {
            getPayloadFromStorage()
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        when (requestCode) {
            PermissionsUtils.PERMISSIONS_READ_REQUEST_CODE -> if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                initList()
            }
            PermissionsUtils.PERMISSIONS_WRITE_REQUEST_CODE -> if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                getPayloadFromStorage()
            } else {
                Toast.makeText(activity, R.string.permission_storage_error, Toast.LENGTH_SHORT).show()
            }
        }
    }

    private fun getPayloadFromStorage() {
        Konae().with(activity)
                .withChosenListener(object : Konae.Result {
                    override fun onChoosePath(dirFile: File) {
                        onChosenFileListener(dirFile)
                    }
                })
                .withFileFilter(ExtensionFileFilter("bin"))
                .withTitle(activity.getString(R.string.dialog_file_chooser_payload_title))
                .build()
                .show()
    }

    private fun onChosenFileListener(pathFile: File) {
        val payload = Payload(PayloadHelper.getName(pathFile.absolutePath), PayloadHelper.getPath(PayloadHelper.getName(pathFile.absolutePath)))

        if (!payload.name.contains("bin")) {
            Toast.makeText(activity, activity.getString(R.string.helper_error_file_payload_wrong), Toast.LENGTH_SHORT).show()
        }

        try {
            MemoryUtils.toFile(pathFile, (PayloadHelper.FOLDER_PATH + "/" + payload.name))

            EventBus.getDefault().post(Events.UpdatePayloadsListEvent())
            LogHelper.log(LogHelper.INFO, "Added new payload: ${payload.name}")
        } catch (e: IOException) {
            e.printStackTrace()
            LogHelper.log(LogHelper.ERROR, "Failed to add payload: ${payload.name}")
        }
    }
}

以下是最可能相关的更多代码:

package com.pavelrekun.rekado.services.payloads

import android.os.Environment
import com.pavelrekun.rekado.data.Payload
import io.paperdb.Paper
import java.io.File


object PayloadHelper {

    val FOLDER_PATH = "${Environment.getExternalStorageDirectory()}/RCM Loader/"
    const val BASIC_PAYLOAD_NAME = "hekate-4.0.bin"

    private const val CHOSEN_PAYLOAD = "CHOSEN_PAYLOAD"

    fun init() {
        val folderFile = File(FOLDER_PATH)
        if (!folderFile.exists()) folderFile.mkdirs()
    }

    fun getAll(): MutableList<Payload> {
        val payloads: MutableList<Payload> = ArrayList()

        File(FOLDER_PATH).listFiles().forEach {
            if (it.path.contains("bin")) {
                payloads.add(Payload(getName(it.path), it.path))
            }
        }

        return payloads
    }

    fun clearFolder() {
        File(FOLDER_PATH).listFiles().forEach {
            if (it.name != BASIC_PAYLOAD_NAME) {
                it.delete()
            }
        }
    }

    fun getNames(): MutableList<String> {
        val payloads: MutableList<String> = ArrayList()

        for (payload in getAll()) {
            payloads.add(payload.name)
        }

        return payloads
    }

    fun getName(path: String): String {
        return File(path).name
    }

    fun getPath(name: String): String {
        return "$FOLDER_PATH/$name"
    }

    fun find(name: String): Payload? {
        for (payload in getAll()) {
            if (payload.name == name) {
                return payload
            }
        }

        return null
    }

    fun putChosen(payload: Payload) {
        Paper.book().write(CHOSEN_PAYLOAD, payload)
    }

    fun getChosen(): Payload {
        return Paper.book().read(CHOSEN_PAYLOAD)
    }
}

- 包 com.pavelrekun.rekado.services.utils

import android.Manifest
import android.app.Activity
import android.content.pm.PackageManager
import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat
import android.support.v7.app.AlertDialog

import com.pavelrekun.rekado.R

object PermissionsUtils {

    const val PERMISSIONS_READ_REQUEST_CODE = 125
    const val PERMISSIONS_WRITE_REQUEST_CODE = 126

    private fun requestPermissions(fragment: Fragment, permissions: Array<String>, code: Int) {
        fragment.requestPermissions(permissions, code)
    }

    fun checkPermissionGranted(activity: Activity, permission: String): Boolean {
        val result = ContextCompat.checkSelfPermission(activity, permission)
        return result == PackageManager.PERMISSION_GRANTED
    }

    fun showPermissionDialog(activity: Activity, fragment: Fragment, code: Int) {
        val builder = AlertDialog.Builder(activity)
        builder.setTitle(R.string.permission_storage_dialog_title)
        builder.setMessage(R.string.permission_storage_dialog_description)

        val storagePermissionDialog = builder.create()
        storagePermissionDialog.setButton(AlertDialog.BUTTON_POSITIVE, activity.getString(R.string.permission_storage_button)) { _, _ ->
            storagePermissionDialog.dismiss()
            requestPermissions(fragment, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), code)
        }

        storagePermissionDialog.show()
    }
}

MemoryUtils:

package com.pavelrekun.rekado.services.utils

import com.pavelrekun.rekado.RekadoApplication
import com.pavelrekun.rekado.services.eventbus.Events
import com.pavelrekun.rekado.services.payloads.PayloadHelper
import org.greenrobot.eventbus.EventBus
import java.io.*

object MemoryUtils {

    fun copyAsset() {
        val assetManager = RekadoApplication.instance.applicationContext.assets
        val sxPayloadFile = assetManager.open(PayloadHelper.BASIC_PAYLOAD_NAME)

        copyFile(sxPayloadFile, FileOutputStream("${PayloadHelper.FOLDER_PATH}/${PayloadHelper.BASIC_PAYLOAD_NAME}"))

        EventBus.getDefault().post(Events.UpdatePayloadsListEvent())
    }

    @Throws(IOException::class)
    private fun copyFile(inputStream: InputStream, outputStream: OutputStream) {
        inputStream.use { input ->
            outputStream.use { output ->
                input.copyTo(output)
            }
        }
    }

    fun removeFile(path: String) {
        File(path).delete()
    }

    fun toFile(file: File, path: String): File {
        return file.copyTo(File(path), true)
    }
}

Rekado应用程序

package com.pavelrekun.rekado

import android.annotation.SuppressLint
import android.app.Application
import android.support.v7.app.AppCompatDelegate
import com.pavelrekun.rang.Rang
import com.pavelrekun.rekado.services.logs.LogHelper
import com.pavelrekun.rekado.services.payloads.PayloadHelper
import io.paperdb.Paper

@SuppressLint("StaticFieldLeak")
class RekadoApplication : Application() {

    companion object {
        lateinit var instance: RekadoApplication
    }

    override fun onCreate() {
        super.onCreate()

        instance = this

        Paper.init(this)

        LogHelper.init()
        PayloadHelper.init()

        Rang.defaults().primaryColor().accentColor().nightMode().oledMode()
        Rang.init(this)
    }

}

如果有人检查代码并试图找出为什么在请求并授予存储权限并且“RCM Loader”文件夹在存储中找不到。该应用程序在崩溃后运行良好,并在文件夹内创建了包含捆绑 bin 文件的文件夹,但我首先试图找出导致崩溃的原因:https://github.com/ThirdEyeClarity/RCM-Loader?files=1

【问题讨论】:

  • 请分享您的 MemoryUtils 代码。
  • 刚刚添加到帖子底部

标签: android kotlin android-permissions


【解决方案1】:

通过使用这一行查看 logcat:

Caused by: java.io.FileNotFoundException: /storage/emulated/0/RCM Loader/hekate-4.0.bin (No such file or directory)

在您向我们展示的代码中,我想知道PayloadHelper.init() 方法:

fun init() {
    val folderFile = File(FOLDER_PATH)
    if (!folderFile.exists()) folderFile.mkdirs()
}

我在这些示例中的任何地方都看不到对它的任何调用。 您能告诉我们init() 方法在哪里使用吗?

【讨论】:

  • 它实际上并没有被我在项目中找到。我只是在帖子底部添加了我认为是相关代码的内容
猜你喜欢
  • 1970-01-01
  • 2015-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-08
  • 2020-02-04
相关资源
最近更新 更多