Android应用在尝试打开JPG文件时崩溃(Android 4.1,API 16,FileNotFoundException)

移动开发 2026-07-09

编辑: 应用崩溃是因为缺少 "All files access" 权限。正如CommonsWare在下面的评论中指出的,可以通过设置页面名为“All files access”的方式授予该权限。

注:本应用仅供个人使用。参见CommonsWare关于在何种有限情形下可能适用“All files access”权限的回答。

由于无需修改程序代码,以下内容可以忽略。


我有一个应用(仅供个人使用),在安装后会立即崩溃。该应用多年来在一系列旧设备上运行良好,但在我在一部搭载Android 16的手机上安装时却崩溃。

乍一看,问题似乎在于我的应用尚未获得访问外部存储所需的权限。然而,下面的Stack Overflow线索建议我开一个新的Stack Overflow问题,展示我当前的manifest、与崩溃相关的完整堆栈跟踪,以及触发该崩溃的代码。
Requesting storage permission (in my own app for my own personal use)

我希望得到关于我可能哪里出了问题的任何建议

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="1"
      android:versionName="1.0">
    <uses-permission
        android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission
        android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission
        android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
    <uses-permission
        android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:label="@string/app_name"
        android:allowBackup="false"
        android:requestLegacyExternalStorage="true">

        <activity android:name=".MyMap"
                  android:label="@string/app_name"
                  android:configChanges ="orientation"
            android:exported="true">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="com.prepbgg.mymap.action.latlong"/>
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="latlong"/>
            </intent-filter>
        </activity>

        <activity android:name=".PickFromList">
        </activity>
        <activity android:name=".TextList">
        </activity>
        <activity android:name=".DisplayText"
            android:configChanges="orientation">
        </activity>
        <activity android:name=".DisplayJpg"
            android:configChanges="orientation">
        </activity>

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.prepbgg.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>


    </application>
</manifest>

从应用的主活动调用onCreate() 的Logcat如下:

2026-06-01 11:04:33.113 32186-32186 Hi                      com.prepbgg.mymap                    I  Starting onCreate
2026-06-01 11:04:33.127 32186-32186 CompatChangeReporter    com.prepbgg.mymap                    D  Compat change id reported: 279646685; UID 10350; state: ENABLED
2026-06-01 11:04:33.144 32186-32186 MapView                 com.prepbgg.mymap                    I  com.prepbgg.mymap.MyMap@849c3f5
2026-06-01 11:04:33.155 32186-32186 Model                   com.prepbgg.mymap                    I  SM-A176B
2026-06-01 11:04:33.156 32186-32186 Info                    com.prepbgg.mymap                    I  recycling bitmap
2026-06-01 11:04:33.168 32186-32186 m.prepbgg.mymap         com.prepbgg.mymap                    I  Explicit concurrent mark compact GC freed 1461KB AllocSpace bytes, 0(0B) LOS objects, 73% free, 2194KB/8338KB, paused 410us,1.121ms total 12.052ms
2026-06-01 11:04:33.197 32186-32186 Pixels per cell         com.prepbgg.mymap                    I  600
2026-06-01 11:04:33.197 32186-32186 Model                   com.prepbgg.mymap                    I  not known
2026-06-01 11:04:33.197 32186-32186 Pixels per cell         com.prepbgg.mymap                    I  600
2026-06-01 11:04:33.279 32186-32186 BitmapFactory           com.prepbgg.mymap                    E  Unable to decode file: java.io.FileNotFoundException: /storage/emulated/0/maps/LR/0450E0090N/LR05100150.jpg: open failed: EACCES (Permission denied)
2026-06-01 11:04:33.283 32186-32186 TransactionExecutor     com.prepbgg.mymap                    E  Failed to execute the transaction: tId:1599214240 ClientTransaction{
                                                                                                    tId:1599214240   transactionItems=[
                                                                                                    tId:1599214240     LaunchActivityItem{activityToken=android.os.BinderProxy@914ef85,intent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 xflg=0x4 cmp=com.prepbgg.mymap/.MyMap },ident=134182143,info=ActivityInfo{7de2bcf com.prepbgg.mymap.MyMap},curConfig={1.15 234mcc20mnc [en_GB] ldltr sw384dp w384dp h832dp 450dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 0 - 1080, 2340) mMaxBounds=Rect(0, 0 - 1080, 2340) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0 mStageConfig=undefined mPopOver=off mOverlappingWithCutout=false} s.2023 fontWeightAdjustment=0 ff=0 bf=-1 bts=0 cst=1.0 nightDim=0 themeSeq=0},overrideConfig={1.15 234mcc20mnc [en_GB] ldltr sw384dp w384dp h832dp 450dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 0 - 1080, 2340) mMaxBounds=Rect(0, 0 - 1080, 2340) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mActivityType=standard mAlwaysOnTop=undefined mRotation=ROTATION_0 mStageConfig=undefined mPopOver=off mOverlappingWithCutout=false} s.2 fontWeightAdjustment=0 ff=0 bf=-1 bts=0 cst=1.0 nightDim=0 themeSeq=0},deviceId=0,referrer=com.android.shell,procState=2,state=null,persistentState=null,pendingResults=null,pendingNewIntents=null,sceneTransitionInfo=null,profilerInfo=null,assistToken=android.os.BinderProxy@5935a30,shareableActivityToken=android.os.BinderProxy@65836a9,activityWindowInfo=ActivityWindowInfo{isEmbedded=false, taskBounds=Rect(0, 0 - 1080, 2340), taskFragmentBounds=Rect(0, 0 - 1080, 2340)}}
                                                                                                    tId:1599214240     ResumeActivityItem{mActivityToken=android.os.BinderProxy@914ef85,procState=-1,isForward=true,shouldSendCompatFakeFocus=false}
                                                                                                    tId:1599214240     Target activity: com.prepbgg.mymap.MyMap
                                                                                                    tId:1599214240   ]
                                                                                                    tId:1599214240 }
