即使退出应用程序后,也可以针对SCREEN_ON和SCREEN_OFF使用BroadcastReceiver

时间:2018-07-13 12:01:22

标签: java android broadcastreceiver

我正在尝试制作一个通过跟踪屏幕锁定和解锁时间来监视用户电话使用情况的应用。我尝试设置一个BroadcastReceiver,当应用程序在后台运行时可以正常工作。但是当我关闭该应用程序时将无法使用。有解决方案吗?

我现在使用的代码如下:

public class MainActivity extends AppCompatActivity {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       Intent intent = new Intent(this, ScreenListenerService.class);
       startService(intent);
   }

}

ScreenListenerService类如下。

public class ScreenListenerService extends Service {

   private BroadcastReceiver mScreenStateBroadcastReceiver = new BroadcastReceiver() {

       @Override
       public void onReceive(Context context, Intent intent) {

           if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {

               // Save something to the server

           } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {

               // Save something to the server

           }

       }

   };

   @Override
   public void onCreate() {
       super.onCreate();
       IntentFilter intentFilter = new IntentFilter();
       intentFilter.addAction(Intent.ACTION_SCREEN_ON);
       intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
       registerReceiver(mScreenStateBroadcastReceiver, intentFilter);
   }

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

   @Override
   public int onStartCommand(Intent intent, int flags, int startId) {
       super.onStartCommand(intent, flags, startId);
       return START_STICKY;
   }

   @Override
   public IBinder onBind(Intent intent) {
       return null;
   }

}

我的AndroidManifest文件如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.abbinvarghese.calculu">

   <application
       android:allowBackup="true"
       android:icon="@mipmap/ic_launcher"
       android:label="@string/app_name"
       android:roundIcon="@mipmap/ic_launcher_round"
       android:supportsRtl="true"
       android:theme="@style/AppTheme">
       <service android:name=".ScreenListenerService" />
       <activity android:name=".MainActivity">
           <intent-filter>
               <action android:name="android.intent.action.MAIN" />
               <category android:name="android.intent.category.LAUNCHER" />
           </intent-filter>
       </activity>
   </application>

</manifest>

3 个答案:

答案 0 :(得分:1)

由于Background Execution Limit在Android 8.0(API级别26)上具有强制性,因此现在无法通过运行服务在后台监听 SCREEN_OFF SCREEN_ON 动作。

JobScheduler的帮助下,我找到了解决该问题的方法,该方法可以很好地在后台监听广播而无需运行任何服务。

请检查以下内容:Screen OFF/ON broadcast listener without service on Android Oreo

答案 1 :(得分:1)

要克服8.0带来的限制,您可以运行前台服务。就像服务一样,但通知会发布到前台。

然后,服务代码将如下所示(请记住在接收器上注销接收器):

BroadcastReceiver screenReceiver;

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}


@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    startRunningInForeground();
    detectingDeterminateOfServiceCall(intent.getExtras());
    registerBroadcastReceivers();
    return START_STICKY;
}

private void startRunningInForeground() {

    //if more than or equal to 26
    if (Build.VERSION.SDK_INT >= 26) {

        //if more than 26
        if(Build.VERSION.SDK_INT > 26){
            String CHANNEL_ONE_ID = "sensor.example. geyerk1.inspect.screenservice";
            String CHANNEL_ONE_NAME = "Screen service";
            NotificationChannel notificationChannel = null;
            notificationChannel = new NotificationChannel(CHANNEL_ONE_ID,
                    CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_MIN);
            notificationChannel.enableLights(true);
            notificationChannel.setLightColor(Color.RED);
            notificationChannel.setShowBadge(true);
            notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            if (manager != null) {
                manager.createNotificationChannel(notificationChannel);
            }

            Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.background_running);
            Notification notification = new Notification.Builder(getApplicationContext())
                    .setChannelId(CHANNEL_ONE_ID)
                    .setContentTitle("Recording data")
                    .setContentText("ActivityLog is logging data")
                    .setSmallIcon(R.drawable.background_running)
                    .setLargeIcon(icon)
                    .build();

            Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
            notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
            notification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0);

            startForeground(101, notification);
        }
        //if version 26
        else{
            startForeground(101, updateNotification());

        }
    }
    //if less than version 26
    else{
        Notification notification = new NotificationCompat.Builder(this)
                .setContentTitle("Activity logger")
                .setContentText("data recording on going")
                .setSmallIcon(R.drawable.background_running)
                .setOngoing(true).build();

        startForeground(101, notification);
    }
}

private Notification updateNotification() {

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

    return new NotificationCompat.Builder(this)
            .setContentTitle("Activity log")
            .setTicker("Ticker")
            .setContentText("recording of data is on going")
            .setSmallIcon(R.drawable.activity_log_icon)
            .setContentIntent(pendingIntent)
            .setOngoing(true).build();
}

private void detectingDeterminateOfServiceCall(Bundle b) {
    if(b != null){
        Log.i("screenService", "bundle not null");
        if(b.getBoolean("phone restarted")){
            storeInternally("Phone restarted");
        }
    }else{
        Log.i("screenService", " bundle equals null");
    }
    documentServiceStart();
}


private void documentServiceStart() {
    Log.i("screenService", "started running");
}


private void registerBroadcastReceivers() {
    screenReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            switch (Objects.requireNonNull(intent.getAction())){
                case Intent.ACTION_SCREEN_ON:
                    //or do something else
                    storeInternally("Screen on");
                    break;
                case Intent.ACTION_SCREEN_OFF:
                    //or do something else
                    storeInternally("Screen off");
                    break;
            }
        }
    };

    IntentFilter screenFilter = new IntentFilter();
    screenFilter.addAction(Intent.ACTION_SCREEN_ON);
    screenFilter.addAction(Intent.ACTION_SCREEN_OFF);

    registerReceiver(screenReceiver, screenFilter);
}
@Override
public void onDestroy() {
    super.onDestroy();
    unregisterReceiver(screenReceiver);
}

并从主要活动中调用它:

private void startServiceRunning() {
    if(!isMyServiceRunning(Background.class)){
        if(Build.VERSION.SDK_INT >25){
            startForegroundService(new Intent(this, Background.class));
        }else{
            startService(new Intent(this, Background.class));
        }
    }
}

答案 2 :(得分:0)

您可以直接创建一个广播接收器类,而不是为广播接收器创建新服务,即使该应用未运行,该类也将侦听系统广播。 创建一个扩展BroadcastReceiver的新类。

public class YourReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        //Do your stuff
    }
}

并将其注册在清单中。

<receiver
    android:name=".YourReceiver"
    android:enabled="true"
    android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.ACTION_SCREEN_ON" />
            <action android:name="android.intent.action. ACTION_SCREEN_OFF" />
            <category android:name="android.intent.category.DEFAUL" />
        </intent-filter>
</receiver>

了解Manifest-declared receivers here

上述解决方案无效here是原因。问题是当应用程序被终止时,您的服务将被终止,因此您的接收器实例将从内存中删除。 Here是在后台重新启动服务的小技巧。将以下代码添加到您的服务中。

@Override
public void onTaskRemoved(Intent rootIntent){
    Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
    restartServiceIntent.setPackage(getPackageName());

    PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
    AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
    alarmService.set(
    AlarmManager.ELAPSED_REALTIME,
    SystemClock.elapsedRealtime() + 1000,
    restartServicePendingIntent);

    super.onTaskRemoved(rootIntent);
 }

尽管这不是正确的方法。同样在Android 26+中,您将无法执行此操作,因此您会选择foreground servicehttps://developer.android.com/about/versions/oreo/background