我写了一个应用程序,它需要一直作为前台服务运行。在安卓11设备上进行测试时,操作系统喜欢关闭前台服务。我在一堆其他应用程序中执行操作,然后当我退出其中一个随机应用程序时,操作系统会终止前台服务。在我正在测试的android 7和更早的设备上,我没有看到这种行为。我还没有8-10的测试。
我花了一些时间试图阻止杀戮的发生,但我承认这是新操作系统的一部分,只是为了处理重启问题。
我遇到的问题是,在操作系统重新启动服务之后,ondestroy几乎总是在oncreate之后调用。
当我将返回值设置为start_sticky时,它调用oncreate,然后几乎总是调用ondestroy。onstartcommand失败时不调用。由于未调用onstartcommand,因此服务从未重新启动。没有通过通知调用startforeground可以解释此场景中的ondestroy,但ondestroy是在瞬间调用的。我见过它以0.001秒的速度发生。
当我将返回值设置为start\u redeliver\u intent时,它调用oncreate、onstartcommand,然后总是调用ondestroy。该服务重新启动,并一直工作良好,直到ondestroy杀死该党。我不明白为什么在这个场景中调用ondestroy。
在所有情况下,总是在service.oncreate之前调用application oncreate。如果应用程序和服务是从头开始重新创建的,我不理解如何重新创建绑定。似乎一切都需要由应用程序启动,才能进行绑定。我在applicationoncreate中没有任何东西可以在创建应用程序时启动服务。因此,我在oncreate中添加了启动服务的代码。这是可行的,但似乎有问题。
执行应用程序oncreate。
服务oncreate作为启动的结果执行
服务ondestroy作为启动的结果执行
服务oncreate作为应用程序oncreate的结果执行
执行serviceonstart命令,服务启动,一切都很顺利。
我对在任何情况下都能在所有操作系统上工作没有多大信心。我想确定为什么它总是执行ondestroy。使用start\u redeliver\u intent似乎是重新建立绑定的正确实现。ondestroy每次都会执行,即使运行并连接到面板。
应用程序详细信息和架构
该应用程序是家庭报警系统的虚拟键盘。前台服务已绑定到应用程序。该服务示例化一个新线程,该线程是该服务的子类。主活动在需要对服务的引用时调用应用程序方法。该服务连接到报警面板,并每隔1-10秒接收来自该面板的消息。消息通过侦听器发送到应用程序和主活动。该服务保存最近消息的缓存,以提供新的侦听器,因此活动无需等待10秒即可呈现ui。该服务为报警面板事件提供声音通知。我使用前台服务是因为用户希望实时状态和快速响应。在警报响起之前,他们需要从应用程序中听到进入的声音通知。该服务使用大约36mb的内存。我用profiler来监测能量使用情况,而这些条只占光照的15%左右。它不是资源Pig。
myapplication.java
public class MyApplication extends Application {
public static final String packageName = "com.mydomain.myappname";
public static final String CHANNEL_ID = "MyService";
public static final String ACTION_STOP_FOREGROUND_SERVICE = "ACTION_STOP_FOREGROUND_SERVICE";
MyService myService;
private boolean isServiceBound = false;
private boolean Connect = false;
public void onCreate() {
super.onCreate();
logd( "Application onCreate()");
// Added this to troubleshoot
if (Util.getBoolPreference(this, PreferencesActivity.AUTOCONNECT) && !isConnect())
connect();
}
public void startService() {
createNotificationChannel();
Intent serviceIntent = new Intent(this, MyService.class);
bindService(serviceIntent, myServiceConnection, BIND_AUTO_CREATE)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
startForegroundService(serviceIntent);
else
ContextCompat.startForegroundService(this, serviceIntent);
}
private final ServiceConnection myServiceConnection = new ServiceConnection() {
public void onServiceConnect(ComponentName componentName, IBinder iBinder) {
MyServiceBinder binder = (MyServiceBinder) iBinder;
myService = binder.getService();
isServiceBound = true;
}
public void onServiceDisconnected(ComponentName className) {
isServiceBound = false;
myService = null;
}
public void onBindingDied(ComponentName className){
try {
if (isServiceBound)
unbindService(myServiceConnection);
isServiceBound = false;
myService = null;
startService();
}
catch (Throwable t){
t.printStackTrace()
}
}
};
public void stopService() {
if (isServiceBound)
unbindService(myServiceConnection);
isServiceBound = false;
myService = null;
Intent serviceIntent = new Intent(this, MyService.class);
serviceIntent.setAction(ACTION_STOP_FOREGROUND_SERVICE);
getApplicationContext().stopService(serviceIntent);
}
public void connect() {
setConnect(true);
if (myService == null) {
startService();
}
}
public void disconnect() {
setConnect(false);
if (myService != null) {
try {
myService.disconnect();
} catch (Throwable t) {
t.printStackTrace();
}
}
stopService();
deleteNotificationChannel();
}
public void resetConnection() {
setSettingsUpdated(false);
if (myService != null) {
disconnect();
try {
connect();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
private void createNotificationChannel() {
NotificationChannelCompat.Builder notification = new NotificationChannelCompat.Builder(CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_DEFAULT);
notification.setName(getString(R.string.service_name));
NotificationChannelCompat serviceChannel = notification.build();
NotificationManagerCompat manager = NotificationManagerCompat.from(this);
manager.createNotificationChannel(serviceChannel);
}
private void deleteNotificationChannel() {
NotificationManagerCompat manager = NotificationManagerCompat.from(this);
manager.deleteNotificationChannel(CHANNEL_ID);
}
public boolean isConnect() {
if (myService != null) {
return myService.isConnect();
} else
return false;
}
public MyService getService() {
return myService;
}
}
myservice.java
public class MyService extends Service {
private boolean connected = false;
private int notificationID;
private String currentNotificationContentText = "";
public MyService.MySession mySession;
public MyService() {
}
public boolean isConnected() {
return connected;
}
public void setConnected(boolean connected) {
this.connected = connected;
}
@Override
public void onCreate() {
super.onCreate();
notificationID = (int) System.currentTimeMillis() % 10000;
logd( "MyService onCreate()");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(mySession != null && isConnected())
logd( "MyService onStartCommand() use existing session");
else {
logd( "MyService onStartCommand() start new session");
try {
startForeground(notificationID, getNotification(getString(R.string.notconnected), false));
connect();
} catch (Throwable t) {
SendLog.reportHandledException(this, t);
}
}
return START_STICKY;
}
private final IBinder tpiBinder = new MyServiceBinder();
public class MyServiceBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
logd( "MyService onBind()");
return tpiBinder;
}
@Override
public boolean onUnbind(Intent intent) {
// never called
logd( "MyService onUnbind()");
return true;
}
@Override
public void onRebind(Intent intent) {
// never called
logd( "MyService onRebind()");
}
@Override
public void onDestroy() {
super.onDestroy();
logd( "MyService onDestroy()");
if (mySession != null)
mySession.close();
}
public void connect() {
logd( "MyService connect()");
try {
Thread tpiThread = new Thread(mySession = new MySession());
tpiThread.setName(getString(R.string.service_name));
tpiThread.start();
} catch (Throwable t) {
t.printStackTrace();
SendLog.reportHandledException(this, t);
}
}
public void disconnect() {
logd("MyService disconnect()");
if (mySession != null)
mySession.close();
}
public class MySession implements Runnable {
private boolean run = true;
public MySession() {
}
public void run() {
while (run) {
// Do work here
}
}
public void close() {
run = false;
}
}
private void updateNotificationContent(String contentText) {
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(notificationID, getNotification(contentText, true));
}
private Notification getNotification(String contentText, Boolean silent) {
currentNotificationContentText = contentText;
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
return new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(getString(R.string.service_name))
.setContentText(contentText)
.setSilent(silent)
.setSmallIcon(R.drawable.ic_launcher)
.setContentIntent(pendingIntent)
.build();
}
}
androidmanifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mydomain.myappname"
android:versionCode="1"
android:versionName="1.0">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:name=".application.MyApplication"
android:allowBackup="true"
android:allowClearUserData="true"
android:description="@string/app_description"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:logo="@drawable/ic_launcher"
android:supportsRtl="true"
android:theme="@style/AppBaseTheme">
<service android:name=".api.MyService"
android:stopWithTask="false"
android:foregroundServiceType="connectedDevice"
/>
<service
android:name=".util.MyFirebaseMessagingService"
android:stopWithTask="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@mipmap/ic_launcher" />
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
dumpsys
ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)
All known processes:
*APP* UID 10297 ProcessRecord{c903dea 3880:com.mydomain.myappname/u0a297}
user #0 uid=10297 gids={3003, 50297, 20297, 9997}
mRequiredAbi=armeabi-v7a instructionSet=null
class=com.mydomain.myappname.application.MyApplication
dir=/data/app/~~FJ8S0z499n-wG8dvxHKE3w==/com.mydomain.myappname-mS4YxULunDs7DmM1t2Cyyw==/base.apk publicDir=/data/app/~~FJ8S0z499n-wG8dvxHKE3w==/com.mydomain.myappname-mS4YxULunDs7DmM1t2Cyyw==/base.apk data=/data/user/0/com.mydomain.myappname
packageList={com.mydomain.myappname}
compat={240dpi always-compat}
thread=android.app.IApplicationThread$Stub$Proxy@505555c
pid=3880 starting=false createdTime=-3d21h20m46s510ms
lastActivityTime=-1s106ms lastPssTime=-36s216ms pssStatType=0 nextPssTime=+23s702ms
lastPss=79MB lastSwapPss=392KB lastCachedPss=0.00 lastCachedSwapPss=0.00 lastRss=135MB
procStateMemTracker: best=1 (1=1 1.5x)
adjSeq=1337690 lruSeq=366717
oom adj: max=1001 curRaw=0 setRaw=0 cur=0 set=0
lastCompactTime=0 lastCompactAction=0
mCurSchedGroup=3 setSchedGroup=3 systemNoUi=false trimMemoryLevel=0
curProcState=2 mRepProcState=2 pssProcState=2 setProcState=2 lastStateTime=-1m0s346ms
curCapability=LCM setCapability=LCM
hasShownUi=true pendingUiClean=true hasAboveClient=false treatLikeActivity=false
cached=false empty=false
mHasForegroundServices=true forcingToImportant=null
reportedInteraction=true time=-1m0s347ms
hasClientActivities=false foregroundActivities=true (rep=true)
startSeq=26048
mountMode=DEFAULT
lastRequestedGc=-1m0s378ms lastLowMemory=-1m0s378ms reportLowMemory=false
isMlLaunch=false
isMLException=false
isSDException=false
isSDListout=false
isSDMaxAdj=false
Activities:
- ActivityRecord{2bdbb71 u0 com.mydomain.myappname/.MainActivity t3271}
Recent Tasks:
- Task{7a19dad #3271 visible=false type=standard mode=fullscreen translucent=true A=10297:com.mydomain.myappname U=0 StackId=3271 sz=1}
Configuration={1.1 ?mcc?mnc [en_US] ldltr sw800dp w1280dp h728dp 240dpi xlrg land finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1920, 1200) mAppBounds=Rect(0, 0 - 1920, 1128) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_90} s.7371 bts=0 ff=0 bf=0 themeSeq=0}
OverrideConfiguration={1.1 ?mcc?mnc [en_US] ldltr sw800dp w1280dp h728dp 240dpi xlrg land finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1920, 1200) mAppBounds=Rect(0, 0 - 1920, 1128) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=standard mAlwaysOnTop=undefined mRotation=ROTATION_90} s.1 bts=0 ff=0 bf=0 themeSeq=0}
mLastReportedConfiguration={1.1 ?mcc?mnc [en_US] ldltr sw800dp w1280dp h728dp 240dpi xlrg land finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1920, 1200) mAppBounds=Rect(0, 0 - 1920, 1128) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_90} s.7371 bts=0 ff=0 bf=0 themeSeq=0}
Services:
- ServiceRecord{4b2405d u0 com.mydomain.myappname/.util.MyFirebaseMessagingService}
- ServiceRecord{8c56fda u0 com.mydomain.myappname/.api.MyService}
Connections:
- ConnectionRecord{93e585 u0 CR com.mydomain.myappname/.api.MyService:@d9f4afc}
- ConnectionRecord{1156a34 u0 CR IMP com.mydomain.myappname/.util.MyFirebaseMessagingService:@9fc4907}
- ConnectionRecord{b383ff6 u0 CR WACT CAPS com.google.android.gms/.measurement.service.MeasurementBrokerService:@925b491}
Published Providers:
- com.google.firebase.provider.FirebaseInitProvider
-> ContentProviderRecord{46f9065 u0 com.mydomain.myappname/com.google.firebase.provider.FirebaseInitProvider}
Connected Providers:
- f84cd3e/com.android.providers.settings/.SettingsProvider->3880:com.mydomain.myappname/u0a297 s1/1 u0/0 +59s807ms
Receivers:
- ReceiverList{3549474 3880 com.mydomain.myappname/10297/u0 remote:f0b447}
- ReceiverList{c79fe0c 3880 com.mydomain.myappname/10297/u0 remote:379e53f}
Process OOM control (56 total, non-act at 9, non-svc at 9):
Proc #41: fg T/ /CRE --- t: 0 0:com.mydomain.myappname/u0a236 (cch-rec)
oom: max=1001 curRaw=1001 setRaw=0 cur=200 set=0
state: cur=CRE set=TOP lastPss=0.00 lastSwapPss=0.00 lastCachedPss=0.00
cached=true empty=true hasAboveClient=false
Proc # 0: fg T/A/TOP LCM t: 0 3880:com.mydomain.myappname/u0a297 (top-activity)
oom: max=1001 curRaw=0 setRaw=0 cur=0 set=0
state: cur=TOP set=TOP lastPss=79MB lastSwapPss=392KB lastCachedPss=0.00
cached=false empty=false hasAboveClient=false
Proc #42: fg +50 F/ /FGS --- t: 0 0:com.mydomain.myappname/u0a236 (fg-service-act)
oom: max=1001 curRaw=1001 setRaw=50 cur=50 set=50
state: cur=FGS set=FGS lastPss=57MB lastSwapPss=49MB lastCachedPss=0.00
cached=false empty=true hasAboveClient=false
UID states:
UID u0a297: UidRecord{6d51728 u0a297 TOP fgServices change:active|uncached procs:1 seq(0,0,0)}
curProcState=2 curCapability=LCM
proc=ProcessRecord{c903dea 3880:com.mydomain.myappname/u0a297}
Raw LRU list (dumpsys activity lru):
Activities:
#55: fg TOP LCM 3880:com.mydomain.myappname/u0a297 act:activities|recents
Other:
#14: fg CRE --- 0:com.mydomain.myappname/u0a236
#13: fg +50 FGS --- 0:com.mydomain.myappname/u0a236
Process LRU list (sorted by oom_adj, 56 total, non-act at 9, non-svc at 9):
Proc #41: fg T/ /CRE --- t: 0 0:com.mydomain.myappname/u0a236 (cch-rec)
Proc # 0: fg T/A/TOP LCM t: 0 3880:com.mydomain.myappname/u0a297 (top-activity)
Proc #42: fg +50 F/ /FGS --- t: 0 0:com.mydomain.myappname/u0a236 (fg-service-act)
PID mappings:
PID #3880: ProcessRecord{c903dea 3880:com.mydomain.myappname/u0a297}
Foreground Processes:
PID #5976: ImportanceToken { 386cef7 MTP:setProcessImportant() 5976 android.os.BinderProxy@d7f9164 }
PID #16480: ImportanceToken { 9fe0aee setProcessImportant() 16480 android.os.BinderProxy@a935b8f }
PID #24650: ImportanceToken { 9406b48 ThemeService 24650 android.os.BinderProxy@2cdcde1 }
Component Call Count: (Since 2021-07-24 03:35:32)
[ packageName, activity, broadcast, cprovider, service]
com.
mydomain.myappname 33 32 0 63
暂无答案!
目前还没有任何答案,快来回答吧!