IntentService的StartForeground

13

我有一个IntentService,我想使用正在运行的通知使其保持黏性。问题是通知会出现然后立即消失。服务仍在继续运行。我应该如何在IntentService中使用startForeground()

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);
    Notification notification = new Notification(R.drawable.marker, "Notification service is running",
            System.currentTimeMillis());
    Intent notificationIntent = new Intent(this, DashboardActivity.class);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|
        Intent.FLAG_ACTIVITY_SINGLE_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    notification.setLatestEventInfo(this, "App",
            "Notification service is running", pendingIntent);
    notification.flags|=Notification.FLAG_NO_CLEAR;
    startForeground(1337, notification);
    return START_STICKY;
}

@Override
protected void onHandleIntent(Intent intent) {

    String id = intent.getStringExtra(ID);
    WebSocketConnectConfig config = new WebSocketConnectConfig();
    try {
        config.setUrl(new URI("ws://" + App.NET_ADDRESS
                + "/App/socket?id="+id));
    } catch (URISyntaxException e) {
        e.printStackTrace();
    }
    ws = SimpleSocketFactory.create(config, this);
    ws.open();
}

谢谢

2个回答

23

这不应该是一个IntentService。按照原来的写法,你的IntentService只会存活一毫秒左右。一旦onHandleIntent()返回,服务就会被销毁。这应该是一个常规的Service,在其中分叉出自己的线程并管理线程和服务的生命周期。

你的Notification立即消失的原因是服务立即消失。


5
因为可能是错误的答案,所以被踩了。从IntentService文档中摘录:“所有请求都在单个工作线程上处理-它们可能需要尽可能长的时间(并且不会阻塞应用程序的主循环),但一次只能处理一个请求。” 没有提到毫秒或类似的内容。https://developer.android.com/reference/android/app/IntentService.html - GregoryK
3
按照现有的写法,这个 IntentService 只会存在一毫秒左右的时间,因为在 onHandleIntent() 中的代码只需要一毫秒左右的运行时间。 - CommonsWare
3
@GregoryK 实际上答案是正确的,因为 onHandleIntent 方法中没有任何线程阻塞的代码来防止 IntentService 销毁。 - Arcao
这个答案是不正确的,根据文档:该方法可能需要几秒钟才能完成,所以应该只能从一个工作线程中调用。 - sam_k

6
根据IntentService文档的说明:服务在需要时启动,使用工作线程依次处理每个意图,并在没有任务时停止自身。因此,我认为问题在于当onHandleIntent()完成后,您的服务将没有任务可执行。因此,服务停止并且通知被关闭。因此,对于您的任务,IntentService的概念可能不是最佳选择。
由于问题的标题是“IntentService的StartForeground”,我想澄清一些事情:
要使您的IntentService在前台运行非常简单(请参见下面的代码),但是您需要考虑几件事:
  • 如果服务只需要几秒钟,请不要将其放在前台 - 这可能会让用户感到烦恼。想象一下您定期运行短任务 - 这将导致通知出现和消失 - 哎呀*

  • 您可能需要使您的服务能够保持设备唤醒状态(但这是另一个故事,它在stackoverflow上得到了很好的涵盖)*

  • 如果您将多个意图排队发送到IntentService,则下面的代码将显示/隐藏通知。 (因此,对于您的情况可能有更好的解决方案 - 正如@CommonsWare建议扩展Service并自己完成所有操作,但是我想提醒您 - IntentService的javadoc中没有任何内容说它只能工作几秒钟 - 它可以一直工作,直到有任务需要执行。)

public class ForegroundService extends IntentService {

    private static final String TAG = "FrgrndSrv";

    public ForegroundService() {
        super(TAG);
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        Notification.Builder builder = new Notification.Builder(getBaseContext())
                .setSmallIcon(R.drawable.ic_foreground_service)
                .setTicker("Your Ticker") // use something from something from R.string
                .setContentTitle("Your content title") // use something from something from
                .setContentText("Your content text") // use something from something from
                .setProgress(0, 0, true); // display indeterminate progress

        startForeground(1, builder.build());
        try {
            doIntesiveWork();
        } finally {
            stopForeground(true);
        }
    }

    protected void doIntesiveWork() {
        // Below should be your logic that takes lots of time
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

1
计算机编程的一个通用规则是:永远不要对其他资源代表你获取的资源做出任何假设。您没有创建IntentService使用的后台线程,因此不应该对您可以安全使用它的时间做出任何假设。我们在AsyncTask中遇到了这个问题,Google改变了execute()的规则,限制您在所有任务中只能使用单个线程。如果您想长时间持有线程,请创建自己的线程。建议令人尴尬的编程实践会被投票否决。 - CommonsWare
3
@CommonsWare 我理解你的观点,很有道理。实际上,我对于“按照现有写法,你的IntentService只会存在1毫秒左右”这个说法有些不同意。我并非要做出任何假设,Java API中明确说明:“IntentService是用于处理异步请求(表示为Intent)的服务的基类。客户端通过startService(Intent)调用发送请求;服务根据需要启动,使用工作线程依次处理每个Intent,当工作完成后停止自身。” - GregoryK

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