应用程序关闭时,Kivy服务会停止

时间:2017-11-18 03:24:30

标签: android python android-service kivy

我从我的Kivy应用程序开始提供服务:

service = autoclass('net.saband.myapp.ServiceMyservice')
mActivity = autoclass('org.kivy.android.PythonActivity').mActivity
service.start(mActivity, '')

有效。如果我使用后退按钮关闭我的应用程序,我的服务仍然有效。但如果我通过从最近的应用程序列表中删除我的应用程序来关闭我的应用程序,服务就会消失。

我找到this issue并尝试使用this article引导的startForeground。它可以工作,但通知不可删除,所以这个解决方案不适合我。

我已经阅读了this question,看起来我可以使用START_STICKY帮助...但它是kivy服务,那么我该如何实现呢?我试图在我的python-for-android模板中编辑Service.tmpl.java并更改它:

public class Service{{ name|capitalize }} extends PythonService {
    {% if sticky %}
    @Override
    public int startType() {
        return START_STICKY;
    }
    {% endif %}
...

到此:

public class Service{{ name|capitalize }} extends PythonService {

    @Override
    public int startType() {
        return START_STICKY;
    }

(是的,我知道{% if sticky %}意味着我可以将其设置在某个地方,但在official docs中没有任何关于它的信息。)

但没有改变,服务仍然死亡。根据日志安排重启:

11-17 22:52:07.140  1496  1511 I ActivityManager: Killing 29431:net.saband.myapp/u0a122 (adj 9): remove task
11-17 22:52:07.219  1496  3404 I WindowState: WIN DEATH: Window{3c605b3 u0 net.saband.myapp/org.kivy.android.PythonActivity}
11-17 22:52:07.220  1496  3404 W WindowManager: Force-removing child win Window{5ed4ff u0 SurfaceView} from container Window{3c605b3 u0 net.saband.myapp/org.kivy.android.PythonActivity}
11-17 22:52:07.225  1496  2871 W WindowManager: Failed looking up window
11-17 22:52:07.225  1496  2871 W WindowManager: java.lang.IllegalArgumentException: Requested window android.os.BinderProxy@c7f2770 does not exist
11-17 22:52:07.225  1496  2871 W WindowManager:     at com.android.server.wm.WindowManagerService.windowForClientLocked(WindowManagerService.java:8821)
11-17 22:52:07.225  1496  2871 W WindowManager:     at com.android.server.wm.WindowManagerService.windowForClientLocked(WindowManagerService.java:8812)
11-17 22:52:07.225  1496  2871 W WindowManager:     at com.android.server.wm.WindowState$DeathRecipient.binderDied(WindowState.java:1212)
11-17 22:52:07.225  1496  2871 W WindowManager:     at android.os.BinderProxy.sendDeathNotice(Binder.java:558)
11-17 22:52:07.225  1496  2871 I WindowState: WIN DEATH: null
11-17 22:52:07.247  1496  3311 D ActivityManager: cleanUpApplicationRecord -- 29431
11-17 22:52:07.250  1496  3538 I ActivityManager: Killing 29366:net.saband.myapp:service_myservice/u0a122 (adj 8): remove task
11-17 22:52:07.304  1496  3557 D ActivityManager: cleanUpApplicationRecord -- 29366
11-17 22:52:07.305  1496  3557 W ActivityManager: Scheduling restart of crashed service net.saband.myapp/.ServiceMyservice in 1000ms

但没有任何反应。

我需要该服务即使在应用程序关闭时也可以通过从最近的应用列表中滑出来继续工作。我需要可移动通知。就这样。许多应用都可以做到。但有没有办法用Kivy和python-for-android做到这一点?

感谢。

1 个答案:

答案 0 :(得分:1)

我做到了。但这需要更改java代码,解决方案是硬编码的。 python-for-android开发人员没有预料到这一点,这是奇怪而令人不快的。

嗯,解决方案。

打开文件.buildozer/android/platform/build/dists/myapp/src/org/kivy/android/PythonService.java。在功能startType()中,将START_NOT_STICKY更改为START_STICKY

public int startType() {
    return START_STICKY;
}

现在服务将重新启动。但这还不够,因为在函数onStartCommand(Intent intent, int flags, int startId)重新启动后,intent将为null,因此我们将收到错误:

E AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.os.Bundle android.content.Intent.getExtras()' on a null object reference

所以我们需要在这个函数中添加if语句:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (pythonThread != null) {
        Log.v("python service", "service exists, do not start again");
        return START_NOT_STICKY;
    }
    if (intent != null) { 
        startIntent = intent;
        Bundle extras = intent.getExtras();
        androidPrivate = extras.getString("androidPrivate");
        androidArgument = extras.getString("androidArgument");
        serviceEntrypoint = extras.getString("serviceEntrypoint");
        pythonName = extras.getString("pythonName");
        pythonHome = extras.getString("pythonHome");
        pythonPath = extras.getString("pythonPath");
        pythonServiceArgument = extras.getString("pythonServiceArgument");

        pythonThread = new Thread(this);
        pythonThread.start();

        if (canDisplayNotification()) {
            doStartForeground(extras);
        }
    } else {
        pythonThread = new Thread(this);
        pythonThread.start();
    }

    return startType();
}

但这还不够,因为现在我们在nativeStart函数调用中有另一个错误,因为没有额外内容:

F DEBUG   : Abort message: 'art/runtime/java_vm_ext.cc:410] JNI DETECTED ERROR IN APPLICATION: GetStringUTFChars received NULL jstring'

所以我添加了空检查和一些默认值(其中2个是硬编码的)到run()函数:

@Override
public void run(){
    String package_root = getFilesDir().getAbsolutePath();
    String app_root =  package_root + "/app";
    File app_root_file = new File(app_root);
    PythonUtil.loadLibraries(app_root_file);
    this.mService = this;

    if (androidPrivate == null) {
        androidPrivate = package_root;
    }
    if (androidArgument == null) {
        androidArgument = app_root;
    }
    if (serviceEntrypoint == null) {
        serviceEntrypoint = "./service/main.py"; // hardcoded
    }
    if (pythonName == null) {
        pythonName = "myservice"; // hardcoded
    }
    if (pythonHome == null) {
        pythonHome = app_root;
    }
    if (pythonPath == null) {
        pythonPath = package_root;
    }
    if (pythonServiceArgument == null) {
        pythonServiceArgument = app_root+":"+app_root+"/lib";
    }

    nativeStart(
        androidPrivate, androidArgument,
        serviceEntrypoint, pythonName,
        pythonHome, pythonPath,
        pythonServiceArgument);
    stopSelf();
}

现在可行。