如何收听已连接电源的Android> 8

时间:2019-06-11 08:31:22

标签: android kotlin

我有一个简单的Android Kotlin应用程序,它的一部分工作是在接通和断开电源时监听并执行操作

这是我的旧代码,在定位Oreo以下的设备时效果很好。

AndroidManifest.xml

<receiver android:name=".ChargingUtil$PlugInReceiver">
    <intent-filter>
        <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
        <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
    </intent-filter>
</receiver>

ChargingUtil.kt

class ChargingUtil (context: Context){

    /*... Some other charging-related functions here ... */

    class PlugInReceiver : BroadcastReceiver() {

        override fun onReceive(context: Context, intent: Intent) {
            Log.d("thisistest", "Power was changed")
            // Here I do some logic with `intent.action`
        }
    }
}

在更高的Android版本中,对实现广播的方式进行了一些更改:https://developer.android.com/guide/components/broadcasts

到目前为止,我已经尝试过:

  • 我尝试遵循this documentation,但是它们的实现实际上与我当前的代码相同(仅适用于Android 8以下版本)。
  • 我还发现this question,但唯一的解决方法是定期检查电源是否接通。我认为这对我而言并不可行,因为我的应用需要立即知道何时更改充电状态。

所以我的问题是:

电源连接/断开时如何调用功能? 考虑到运行Android 8或更高版本的系统对清单施加的其他限制,声明接收者。

注意:我正在使用Kotlin,并希望避免使用不赞成使用的软件包


在Android方面,我有点菜鸟,如果实际上有一个我刚错过的明显解决方案,对不起。在此先感谢您的帮助。

3 个答案:

答案 0 :(得分:4)

您提到的问题已经有了答案。

启动后,使用ACTION_BOOT_COMPLETED启动前台服务。此服务应注册ACTION_POWER_CONNECTED广播。您也可以在单独的过程中启动此服务。一旦电源接通/断开,您将收到服务类别中的广播,您可以在其中运行所需的方法。

public class MyService extends Service {
    private String TAG = this.getClass().getSimpleName();

    @Override
    public void onCreate() {
        Log.d(TAG, "Inside onCreate() API");
        if (Build.VERSION.SDK_INT >= 26) {
            NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
            mBuilder.setSmallIcon(R.drawable.ic_launcher);
            mBuilder.setContentTitle("Notification Alert, Click Me!");
            mBuilder.setContentText("Hi, This is Android Notification Detail!");
            NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

            // notificationID allows you to update the notification later on.
            mNotificationManager.notify(100, mBuilder.build());
            startForeground(100, mBuilder.mNotification);

            IntentFilter filter1=new IntentFilter();
            filter1.addAction(Intent.ACTION_POWER_CONNECTED);
            registerReceiver(myBroadcastReceiver,filter1);
        }
    }


    @Override
    public int onStartCommand(Intent resultIntent, int resultCode, int startId) {
        Log.d(TAG, "inside onStartCommand() API");
        return startId;
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "inside onDestroy() API");
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

       BroadcastReceiver myBroadcastReceiver =new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                // call your method
            }
        };
}

您也可以将JobScheduler设置为setRequiresCharging为真。更改电源状态后,这将开始调用JobScheduler的作业。

ComponentName serviceComponent = new ComponentName(context, TestJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(0, serviceComponent);
builder.setMinimumLatency(1 * 1000); // wait at least
builder.setOverrideDeadline(3 * 1000); // maximum delay
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED); 
builder.setRequiresDeviceIdle(true); 
builder.setRequiresCharging(true);
JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
jobScheduler.schedule(builder.build());

答案 1 :(得分:0)

从Android 8.0(API级别26和更高版本)开始,您不能使用静态接收器来接收大多数Android系统广播read here

BroadcastReceiver是静态接收器还是动态接收器,具体取决于您如何注册:

  • 要静态注册接收器,请在您的计算机中使用<receiver>元素 AndroidManifest.xml个文件。静态接收者也称为清单声明的接收者。

  • 要动态注册接收者,请使用应用程序上下文或活动上下文。的 只要注册上下文有效,接收方就接收广播,即 只要相应的应用或活动正在运行。动态接收器也称为 上下文注册的接收者。

因此,您需要动态注册接收器,转到AndroidManifest.xml并删除<receiver>标签,然后在活动时进行注册。

private MyBatteryReceiver mReceiver = new MyBatterReceiver();

然后使用IntentFilter进行强行操作:

IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
filter.addAction(Intent.ACTION_POWER_CONNECTED)

剩下的就是注册和撤消您的注册

this.registerReceiver(mReceiver, filter); // using activity context.
this.unregisterReceiver(mReceiver); // implement on onDestroy().

答案 2 :(得分:0)

感谢@Derek的回答,加上一些修改,我终于可以使用了。将工作解决方案发布到此处,以防对其他人有帮助。

PowerConnectionReciever.kt

import android.content.Intent
import android.content.BroadcastReceiver
import android.os.IBinder
import android.content.IntentFilter
import android.app.Service
import android.content.Context

class PowerConnectionService : Service() {

    private var connectionChangedReceiver: BroadcastReceiver = 
        object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            // This block gets run whenever the power connection state is changed
            when {
                intent.action == Intent.ACTION_POWER_CONNECTED ->
                    powerWasConnected()
                intent.action == Intent.ACTION_POWER_DISCONNECTED ->
                    powerWasDisconnected()
            }
        }
    }

    override fun onCreate() {
        val connectionChangedIntent = IntentFilter()
        connectionChangedIntent.addAction(Intent.ACTION_POWER_CONNECTED)
        connectionChangedIntent.addAction(Intent.ACTION_POWER_DISCONNECTED)
        registerReceiver(connectionChangedReceiver, connectionChangedIntent)
    }

    override fun onStartCommand(
        resultIntent: Intent, resultCode: Int, startId: Int): Int {
        return startId
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(connectionChangedReceiver)
    }

    override fun onBind(intent: Intent): IBinder? {
        return null
    }

    private fun powerWasConnected() {
        // Do whatever you need to do when the power is connected here
    }
    private fun powerWasDisconnected() {
        // And here, do whatever you like when the power is disconnected
    }
}

然后在我的 MainActivity.kt 文件中,添加了此函数,该函数在onCreate挂钩中调用。

private fun startPowerConnectionListener() {
        val serviceComponent = ComponentName(this, PowerConnectionService::class.java)
        val builder = JobInfo.Builder(0, serviceComponent)
        builder.setMinimumLatency((200)) // wait time
        builder.setOverrideDeadline((200)) // maximum delay
        val jobScheduler = this.getSystemService(JobScheduler::class.java)
        jobScheduler.schedule(builder.build())
    }

我唯一需要做的其他更改是在 AndroidMainifest.xml

FOREGROUND_SERVICE的权限添加为第一级项目:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

当然,还需要注册新的PowerConnectionService,这要在相关的activity节点内

<service
    android:name=".PowerConnectionService"
    android:permission="android.permission.BIND_JOB_SERVICE"
    android:exported="true">
</service>