Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/213.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
未接收Intent.ACTION\u MEDIA\u安装在API 27的Android应用程序中,用于USB闪存驱动器_Android_Android Source_Android Broadcastreceiver - Fatal编程技术网

未接收Intent.ACTION\u MEDIA\u安装在API 27的Android应用程序中,用于USB闪存驱动器

未接收Intent.ACTION\u MEDIA\u安装在API 27的Android应用程序中,用于USB闪存驱动器,android,android-source,android-broadcastreceiver,Android,Android Source,Android Broadcastreceiver,下面的代码在API 23上工作,但在API 27上不工作。我了解到Android API 26及以上版本对接收广播意图有一些限制,但这些限制仅适用于清单文件中指定的限制: public class USBTest extends Service { private USBMountBroadcastReceiver mountBroadcastReceiver; private class USBMountBroadcastReceiver extends BroadcastR

下面的代码在API 23上工作,但在API 27上不工作。我了解到Android API 26及以上版本对接收广播意图有一些限制,但这些限制仅适用于清单文件中指定的限制:

public class USBTest extends Service
{
    private USBMountBroadcastReceiver mountBroadcastReceiver;

    private class USBMountBroadcastReceiver extends BroadcastReceiver
    {
        @Override
        public void onReceive(final Context context, Intent intent)
        {
            String action = intent.getAction();

            if (action == null)
            {
                Log.i(TAG, " got NULL action");
                return;
            }

            if (action.equals(Intent.ACTION_MEDIA_MOUNTED))
            {
                String root = intent.getData().getPath();
                Log.d(TAG, "USB mount path is" + root);
            }
        }
    }

    @Override
    public void onCreate()
    {
        mountBroadcastReceiver = new USBMountBroadcastReceiver();
        IntentFilter usbIntent = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
        usbIntent.addAction(Intent.ACTION_MEDIA_EJECT);
        usbIntent.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
        usbIntent.addAction(Intent.ACTION_MEDIA_REMOVED);
        usbIntent.addDataScheme("file");
        registerReceiver(mountBroadcastReceiver, usbIntent);
    }
}
更新1:广播接收器未提供服务:

public class USBBroadcastReceiver  extends BroadcastReceiver
{
    private static final String TAG = "USBBroadcastReceiver";

    /**
     * @see android.content.BroadcastReceiver#onReceive(Context,Intent)
     */
    @Override public void onReceive(Context context, Intent intent) {

        String action = intent.getAction();

        if (action!=null) Log.i(TAG, "got action = " + action);

        if (action==null)
        {
            Log.i(TAG, "got NULL action");
        }
        else if (Intent.ACTION_MEDIA_MOUNTED.equals(action))
        {
            Log.i(TAG, "Received media mounted : " + action);
        }
    }
}
public class TestUSB extends JobIntentService
{
    private static final String TAG = "TestUSB";

    /**
     * Unique job ID for this service.
     */
    static final int JOB_ID = 1001;

    @Override
    protected void onHandleWork(Intent intent)
    {
        Log.i(TAG, "onHandleWork");

        String action = intent.getAction();

        if (action!=null) Log.i(TAG, "got action = " + action);
    }
}
在舱单中:

<receiver android:name="USBBroadcastReceiver" android:exported="True">
    <intent-filter>
        <action android:name="android.intent.action.MEDIA_EJECT" />
        <action android:name="android.intent.action.MEDIA_REMOVED" />
        <action android:name="android.intent.action.MEDIA_MOUNTED" />
        <action android:name="android.intent.action.MEDIA_BAD_REMOVAL" />
        <data android:scheme="file" />
    </intent-filter>
</receiver>
<service android:name="TestUSB"
        android:permission="android.permission.BIND_JOB_SERVICE">
    <intent-filter>
        <action android:name="android.intent.action.MEDIA_MOUNTED" />
    </intent-filter>
</service>
在舱单中:

<receiver android:name="USBBroadcastReceiver" android:exported="True">
    <intent-filter>
        <action android:name="android.intent.action.MEDIA_EJECT" />
        <action android:name="android.intent.action.MEDIA_REMOVED" />
        <action android:name="android.intent.action.MEDIA_MOUNTED" />
        <action android:name="android.intent.action.MEDIA_BAD_REMOVAL" />
        <data android:scheme="file" />
    </intent-filter>
</receiver>
<service android:name="TestUSB"
        android:permission="android.permission.BIND_JOB_SERVICE">
    <intent-filter>
        <action android:name="android.intent.action.MEDIA_MOUNTED" />
    </intent-filter>
</service>

上述两种方法都不起作用。

来自以下文档:

安卓8.0限制了应用程序的功能,而用户没有 直接与他们互动。应用程序有两种限制方式:

  • 后台服务限制:当应用处于空闲状态时,其后台服务的使用会受到限制。这不适用于前台服务,因为前台服务对用户来说更为明显
  • 广播限制:除了有限的例外,应用程序无法使用其清单注册隐式广播。他们仍然可以 在运行时注册这些广播,它们可以使用 清单以注册特定目标的显式广播 在他们的应用程序上
因此有一些重要的后台服务限制

在后台运行的服务可能会消耗设备资源,可能会导致更糟糕的用户体验。为了缓解此问题,系统对服务应用了许多限制。 当应用程序位于前台时,它可以自由创建和运行前台和后台服务。当一个应用程序进入后台时,它有一个几分钟的窗口,在这个窗口中它仍然可以创建和使用服务。在该窗口结束时,应用程序被视为空闲。此时,系统停止应用程序的后台服务,就像应用程序调用了服务的Service.stopSelf()方法一样

在某些情况下,后台应用程序被放置在临时位置 白名单几分钟。当一个应用程序在白名单上时,它 可以不受限制地启动服务及其后台服务 被允许运行

因此,为了使其在安卓8.0(API 26)中工作,您通常可以用
JobScheduler
作业替换后台服务。它将在满足特定条件时安排要执行的任务

或者,您可以让一个服务在后台运行,不断地检查这一点,但通过一个通知通知用户后台正在运行某些东西,这实际上使该服务成为一个前台服务。但一旦通知消失或被驳回,服务就会停止

最后,我认为在您的情况下,您可以在清单中注册您的广播接收器,因为

针对Android 8.0或更高版本的应用程序不能再在其清单中为隐式广播注册广播接收器

这些广播受上述限制:

ACTION_MEDIA_MOUNTED, ACTION_MEDIA_CHECKING, ACTION_MEDIA_UNMOUNTED, ACTION_MEDIA_EJECT, ACTION_MEDIA_UNMOUNTABLE, ACTION_MEDIA_REMOVED, ACTION_MEDIA_BAD_REMOVAL
所以你应该能够让它工作,在清单中声明你的广播接收器

编辑

尝试在清单中使用此代码

<receiver android:name="USBBroadcastReceiver" android:exported="True">
    <intent-filter>
        <action android:name="android.intent.action.MEDIA_EJECT" />
        <action android:name="android.intent.action.MEDIA_REMOVED" />
        <action android:name="android.intent.action.MEDIA_MOUNTED" />
        <action android:name="android.intent.action.MEDIA_BAD_REMOVAL" />
        <data android:scheme="file" />
    </intent-filter>
</receiver>

我也遇到了同样的问题,直到找到这篇文章:


显然,必须触发媒体安装的过滤器…

意图。媒体安装的操作对我也不起作用。使用
contentobservator
的工作原理如下:

Uri uri = DocumentsContract.buildRootsUri("com.android.externalstorage.documents");

ContentObserver contentObserver = new ContentObserver(handler) {
    @Override
    public void onChange(boolean selfChange) {
        StorageManager sm = (StorageManager) requireContext().getSystemService(Context.STORAGE_SERVICE);
        // Check for new volumes here:
        for (StorageVolume storageVolume : sm.getStorageVolumes()) {
        }
    }
};

context.getContentResolver().registerContentObserver(uri, false, contentObserver);

(是Android源代码中触发更改的代码。)

您针对的是哪一个API级别?@PRA我针对的是API 27我在Android 9的像素1上也有同样的问题。在运行时使用清单和进行注册,但两者都不起作用。这段代码在Android 7.0上的三星S6上运行良好。因此,如果我将其添加到清单中,我可以在服务中使用它吗?或者我还需要使用作业调度器吗?您不需要服务。您将广播添加到清单中(因此它已经注册),实现该类,并在onReceive方法中定义在“捕获”该意图或动作时要执行的操作。不要在内部执行onReceive长时间运行的工作,因为系统可能会在10秒后终止整个进程。而是启动一个通知、一个活动或一个线程,从主线程运行所需的代码。更多信息,以及关于我所说内容的页面末尾。我通过从BroadcastReceiver扩展它创建了一个新类,并在清单文件的意图过滤器中指定了“android.intent.action.MEDIA_MOUNTED”操作。但是,当我插入USB时,我仍然没有在OnReceive()中接收到意图。也许您需要指定权限,如
?我建议您也使用
adb shell dumpsys activity broadcasts history
检查您的设备是否正在实际启动广播。我遇到了这个问题,发现我的设备在插入USB闪存驱动器时甚至没有启动广播。