简体   繁体   English

应用关闭后,Android服务无法正常运行

[英]Android Service not staying alive after app closes

I want to have a background service, which will stay alive after the app is closed and which I can bind to again when the app is started. 我希望有一个后台服务,该后台服务在应用程序关闭后将保持活动状态,并且在启动应用程序时可以再次绑定到该后台服务。

For testing I made it that a counter will increase every time I bind to the service. 为了进行测试,我确定每次绑定到该服务时计数器都会增加。


So theoretically the app should start, I will create the service, then bind to it -> the counter should move up. 因此,从理论上讲,应用程序应该启动,我将创建服务,然后将其绑定->计数器应向上移动。

Then I close the app and press the Bind button again and It should log a "1" and move the counter up again. 然后我关闭该应用程序并再次按Bind按钮,它应该记录为“ 1”并再次向上移动计数器。

But it doesn't ... It will display a 0 every time I restart the app and bind to it ... 但这不是...每次我重新启动应用并绑定到它时,它将显示0。


This is my current Test - Service - class: 这是我当前的测试-服务-类:

package com.programm.testapp;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class TestService extends Service {

    /*
     * Service Binder
     */
    private final IBinder iBinder = new TestService.LocalConnectionService();

    public class LocalConnectionService extends Binder {
        public TestService getService(){
            return TestService.this;
        }
    }

    /*
     * Test var
     * It should increase every time the app is started.
     */
    private int test;

    @Override
    public IBinder onBind(Intent intent) {
        Log.d("mDEBUG", "Test: " + test);
        test++;

        return iBinder;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("mDEBUG", "Service: Start Command");

        return START_STICKY;
    }
}

This is my current Test - Activity: 这是我当前的测试-活动:

package com.programm.testapp;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    private TestService service;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button createButton = findViewById(R.id.button_create_service);
        createButton.setOnClickListener(this::createService);

        Button destroyButton = findViewById(R.id.button_destroy_service);
        destroyButton.setOnClickListener(this::destroyService);



        Button bindButton = findViewById(R.id.button_bind_service);
        bindButton.setOnClickListener(this::bindService);

        Button unbindButton = findViewById(R.id.button_unbind_service);
        unbindButton.setOnClickListener(this::unbindService);


    }

    private void createService(View v){
        Intent intent = new Intent(this.getBaseContext(), TestService.class);
        startService(intent);
    }

    private void destroyService(View v){
        Intent intent = new Intent(this.getBaseContext(), TestService.class);
        stopService(intent);
    }

    private void bindService(View v){
        Intent intent = new Intent(this.getBaseContext(), TestService.class);
        bindService(intent, serviceConnection, BIND_AUTO_CREATE);
    }

    private void unbindService(View v){
        unbindService(serviceConnection);
    }


    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d("mDEBUG", "Connection: on service connected");

            MainActivity.this.service = ((TestService.LocalConnectionService) service).getService();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d("mDEBUG", "Connection: on service disconnected");
        }
    };
}

This is my AndroidManifest.xml - file: 这是我的AndroidManifest.xml-文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.programm.testapp">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".TestService"
            android:enabled="true"
            android:exported="false"></service>
    </application>
</manifest>

This is my output after I ... 这是我...之后的输出

  1. Pressed Create Service - Button 按下创建服务-按钮
  2. Pressed Bind Service - Button 按下绑定服务-按钮
  3. Pressed Unbind Service - Button 按下取消绑定服务-按钮
  4. Close App and Restart it 关闭应用程序并重新启动
  5. Pressed Bind Service - Button 按下绑定服务-按钮

:

.../com.programm.testapp D/mDEBUG: Service: Start Command
.../com.programm.testapp D/mDEBUG: Test: 0
.../com.programm.testapp D/mDEBUG: Connection: on service connected
.../com.programm.testapp D/mDEBUG: Service: Start Command
.../com.programm.testapp D/mDEBUG: Test: 0
.../com.programm.testapp D/mDEBUG: Connection: on service connected

By the way the second "Service: Start Command" is called as I CLOSE the app ... after a few new Logs I noticed, that also the Constructer and the "onCreate" method of the Service - class will be called with it. 顺便说一句,当我关闭应用程序时,第二个“服务:启动命令”会被调用...在我注意到一些新日志之后,还将同时调用Service类的Constructor和“ onCreate”方法。

Is this normal? 这正常吗?


Edit: 编辑:

