Как слушать для подключенного питания Android> 8 - PullRequest
1 голос
/ 11 июня 2019

У меня есть простое приложение 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

Что я пробовал до сих пор:

  • Я пытался следовать этой документации , но их реализация фактически совпадает с моим текущим кодом (который работает только под Android 8).
  • Я также нашел этот вопрос , но единственным решением было периодически проверять, подключено ли питание. Я не думаю, что это жизнеспособно для меня, так как мое приложение должно мгновенно знать, когда изменяется состояние зарядки.

Итак, мой вопрос:

Как вызвать функцию, когда питание подключено / отключено? Принимая во внимание дополнительные ограничения, которые системы под управлением Android 8 или более поздней версии накладывают на заявленные манифесты получателей.

Примечание: я использую Kotlin, и хотел бы избежать использования устаревших пакетов


Я немного нуб, когда дело доходит до Android, так что извините, если есть на самом деле очевидное решение, которое я только что пропустил. Заранее благодарю за любую помощь.

Ответы [ 3 ]

4 голосов
/ 11 июня 2019

На вопрос, на который вы ответили, уже есть ответ.

Используйте 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 true.это приведет к запуску задания 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());
0 голосов
/ 12 июня 2019

Благодаря ответу @ Дерека, а также нескольким изменениям, я получил это на работу. Публикация рабочего решения здесь, на случай, если это кому-нибудь поможет.

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>
0 голосов
/ 11 июня 2019

Начиная с Android 8.0 (уровень API 26 и выше), вы не можете использовать статические приемники для приема большинства передач системы Android читать здесь ,

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().
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...