2026-06-01 11:04:33.283 32186-32186 AndroidRuntime          com.prepbgg.mymap                    D  Shutting down VM
2026-06-01 11:04:33.287 32186-32186 AndroidRuntime          com.prepbgg.mymap                    E  FATAL EXCEPTION: main
                                                                                                    Process: com.prepbgg.mymap, PID: 32186
                                                                                                    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.prepbgg.mymap/com.prepbgg.mymap.MyMap}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Bitmap.recycle()' on a null object reference
                                                                                                        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4710)
                                                                                                        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4941)
                                                                                                        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:222)
                                                                                                        at android.app.servertransaction.TransactionExecutor.executeNonLifecycleItem(TransactionExecutor.java:133)
                                                                                                        at android.app.servertransaction.TransactionExecutor.executeTransactionItems(TransactionExecutor.java:103)
                                                                                                        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:80)
                                                                                                        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:3150)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:110)
                                                                                                        at android.os.Looper.loopOnce(Looper.java:273)
                                                                                                        at android.os.Looper.loop(Looper.java:363)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:10060)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:632)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)
                                                                                                    Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Bitmap.recycle()' on a null object reference
                                                                                                        at com.prepbgg.mymap.MapView.drawTile(MapView.java:495)
                                                                                                        at com.prepbgg.mymap.MapView.showTiles(MapView.java:407)
                                                                                                        at com.prepbgg.mymap.MapView.doDrawing(MapView.java:281)
                                                                                                        at com.prepbgg.mymap.MapView.redrawBuffer(MapView.java:241)
                                                                                                        at com.prepbgg.mymap.MyMap.setupMapLayout(MyMap.java:540)
                                                                                                        at com.prepbgg.mymap.MyMap.onCreate(MyMap.java:182)
                                                                                                        at android.app.Activity.performCreate(Activity.java:9519)
                                                                                                        at android.app.Activity.performCreate(Activity.java:9488)
                                                                                                        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1524)
                                                                                                        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4692)
                                                                                                        ... 13 more
