这个解决方法基本上是使服务自动重启。这意味着您的服务将从头开始运行。是的,这是硬编码。
在Service模板文件的start()方法中添加一个字符串参数。
我的是“restart”参数。这将成为活动意图的额外参数,传递给由ctx.startService()方法触发的onStartCommand()方法。然后将“autoRestartService”与该
restart参数值一起使用。
我的.buildozer/android/platform/build-/dists//templates/Service.tmpl.java:
package {{ args.package }};
import android.content.Intent;
import android.content.Context;
import org.kivy.android.PythonService;
public class Service{{ name|capitalize }} extends PythonService {
{% if sticky %}
@Override
public int startType() {
return START_STICKY;
}
{% endif %}
@Override
protected int getServiceId() {
return {{ service_id }};
}
static public void start(Context ctx, String pythonServiceArgument, String restart) {
Intent intent = new Intent(ctx, Service{{ name|capitalize }}.class);
String argument = ctx.getFilesDir().getAbsolutePath() + "/app";
intent.putExtra("androidPrivate", ctx.getFilesDir().getAbsolutePath());
intent.putExtra("androidArgument", argument);
intent.putExtra("serviceTitle", "{{ args.name }}");
intent.putExtra("serviceDescription", "{{ name|capitalize }}");
intent.putExtra("serviceEntrypoint", "{{ entrypoint }}");
intent.putExtra("pythonName", "{{ name }}");
intent.putExtra("serviceStartAsForeground", "{{ foreground|lower }}");
intent.putExtra("pythonHome", argument);
intent.putExtra("pythonPath", argument + ":" + argument + "/lib");
intent.putExtra("pythonServiceArgument", pythonServiceArgument);
intent.putExtra("autoRestartService", restart);
ctx.startService(intent);
}
static public void stop(Context ctx) {
Intent intent = new Intent(ctx, Service{{ name|capitalize }}.class);
ctx.stopService(intent);
}
}
在PythonService的onStartCommand()方法中设置autoRestartService值
请查看下面的PythonService的onDestroy()方法。如果服务被关闭(由于关闭应用程序或从最近的应用程序中滑动),将触发onDestroy()方法。根据autoRestartService值,有一个选项是否重新启动服务。因此,在onStartCommand()方法中通过从意图附加项获取它来设置它。
我的.buildozer/android/platform/build-/dists//src/main/org/kivy/android/PythonService.java:
package org.kivy.android;
import android.os.Build;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import android.app.Service;
import android.os.IBinder;
import android.os.Bundle;
import android.content.Intent;
import android.content.Context;
import android.util.Log;
import android.app.Notification;
import android.app.PendingIntent;
import android.os.Process;
import java.io.File;
import android.app.NotificationManager;
import android.app.NotificationChannel;
import android.graphics.Color;
public class PythonService extends Service implements Runnable {
private Thread pythonThread = null;
private String androidPrivate;
private String androidArgument;
private String pythonName;
private String pythonHome;
private String pythonPath;
private String serviceEntrypoint;
private String pythonServiceArgument;
public static PythonService mService = null;
private Intent startIntent = null;
private boolean autoRestartService = false;
public void setAutoRestartService(boolean restart) {
autoRestartService = restart;
}
public int startType() {
return START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@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;
}
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");
boolean serviceStartAsForeground = (
extras.getString("serviceStartAsForeground").equals("true")
);
pythonServiceArgument = extras.getString("pythonServiceArgument");
autoRestartService = (
extras.getString("autoRestartService").equals("true")
);
pythonThread = new Thread(this);
pythonThread.start();
if (serviceStartAsForeground) {
doStartForeground(extras);
}
return startType();
}
protected int getServiceId() {
return 1;
}
protected void doStartForeground(Bundle extras) {
String serviceTitle = extras.getString("serviceTitle");
String serviceDescription = extras.getString("serviceDescription");
Notification notification;
Context context = getApplicationContext();
Intent contextIntent = new Intent(context, PythonActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(context, 0, contextIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
notification = new Notification(
context.getApplicationInfo().icon, serviceTitle, System.currentTimeMillis());
try {
Method func = notification.getClass().getMethod(
"setLatestEventInfo", Context.class, CharSequence.class,
CharSequence.class, PendingIntent.class);
func.invoke(notification, context, serviceTitle, serviceDescription, pIntent);
} catch (NoSuchMethodException | IllegalAccessException |
IllegalArgumentException | InvocationTargetException e) {
}
} else {
String NOTIFICATION_CHANNEL_ID = "org.kivy.p4a";
String channelName = "Background Service";
NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName,
NotificationManager.IMPORTANCE_NONE);
chan.setLightColor(Color.BLUE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.createNotificationChannel(chan);
Notification.Builder builder = new Notification.Builder(context, NOTIFICATION_CHANNEL_ID);
builder.setContentTitle(serviceTitle);
builder.setContentText(serviceDescription);
builder.setContentIntent(pIntent);
builder.setSmallIcon(context.getApplicationInfo().icon);
notification = builder.build();
}
startForeground(getServiceId(), notification);
}
@Override
public void onDestroy() {
super.onDestroy();
pythonThread = null;
if (autoRestartService && startIntent != null) {
Log.v("python service", "service restart requested");
startService(startIntent);
}
Process.killProcess(Process.myPid());
}
@Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
stopSelf();
}
@Override
public void run(){
String app_root = getFilesDir().getAbsolutePath() + "/app";
File app_root_file = new File(app_root);
PythonUtil.loadLibraries(app_root_file,
new File(getApplicationInfo().nativeLibraryDir));
this.mService = this;
nativeStart(
androidPrivate, androidArgument,
serviceEntrypoint, pythonName,
pythonHome, pythonPath,
pythonServiceArgument);
stopSelf();
}
public static native void nativeStart(
String androidPrivate, String androidArgument,
String serviceEntrypoint, String pythonName,
String pythonHome, String pythonPath,
String pythonServiceArgument);
}
这里有一个setAutoRestartService()方法,但我们无法调用它,因为它是非静态方法。
最后一件事,buildozer.spec
在buildozer.spec中添加FOREGROUND_SERVICE权限和服务。
android.permissions = FOREGROUND_SERVICE
...
services = myservice:./path/to/your-service.py:foreground
现在通过将“true”字符串作为第三个位置参数来启动服务。
activity = autoclass('org.kivy.android.PythonActivity').mActivity
service = autoclass('com.omdo.example.ServiceMyservice')
service.start(activity, '', 'true')
注意: 我并不真正理解Java,希望有人能让它更简单易懂。
参考:
contextIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
但它没有帮助。我该如何实现这个? - volion80