Android如何在不同的线程中运行Service?

29

我正在开发一款Android应用程序,其中包括一个服务来读取多个小时的传感器值。当我启动服务时,我的设备会卡住,所有其他进程都变得缓慢。为了解决这个问题,我尝试在单独的线程中启动服务,如下所示,但问题仍然存在。

    new Thread(new Runnable() {

                @Override
                public void run() {
                    Intent intent=new Intent(getApplicationContext(), SensorService.class);
                    startService(intent);

                }
            }).start();

这个线程只是在不同的线程启动服务,但服务在主线程中运行。有人可以帮助我如何在单独的线程中运行服务吗?


你应该发布你正在尝试运行的代码,这样我们才能看到你正在做什么。我猜测你在服务中的代码应该在一个新线程上执行。请发布你正在尝试执行的服务。 - BlackHatSamurai
6个回答

9
应用程序组件(服务、活动等)始终在主线程中运行,无论它们从哪个线程启动。考虑在您的服务中启动线程,或使用IntentService来解决。
在您的特定情况下,您可以尝试为传感器更改注册全局BroadcastReceiver,然后启动一个IntentService将新获取的值放入数据库中。
实际上,这里是类似问题的解决方案链接
再次强调,这不是真正的多线程问题。整个任务必须以另一种方式实现。

嗨,尤金,感谢您的快速回复。传感器值每70毫秒更改一次,因此我认为我们不需要注册全局广播接收器。 - praveen
我担心长时间运行的任务,每70毫秒注册一次事件,会很快耗尽电池。 - Eugene
1
IntentService 已经被弃用了。 - Jordan
9年后,lol - Eugene

2
为了在同一进程但另一个非主线程中启动服务,我们可以创建另一个HandlerThread并使用Handler在其上运行我们的任务。
class MyService : Service() {
    private lateinit var thread: HandlerThread
    private lateinit var handler: Handler

    override fun onCreate() {
        super.onCreate()
        thread = HandlerThread("MyService").apply {
            start()
        }
        handler = Handler(thread.looper)
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        if (intent?.action == "my-job") {
            handler.post {
                // Do any job on another non-main thread here
                // ...
            }
        }
    }

    override fun onDestroy() {
        thread.interrupt()
        super.onDestroy()
    }
}

1
这是2022年的正确答案。 - yehyatt

2

你所做的只是启动新的活动,所以如果你运行监视器的逻辑在 SensorService 中,那么它仍然会在主线程上运行。你需要将监视逻辑放入新线程中,而不仅仅是使用它来启动活动。

如果你想在后台线程上运行服务,你需要使用静态的 performOnBackgrounThread 方法,就像这段代码一样,可以在Android文档(android-8\SampleSyncAdapter\src\com\example\android\samplesync\client\NetworkUtilities.java)中找到:

public static Thread performOnBackgroundThread(final Runnable runnable) {
    final Thread t = new Thread() {
        @Override
        public void run() {
            try {
                runnable.run();
            } finally {

            }
        }
    };
    t.start();
    return t;
}

还要记住的是,您永远不应该在主UI线程上执行网络操作。虽然您在这里没有这样做,但这只是一个提示...


嗨,布莱恩,如何将监视逻辑放在新线程中? - praveen
你提供的代码无法运行,服务仍在主线程中运行。我想在不同的线程中运行。 - praveen
你应该发布你正在尝试运行的代码,这样我们才能看到你正在做什么。 - BlackHatSamurai

2
您可以使用后台服务来解决这个问题。通过使用具有sleep()Thread,可以为特定实例提供解决方案。此链接Background Servies将会对您有所帮助。或者可以使用PendingIntent来解决问题,例如...
PendingIntent operation = PendingIntent.getActivity(getBaseContext(), 0, ij, Intent.FLAG_ACTIVITY_NEW_TASK);

1
我认为解决这个问题的答案在于使用 IntentService 的能力。 IntentService 是常规 Service 类的子类。然而,它们之间有一些关键的区别。
现在,以下是您如何利用 IntentServices: IntentServices 不在主线程上运行。相反,它们在单独的“工作线程”上运行。这个单一属性将解决您的问题并消除您当前面临的 ANR 问题。
要了解服务和 IntentServices 之间的差异,请查看此处

0

1
这对我没有用;尽管在不同的线程中调用了startService,但服务似乎仍在主线程中运行。 - Sam

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