首页 > 解决方案 > 未显示应用时,Android 前台停止

问题描述

我是 android 新手,正在开发一个 Android 应用程序,该应用程序每隔几秒钟进行一次测量,并将这些测量结果链接到用户的当前位置。即使用户正在使用手机(应用程序已最小化)或屏幕锁定时,仍应收集数据。我应该注意,这个应用程序是为了在内部使用(而不是在 Google Play 商店中)并且得到用户的完全许可!

在查看 Android 文档时,我发现前台服务可能是我的解决方案。所以我按照记录的方式实施了这项服务。在对应用程序进行编程时,一切似乎都运行良好,但是当我开始制作应用程序的发布版本并测试应用程序时,我注意到了一些意外行为。这是我用于服务并从我的活动中调用服务的代码:

public class LocationService extends Service {
    private final LocationServiceBinder binder = new LocationServiceBinder();
    private final String TAG = "LocationService";
    private LocationListener mLocationListener;
    private LocationManager mLocationManager;
    private PowerManager.WakeLock wakeLock;
    private Timer timer;

    private final int LOCATION_INTERVAL = 500;
    private final int LOCATION_DISTANCE = 1;

    @Override
    public void onCreate() {
        startForeground(12345678, getNotification());
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        PowerManager pm = (PowerManager)getSystemService(POWER_SERVICE);
        wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Service:WakeLock");
        wakeLock.acquire();
        startTracking();

        super.onStartCommand(intent, flags, startId);
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        task.cancel();
        wakeLock.release();

        if (timer != null) {
            timer.cancel();
            timer.purge();
            timer.cancel();
            timer = null;
        }

        if (mLocationManager != null) {
            try {
                mLocationManager.removeUpdates(mLocationListener);
            } catch (Exception ex) {
                Log.i(TAG, "fail to remove location listeners, ignore", ex);
            }
        }

        stopForeground(true);
        stopSelf();
        super.onTaskRemoved(rootIntent);
    }
    
    private Notification getNotification() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("channel_01",
                    "My Channel", NotificationManager.IMPORTANCE_DEFAULT);

            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }

        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,
                0, intent, 0);

        return new NotificationCompat.Builder(this, "channel_01")
                .setContentTitle("APP")
                .setContentText("App is running!")
                .setContentIntent(pendingIntent).build();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }    
    
    public class LocationServiceBinder extends Binder {
        public LocationService getService() {
            return LocationService.this;
        }
    }

    private TimerTask task = new TimerTask() {
        @Override
        public void run() {
            requestLocationInformation();
        }
    };

    public void startTracking() {
            initializeLocationManager();
            mLocationListener = new LocationListener(LocationManager.GPS_PROVIDER);

            if (timer == null) {
                timer = new Timer("Measurements");
                timer.scheduleAtFixedRate(task, 1000, 5000);
            }

            try {
                mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                        LOCATION_INTERVAL, LOCATION_DISTANCE, mLocationListener);
            } catch (java.lang.SecurityException ex) {
                Log.i(TAG, "fail to request location update, ignore", ex);
            } catch (IllegalArgumentException ex) {
                Log.d(TAG, "gps provider does not exist " + ex.getMessage());
            }
        }
    }

    private class LocationListener implements android.location.LocationListener {
        private Location lastLocation = null;
        private final String TAG = "LocationListener";
        private Location mLastLocation;

        public LocationListener(String provider) {
            mLastLocation = new Location(provider);
        }
    }

    public void requestLocationUpdates() {
        try {
            mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                    LOCATION_INTERVAL, LOCATION_DISTANCE, mLocationListener);
        } catch (java.lang.SecurityException ex) {
            Log.i(TAG, "fail to request location update, ignore", ex);
        } catch (IllegalArgumentException ex) {
            Log.d(TAG, "gps provider does not exist " + ex.getMessage());
        }
    }

    private void initializeLocationManager() {
        if (mLocationManager == null) {
            mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
        }
    }

    private void requestLocationInformation() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            Location location = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);

            if (location != null && swbRunning) {
                String locInfo = "latitude:" + location.getLatitude() + " longitude:" + location.getLongitude() + " accuracy: " + location.getAccuracy() + "\n";
                Log.d(TAG, "Location --> " + locInfo);
            }
        }
    }
}
public class MainActivity extends ReactActivity {
    //permissions to be requested at runtime - needed for android 6.0+
    static String[] runtimePermissions = { Manifest.permission.INTERNET, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_PHONE_STATE, Manifest.permission.WAKE_LOCK };
    static int permissionRequestCode = 1;
    private LocationService locaService;
    

  @RequiresApi(api = Build.VERSION_CODES.M)
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (!havePermissions()) {
          requestPermissions(runtimePermissions, permissionRequestCode);
      } else {
        Intent intent = new Intent(this, LocationService.class);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);

        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
            startForegroundService(intent);
        else
            startService(intent);
      }
    }

    private ServiceConnection serviceConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            locaService = ((LocationService.LocationServiceBinder) service).getService();
        }

        public void onServiceDisconnected(ComponentName className) {
            locaService = null;
        }
    };

为了测试应用程序,我使用了三星 Galaxy A42 (android 11) 设备,这也是我们的用户使用的设备。在发布版本中,一切正常,直到应用程序被最小化或屏幕被锁定。我调查了这个问题,并根据我可以在网上找到的关于这个问题的信息,我尝试了一些不同的解决方案。我添加了一个部分唤醒锁以保持设备平稳运行,并且按照以下帖子的建议,我还在 android 清单中添加了 stopWithTask=false。我还在没有此问题的旧设备(android 8)上运行了该应用程序。

杀死应用程序后保持后台服务运行 当用户将其置于后台时,我的 Android 11 应用程序将停止运行,除非手机已连接到电源 Android 在三星设备上保持屏幕打开

如上一篇文章所述,三星以执行电池优化而闻名,这可能会影响运行前台服务的应用程序。所以我使用了https://dontkillmyapp.com/上的建议,但这并不能解决问题。由于我尝试了所有能找到的解决方案,我开始认为这可能是我问题的主要根源。我想知道是否有人遇到过类似的问题,以及是否有解决此问题的方法。

标签: androidsamsung-mobileforeground-serviceandroid-11

解决方案


推荐阅读