2026-06-01 11:04:33.306 32186-32186 Process                 com.prepbgg.mymap                    I  Sending signal. PID: 32186 SIG: 9
2026-06-01 11:05:25.087 32633-32633 nativeloader            com.prepbgg.mymap                    D  Load libframework-connectivity-tiramisu-jni.so using APEX ns com_android_tethering for caller /apex/com.android.tethering/javalib/framework-connectivity-t.jar: ok
2026-06-01 11:05:25.091 32633-32633 ActivityThread          com.prepbgg.mymap                    D  setConscryptValidator
2026-06-01 11:05:25.092 32633-32633 ActivityThread          com.prepbgg.mymap                    D  setConscryptValidator - put
---------------------------- PROCESS STARTED (32633) for package com.prepbgg.mymap ----------------------------
2026-06-01 11:05:25.144 32633-32633 nativeloader            com.prepbgg.mymap                    D  Configuring clns-9 for other apk /data/app/~~M8gbulRwXA9n-355k7ejBg==/com.prepbgg.mymap-fVWWYzNT8l4gNkOC3qcLUw==/base.apk. target_sdk_version=35, uses_libraries=, library_path=/data/app/~~M8gbulRwXA9n-355k7ejBg==/com.prepbgg.mymap-fVWWYzNT8l4gNkOC3qcLUw==/lib/arm64, permitted_path=/data:/mnt/expand:/data/user/0/com.prepbgg.mymap
2026-06-01 11:05:25.146 32633-32633 CompatChangeReporter    com.prepbgg.mymap                    D  Compat change id reported: 202956589; UID 10350; state: ENABLED
2026-06-01 11:05:25.157 32633-32633 GraphicsEnvironment     com.prepbgg.mymap                    V  Currently set values for:
2026-06-01 11:05:25.158 32633-32633 GraphicsEnvironment     com.prepbgg.mymap                    V    angle_gl_driver_selection_pkgs=[]
2026-06-01 11:05:25.158 32633-32633 GraphicsEnvironment     com.prepbgg.mymap                    V    angle_gl_driver_selection_values=[]
2026-06-01 11:05:25.158 32633-32633 GraphicsEnvironment     com.prepbgg.mymap                    V  com.prepbgg.mymap is not listed in per-application setting
2026-06-01 11:05:25.158 32633-32633 GraphicsEnvironment     com.prepbgg.mymap                    V  ANGLE allowlist from config: 
2026-06-01 11:05:25.158 32633-32633 GraphicsEnvironment     com.prepbgg.mymap                    V  com.prepbgg.mymap is not listed in ANGLE allowlist or settings, returning default
2026-06-01 11:05:25.158 32633-32633 GraphicsEnvironment     com.prepbgg.mymap                    V  Neither updatable production driver nor prerelease driver is supported.
2026-06-01 11:05:25.208 32633-32633 CompatChangeReporter    com.prepbgg.mymap                    D  Compat change id reported: 312399441; UID 10350; state: ENABLED
---------------------------- PROCESS ENDED (32633) for package com.prepbgg.mymap ----------------------------

导致崩溃的drawFile() 方法的代码如下。

Logcat中提到的第495行是两行中第一行,读取tile1.recycle()。

    private void drawTile(String strFilename, Rect rect, Canvas bufferCanvas, Paint paint){
        File f = new File(strFilename);

        if ( f.exists() && f!=null)
        {
            Bitmap tile1 = BitmapFactory.decodeFile(strFilename);
            if (tile1!=null) {
                bufferCanvas.drawBitmap(tile1, null, rect, paint);
            }
            tile1.recycle();
        }
        else {
            Log.i("Hi","Using blue");
            Bitmap tile1 = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().getPath() + "/maps/blue.gif");
            bufferCanvas.drawBitmap(tile1, null, rect, paint);
            tile1.recycle();
        }
    }

解决方案

大致来说,我们在清单中请求的权限分为三类:

  • 那些 protectionLevelnormal 的权限,例如 INTERNET。在大多数设备上,我们只需通过请求就能获得它们;清单中的声明是为了强化我们使用受保护内容的意图,并让用户知道我们确实有这样的意图。
  • 那些 protectionLeveldangerous 的权限,例如 READ_CONTACTS。这些是所谓的“运行时权限”,需要在清单中请求,并且要有专门的代码在运行时弹出对话框,要求用户授权权限。
  • 其余的权限,在获取方式上各不相同。很多在设置应用的“特殊访问”区域(Apps > Special app access),由用户通过这种方式手动授予。

在你的情况下,MANAGE_EXTERNAL_STORAGE 属于第三类。如果这是一个计划在Play商店及其他地方分发的应用,目标应尽量避免 MANAGE_EXTERNAL_STORAGE。这不仅从用户体验的角度让人恼火,Google也可能不允许你分发该应用。就你的情况而言,该应用仅供个人使用,只要你愿意在“特殊访问”中为你的应用开启相应开关,你就没问题,而且你对外部存储的完整文件系统拥有访问权限。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章