Служба Android не остается в живых после закрытия приложения - PullRequest
0 голосов
/ 05 марта 2019

Я хочу иметь фоновый сервис, который останется в живых после закрытия приложения и с которым я могу снова связываться при запуске приложения.

Для тестирования я сделал так, что счетчик будет увеличиваться каждый развремя привязки к сервису.


Так что теоретически приложение должно запуститься, я создам сервис, а затем привязаться к нему -> счетчик должен переместиться вверх.

Затем я закрываюприложение и нажмите кнопку Bind снова, и он должен войти в «1» и снова переместить счетчик.

Но это не так ... Он будет отображать 0 каждый раз, когда я перезапускаю приложение и связываюк нему ...


Это мой текущий тест - Сервис - класс:

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;
    }
}

Это мой текущий тест - Активность:

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");
        }
    };
}

Это мой 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>

Это мой вывод после того, как я ...

  1. Служба Pressed Create - кнопка
  2. Служба Pressed Bind- Кнопка
  3. Служба отмененного связывания нажата - Кнопка
  4. Закрыть приложение и перезапустить его
  5. Служба нажатой привязки - кнопка

:

.../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

Кстати, вторая "Служба: команда запуска" вызывается, когда я ЗАКРЫВАЮ приложение ... после несколькихновые журналы Я заметил, что вместе с ним будут вызываться также Constructer и метод onCreate класса Service.

Это нормально?


Редактировать:

Когда я только сворачиваю приложение и не закрываю его через Activity - Menu, поведение точно такое, как я хочу !!!


Edit 2:

Служба Foreground сейчас выполняет свою работу ... Я не смог найти другое решение для этого

1 Ответ

0 голосов
/ 05 марта 2019

Если вы активно закроете приложение (закрыв его из списка активности Android), Android, скорее всего, убьет ваш сервис. Вы можете видеть это в своих приложениях Logcat. Единственный реальный способ обойти это - обслуживание переднего плана.

Кроме того, onBind будет не вызываться при каждом подключении к услуге. Из документации Android :

Вы можете подключить несколько клиентов к услуге одновременно. Однако система кэширует канал связи службы IBinder. Другими словами, система вызывает метод onBind () службы для генерации IBinder только тогда, когда первый клиент связывается. Затем система доставляет тот же IBinder всем дополнительным клиентам, которые связываются с этой же службой, без повторного вызова onBind ().

Во-вторых, только то, что вызывается onStartCommand, не означает, что служба создается заново. Его можно вызывать несколько раз в течение жизненного цикла службы. Например, каждый раз, когда вызывается startService, выполняется onStartCommand, но служба не обязательно воссоздается.

Кроме того, похоже, что вы не отменяете привязку службы при закрытии действия. Это делает вашу деятельность утечкой ServiceConnection и сбой вашего приложения. Это объясняет, почему вы видите, что сервис создается заново каждый раз, когда вы закрываете и перезапускаете приложение.

Попробуйте добавить unbind в методе onPause вашей деятельности:

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

Рабочая конфигурация может выглядеть следующим образом. Он реализует увеличение счетчика с помощью специальной сервисной функции, а не onBind:

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

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)
    }
}
...