When I only minimize the App and not close it via Activity - Menu the behavior is exactly the one I want!!! 当我仅最小化该应用程序而不通过“活动-菜单”关闭它时,行为正是我想要的!!!


Edit 2: 编辑2:

A Foreground service does the job for now ... I couldn't find any other solution for this 前台服务现在可以完成工作...我找不到其他解决方案

If you actively close the app (by closing it from the Android activity list), Android will most likely kill your service. 如果您主动关闭该应用程序(通过从Android活动列表中将其关闭),则Android很可能会终止您的服务。 You can see that in your apps Logcat. 您可以在应用程序Logcat中看到它。 The only real way around that is a foreground service. 解决这一问题的唯一真正方法是前台服务。

Furthermore, onBind will not be called every time you bind to the service. 此外,每次绑定到服务时, 不会调用onBind From the Android documentation : Android文档中

You can connect multiple clients to a service simultaneously. 您可以同时将多个客户端连接到服务。 However, the system caches the IBinder service communication channel. 但是,系统缓存IBinder服务通信通道。 In other words, the system calls the service's onBind() method to generate the IBinder only when the first client binds. 换句话说,仅当第一个客户端绑定时,系统才调用服务的onBind()方法来生成IBinder。 The system then delivers that same IBinder to all additional clients that bind to that same service, without calling onBind() again. 然后,系统将同一IBinder提供给绑定到该服务的所有其他客户端,而无需再次调用onBind()。

Secondly, just that onStartCommand is called does not mean the service is recreated. 其次,仅调用onStartCommand并不意味着将重新创建服务。 It can be called multiple times during the service life cycle. 在使用寿命期间可以多次调用它。 For instance, each time startService is called, onStartCommand is executed, but the service is not necessarily recreated. 例如,每次调用startService时,都会执行onStartCommand,但是不一定必须重新创建服务。

Also, it looks like you do not un-bind the service when closing the activity. 此外,看起来您在关闭活动时未取消绑定服务。 That makes your activity leak the ServiceConnection and your app crash. 这会使您的活动泄漏ServiceConnection并导致应用程序崩溃。 It would explain why you see the service re-created every time you close and re-start the app. 它将解释为什么每次关闭并重新启动应用程序后都会看到重新创建该服务的原因。

Try adding an unbind in your activity's onPause method: 尝试在活动的onPause方法中添加取消绑定:

@Override
void onPause() {
    super.onPause()
    unbindService(this.serviceConnectino)
}

A working configuration could look like below. 工作配置如下所示。 It implements incrementing the counter using a dedicated service function, rather than onBind: 它使用专用服务功能而非onBind实现递增计数器:

MyBoundService.kt MyBoundService.kt

package com.test

import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log

class MyBoundService : Service() {

    abstract class MyBinder: Binder() {
        abstract fun getService(): MyBoundService
    }

    val iBinder: MyBinder = object: MyBinder() {
        override fun getService(): MyBoundService {
            return this@MyBoundService
        }
    }

    private var counter = 0

    fun increment() {
        counter ++
        Log.i("MyBoundService", "Counter: ${counter}")
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.i("MyBoundService", "startCommand");
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onBind(p0: Intent?): IBinder? {
        counter++
        Log.i("MyBoundService", "Bound: ${counter}")
        return iBinder
    }

    override fun onUnbind(intent: Intent?): Boolean {
        Log.i("MyBoundService", "Unbound")
        return super.onUnbind(intent)
    }
}

MainActivity.kt MainActivity.kt

package com.test

import android.content.Intent
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
import android.content.ComponentName
import android.content.Context
import android.content.ServiceConnection
import android.os.IBinder
import android.util.Log
import com.test.MyBoundService

class MainActivity : AppCompatActivity() {


    private val serviceConnection: ServiceConnection = object: ServiceConnection {
        override fun onServiceDisconnected(p0: ComponentName?) {
            Log.i("MainActivity", "Service disconnected")
        }

        override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
            Log.i("MainActivity", "Service connected")
            p1?.let {
                (p1 as MyBoundService.MyBinder).getService().increment()
            }
        }

    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        btn_create.setOnClickListener {
            val i = Intent(this@MainActivity, MyBoundService::class.java)
            startService(i)
        }

        btn_bind.setOnClickListener {
            val i = Intent(this@MainActivity, MyBoundService::class.java)
            bindService(i, serviceConnection, Context.BIND_AUTO_CREATE)
        }
    }

    override fun onPause() {
        super.onPause()
        unbindService(serviceConnection)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM