java - SCREEN_ON 和 SCREEN_OFF 的 BroadcastReceiver,即使在退出应用程序后也是如此

标签 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>

最佳答案

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

那么服务代码是这样的(记得在Destory上注销receiver):

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);
}

并从主要 Activity 中调用它:

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));
        }
    }
}

关于java - SCREEN_ON 和 SCREEN_OFF 的 BroadcastReceiver,即使在退出应用程序后也是如此,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51324659/

相关文章:

java - Wildfly 10.1.0.FINAL 上的内存泄漏 (java.lang.ref.Finalizer/ActiveMQConnection)

android - 如何为 React Native 定义全局 gradle 路径

java - Android 分水岭 OpenCV

android - 如何检查android中的同步设置

android - IntentService <-> Activity 通信

java - Eclipse PDE : Mimicking IResourceChangeEvents for IJavaProject creation between PDE and developer's workspace?

java - 调用 Java 8 功能接口(interface)的最简洁的 Scala 方法是什么?

java - 从父类(super class)访问私有(private)变量 (JAVA)

android - 重启接收器在小米手机中不起作用

android - 如何让我的广播接收器保持活力