The secret of why the page in the application does not respond when startActivity is enabled in the background of Service
-
- question
- analyze
- Solution
Question
When I start a service in the A application and open a thread in the service, when we manually slide to kill the APP, the service is still alive. We want to restart the APP application. We may try the following code, and sometimes it can be pulled up, Sometimes nothing happens, but judging from the logs, the service is running normally and the heartbeat logs are printed normally.
public class StepService extends Service { private static final String TAG = "StepService"; public static boolean isRemoveTask = false; private Handler handler = new Handler(Looper.getMainLooper()); private SvrBinder mBinder; private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e(TAG, "<Stub> StepService Connected."); } @Override public void onServiceDisconnected(ComponentName name) { // Toast.makeText(RemoteService.this,"Link is broken, restart LocalService",Toast.LENGTH_LONG).show(); Log.e(TAG, "<Stub> StepService Disconnected."); // startService(new Intent(StepService.this, GuardService.class)); // bindService(new Intent(StepService.this, GuardService.class), this, Context.BIND_IMPORTANT); Log.e(TAG, "<Stub> StepService Disconnected end."); } }; @Override public void onCreate() { super.onCreate(); Log.e(TAG, "<Stub> StepService onCreate."); String CHANNEL_ONE_ID = "StepServiceId"; String CHANNEL_ONE_NAME = "StepServiceChannel"; String CHANNEL_ID = "StepServiceChannelId"; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel(CHANNEL_ONE_ID, CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_LOW); NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); if (manager == null) return; manager.createNotificationChannel(channel); Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID) .setAutoCancel(true) .setCategory(Notification.CATEGORY_SERVICE) .setOngoing(true) .setPriority(NotificationManager.IMPORTANCE_LOW) .build(); } isHeartBeatThread = true; if (heartBeatThread == null || !heartBeatThread.isAlive()){ heartBeatThread = new HeartBeatThread(); heartBeatThread.start(); } // startService(new Intent(StepService.this, GuardService.class)); // bindService(new Intent(StepService.this, GuardService.class),connection,Context.BIND_IMPORTANT); Log.e(TAG, "<Stub> StepService isRemoveTask:" + isRemoveTask); if (isRemoveTask){ /* Intent intent = new Intent(getBaseContext(), MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getApplicationContext().startActivity(intent);*/ } } @Override public int onStartCommand(Intent intent, int flags, int startId) { // Toast.makeText(this,"RemoteService Start",Toast.LENGTH_LONG).show(); Log.e(TAG, "<Stub> StepService onStartCommand."); return START_STICKY; } @Override public IBinder onBind(Intent intent) { mBinder = new SvrBinder(); return mBinder; } private HeartBeatThread heartBeatThread; private boolean isHeartBeatThread; class HeartBeatThread extends Thread{ @Override public void run() { super.run(); while (isHeartBeatThread){ try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } Log.e(TAG, "HeartBeatThread on on on"); } } } /** * Class for client binders. Since we know that this service always runs in the same process as its client, * So we don't need to deal with IPC. */ public class SvrBinder extends IStepServiceAidlInterface.Stub { @Override public void keepAlive() throws RemoteException { Log.e(TAG, "<Stub> StepService keepAlive."); } } @Override public void onDestroy() { super.onDestroy(); isHeartBeatThread = false; unbindService(connection); Log.e(TAG, "<Stub> StepService onDestroy."); } @Override public boolean onUnbind(Intent intent) { return super.onUnbind(intent); } @Override public void onTaskRemoved(Intent rootIntent) { super.onTaskRemoved(rootIntent); isRemoveTask = true; Log.e(TAG, "<Stub> StepService onTaskRemoved."); /* Intent intent = new Intent(getBaseContext(), MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getApplicationContext().startActivity(intent);*/ /* Intent intent = getBaseContext().getPackageManager() .getLaunchIntentForPackage(getBaseContext().getPackageName()); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent restartIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT); AlarmManager mgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE); mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent); // Restart the application after 1 second*/ Intent k = getBaseContext().getPackageManager() .getLaunchIntentForPackage(getBaseContext().getPackageName()); k.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); k.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(k); // stopForeground(true); // unbindService(connection); // stopSelf(); }
The code in the service is simple.
Analysis
Later, I found out that the reason was because Android 10 and later did not allow startActivity in the background. As shown below
Solution
Add permissions
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
This permission requires the user to actively enable it.
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { if (!Settings.canDrawOverlays(this)) { startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()))); } } else { Toast.makeText(getApplicationContext(), "API < " + android.os.Build.VERSION_CODES.M, Toast.LENGTH_SHORT).show(); }
Try again. After killing the program, the APP main page starts up immediately, which is a perfect solution.