在Android上尝试在启动时启动服务

344

我一直在尝试在Android设备启动时启动一个服务,但我无法使其工作。我查看了许多在线链接,但其中没有任何代码起效。我是否遗漏了什么?

AndroidManifest.xml

<receiver
    android:name=".StartServiceAtBootReceiver"
    android:enabled="true"
    android:exported="false"
    android:label="StartServiceAtBootReceiver" >
    <intent-filter>
        <action android:name="android.intent.action._BOOT_COMPLETED" />
    </intent-filter>
</receiver>

<service
    android:name="com.test.RunService"
    android:enabled="true" />

BroadcastReceiver

public void onReceive(Context context, Intent intent) {
    if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
        Intent serviceLauncher = new Intent(context, RunService.class);
        context.startService(serviceLauncher);
        Log.v("TEST", "Service loaded at start");
    }
}

2
我不太清楚自己做了什么,但我认为现在它可以工作了。可能是接收器的android:permission="android.permission.RECEIVE_BOOT_COMPLETED"的问题。 - Alex
你检查过 <action android:name="android.intent.action._BOOT_COMPLETED"/> 中的额外 "_" 了吗? - OneWorld
导出必须为true,这样系统才能调用接收器,对吧?还是默认就是true? - Eugen Pechanec
针对Oreo,查看此处:https://dev59.com/eVcP5IYBdhLWcg3wXI7Z - Andy Weinstein
16个回答

4

3

在挂载外部存储之前,会发送BOOT_COMPLETE消息。如果您的应用安装在外部存储中,则不会收到BOOT_COMPLETE广播消息。为了防止这种情况发生,您可以将应用程序安装在内部存储中。您只需在menifest.xml文件中添加以下行即可完成:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="internalOnly"
... >

一些HTC设备可以启用“快速启动”功能,类似于深度休眠而不是真正的重新启动,因此不应该产生BOOT_COMPLETE意图。要恢复此功能,您可以在接收器中添加此意图过滤器:
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            </intent-filter>

正如您所建议的那样,为了防止上述问题,开发人员可以在应用程序清单中设置“android:installLocation =”internalOnly"。这是一个坏主意吗?对于智能手机应用程序,如果99.9%(我猜测)的所有用户通常安装应用程序,使用内部存储而不是外部存储,则似乎将“internalOnly”添加到清单中是可以的。我很感激您对此的任何想法或建议。- AJW - AJW

2

正如@Damian所评论的那样,本主题中的所有答案都是错误的。手动执行此操作会存在设备进入睡眠状态而导致服务停止的风险。您需要先获取唤醒锁。幸运的是,支持库提供了一个类来完成此操作:

public class SimpleWakefulReceiver extends WakefulBroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // This is the Intent to deliver to our service.
        Intent service = new Intent(context, SimpleWakefulService.class);

        // Start the service, keeping the device awake while it is launching.
        Log.i("SimpleWakefulReceiver", "Starting service @ " + SystemClock.elapsedRealtime());
        startWakefulService(context, service);
    }
}

然后,在您的 Service 中,请确保释放唤醒锁:

    @Override
    protected void onHandleIntent(Intent intent) {
        // At this point SimpleWakefulReceiver is still holding a wake lock
        // for us.  We can do whatever we need to here and then tell it that
        // it can release the wakelock.

...
        Log.i("SimpleWakefulReceiver", "Completed service @ " + SystemClock.elapsedRealtime());
        SimpleWakefulReceiver.completeWakefulIntent(intent);
    }

不要忘记在你的清单文件中添加WAKE_LOCK权限:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

我有一个小问题不太确定。如果我的_service_是一个Service而不是IntentService,我不能使用这种方式,因为简单的Service中无法覆盖onHandleIntend方法? - paolo2988
我遇到了同样的问题。你介意帮我吗?谢谢!http://stackoverflow.com/questions/35373525/starting-my-service - Ruchir Baronia
也许可以使用 onNewIntent()?或者你可以查看 IntentService 的源代码,看看你的 Service 需要做什么才能匹配它... - phreakhead

2
如果您正在使用Android Studio,并且您非常喜欢自动完成功能,则我必须告知您,我正在使用Android Studio v 1.1.0,并且我已经使用了以下权限的自动完成。
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

Android Studio自动完成的RECEIVE_BOOT_COMPLETED都是小写的,例如receive_boot_completed,我一直在为此烦恼,因为我已经勾选了启动服务时需要做的检查清单。我再次确认了这一点。

Android Studio确实会以小写方式自动完成此权限。


1
事实上,我不久前也遇到了这个问题,但它真的很容易解决。如果您设置了"android.intent.action.BOOT_COMPLETED"权限和意图过滤器,则实际上没有做错任何事情。
请注意,如果您使用的是Android 4.X版本,在启动服务之前必须运行广播接收器,这意味着您必须首先添加一个活动。一旦广播接收器运行,您的应用程序应该按照您的期望进行操作。然而在Android 4.X中,我还没有找到一种在没有任何活动的情况下启动服务的方法,我认为谷歌出于安全原因这样做。

0
如果我在接收器类中保留空构造函数,就会遇到这个问题。删除空构造函数后,onReceive方法开始正常工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接