BroadcastReceiver und BatteryManager

znieh99

znieh99

Fortgeschrittenes Mitglied
12
Hallo Forum,
ich möchte zum Ermitteln des Batterie-Ladestatus den BroadcastReceiver einsetzen. Er soll mir melden wann der Ladevorgang beginnt bzw. endet. Dazu habe ich ihn in eine eigene Klasse ausgelagert, welche mittels Handler diese Ereignisse an die Main melden soll.
Mit den Emulatoren kann ich das nicht testen, da der Status immer 2 (AC Charge) ist und daher keine Änderung auftritt die den Receiver aufruft.
Lass ich die App auf meinen Handy laufen und löse oder verbinde die Lade-Verbindung bekomme ich am Handy die Meldung: "Leider wurde das Programm BatteryManager beendet."
Entferne ich den Handler-Teil (wie im Code) bekomme ich kein Meldung und die App macht auch den Button-gesteuerten Update nicht mehr.
Ich hoffe es kann mir jemand helfen!

Hier die Code-Segmente:


MainActivity:
Code:
package com.app.heinz.batterymanager;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    IntentFilter ifilter;
    Intent batteryStatus;

    Context mContext;
    private Handler mHandler;

    TextView t1;
    TextView t2;
    TextView t3;
    TextView t4;
    TextView t5;
    TextView t6;
    TextView t7;
    TextView t8;

    PowerConnectionReceiver r;
    CheckBattery checkB;


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

        t1 = (TextView) findViewById(R.id.textview_1);
        t2 = (TextView) findViewById(R.id.textview_2);
        t3 = (TextView) findViewById(R.id.textview_3);
        t4 = (TextView) findViewById(R.id.textview_4);
        t5 = (TextView) findViewById(R.id.textview_5);
        t6 = (TextView) findViewById(R.id.textview_6);
        t7 = (TextView) findViewById(R.id.textview_7);
        t8 = (TextView) findViewById(R.id.textview_8);

        // Hier wird der Handler erstellt und die Message
        // empfangen
        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                System.out.println("MSG von CheckBattery: " + msg.what);
                checkB.check();
                viewData();
                super.handleMessage(msg);
            }
        };            //end mHandler ---------------------

        mContext = getApplicationContext();

        r = new PowerConnectionReceiver(mHandler);
        checkB = new CheckBattery(mContext);
    }

    /**
     * Button Start Check gedrückt
     * @param v
     */
    public void onStartCheck(View v) {
        checkB.check();
        viewData();
    }

    /**
     * Anzeige der Batterie-Daten
     */
    private void viewData() {
        t1.setText("Status: " + checkB.getStatus());
        t2.setText("Charging: " + checkB.getCharging());
        t3.setText("ChargePlug: " + checkB.getChargePlug());
        t4.setText("USB Charge: " + checkB.getUsbCharge());
        t5.setText("AC Charge: " + checkB.getAcCharge());
        t6.setText("Level: " + checkB.getLevel());
        t7.setText("Scale: " + checkB.getScale());
        t8.setText("BatteryPct: " + checkB.getBatteryPct());

    }
 }

PowerConnectionReceiver:
Code:
package com.app.heinz.batterymanager;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.Message;

public class PowerConnectionReceiver extends BroadcastReceiver {
    Handler mHandler;

    public PowerConnectionReceiver() {}
    public PowerConnectionReceiver(Handler h) {

        mHandler = h;
    }
    @Override
    public void onReceive(Context context, Intent intent) {
        int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
        boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                status == BatteryManager.BATTERY_STATUS_FULL;

                // Meldung an Main dass Ladestatus geändert
//        Message msg = Message.obtain();
//        msg.what = 100;
//    //    System.out.println("Flag 1: " + new Date());
//        mHandler.sendMessage(msg);


    }
}


CheckBattery:

Code:
package com.app.heinz.batterymanager;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.Message;

import java.util.Date;


public class CheckBattery  {
    IntentFilter ifilter;
    Intent batteryStatus;
    Context context;
    private Handler mHandler;

    private int status;
    private boolean isCharging;
    private int chargePlug;
    private boolean usbCharge;
    private boolean acCharge;
    private int level;
    private int scale;
    private float batteryPct;


    public CheckBattery(Context c) {
        context = c;
        ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        batteryStatus = context.registerReceiver(null, ifilter);

    //    mHandler = h;
    }

    /**
     * Wird vom System aufgerufen wenn sich der Lade-Status ändert
     * @param context
     * @param intent
     */
//    @Override
//    public void onReceive(Context context, Intent intent) {
//        status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
//        isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
//                status == BatteryManager.BATTERY_STATUS_FULL;
//
//        // Meldung an Main dass Ladestatus geändert
//        Message msg = Message.obtain();
//        msg.what = 100;
//        System.out.println("Flag 1: " + new Date());
//        mHandler.sendMessage(msg);
//
//
//    }

    /**
     * Aktualisiert die Daten des Batteriestatus
     */
    public void check() {
        // Are we charging / charged?
        status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
        isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                status == BatteryManager.BATTERY_STATUS_FULL;

        // How are we charging?
        chargePlug = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
        usbCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
        acCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_AC;

        level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
        scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);

        batteryPct = level / (float)scale;
    }


    // Getter
    public int getStatus() { return status; }
    public boolean getCharging() { return isCharging; }
    public int getChargePlug() { return chargePlug; }
    public boolean getUsbCharge() { return usbCharge; }
    public boolean getAcCharge() { return acCharge; }
    public int getLevel() { return level; }
    public int getScale() { return scale; }
    public float getBatteryPct() { return batteryPct;
    }
}
 
Warum registrierst du in CheckBattery einen null-Receiver? Das kann nicht laufen.
Falls du den Receiver im Manifest deklarierst, statt zur Laufzeit wird der von Android instanziiert, dann wird der default Constructor gecallt und damit ist dein Handler im Receiver null. -> NullPointerException
 
Hallo deek,
danke für die rasche Antwort.
ja in CheckBattery gehört gar kein Receiver (ist aus alter Version, aber er wird nicht erstellt?). Der Receiver wird in PowerConnectionReceiver benötigt und ist im
Manifest wie folgt deklariert.
Manifest:
Code:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.app.heinz.batterymanager">

    <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">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name=".PowerConnectionReceiver">
            <intent-filter>
                <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
                <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
            </intent-filter>
        </receiver>
    </application>

</manifest>
 
Ja, wie gesagt, Receiver, die im Manifest deklariert werden, werden vom System instanziiert. D.h. dein Constructor mit dem Handler wird ignoriert. Damit ist der Handler nicht gesetzt und somit null,
Du musst einen anderen Weg finden mit deiner Activity zu kommunizieren.
Ich bin Fan von EventBus, (Square Otto oder Greenrobot EventBus) aber in Zeiten von rxJava tun das einige als Bad Practice ab. (von rxJava bin ich kein Fan)
 
  • Danke
Reaktionen: znieh99
Ok, nicht gut. Ich schau mir mal an was EventBus ist,
lg heinz
[doublepost=1531315152,1531311658][/doublepost]Ich habe eine einfache Lösung gefunden.
Der Handler in PowerConnectionReceiver wird static, damit setzt mein Aufruf des Konstruktors den Handler und er gilt auch für die weiteren Aufrufe des Receiver.
lg heinz
 
Einfach ist nicht immer gut... Sorry das so sagen zu müssen.
Einfach etwas static setzen ohne die Konsequenzen zu kennen (davon gehe ich aus) macht am Ende nur Ärger. Hier insbesondere. Wenn deine Applikation mal gekillt wird und dann der Receiver getriggert passiert die gleiche Chose nochmal, weil deine Activity noch nicht dazu kam das statische Feld zu setzen.
Noch dazu ist einen Constructor aufzurufen nur um ein statisches Feld zu setzen so ziemlich das hässlichste was man in dem Zusammenhang machen kann...


Why are static variables considered evil?
 
deek schrieb:
Wenn deine Applikation mal gekillt wird und dann der Receiver getriggert passiert die gleiche Chose nochmal, weil deine Activity noch nicht dazu kam das statische Feld zu setzen.
Nun, ich setze den Handler in onCreate und denke das vorher nichts getriggert werden kann ?? Oder ??

deek schrieb:
Noch dazu ist einen Constructor aufzurufen nur um ein statisches Feld zu setzen so ziemlich das hässlichste was man in dem Zusammenhang machen kann...
Kritik ist etwas gutes wenn man daraus etwas lernen kann, deine Kritik ist nur abwertend,
lg heinz
 
znieh99 schrieb:
Nun, ich setze den Handler in onCreate und denke das vorher nichts getriggert werden kann ?? Oder ??

Doch. Wenn Android deine App im Hintergrund startet um einen Receiver zu triggern wird keine Activity geladen.

Kritik ist etwas gutes wenn man daraus etwas lernen kann, deine Kritik ist nur abwertend,
lg heinz

Sollte nicht abwertend sein. Ich bin nur der Meinung man sollte gewisse Sachen klar sagen. Wenn ich dir gesagt hätte "ist vielleicht nicht ganz so schön, aber für den Anfang wenn du unbedingt willst lass es so" denkst du dass es schon okay ist. Ist es nicht.
Solche Fehler machen auf lange Sicht nur Probleme auch wenn es auf den ersten Blick funktioniert. Und später ist man keine Ahnung mehr warum etwas nicht geht.

Wenn du die Daten nur in der Activity brauchst dann hol den Receiver aus dem Manifest raus und registriert ihn korrekt mit registerBroadcastReceiver. Dann kannst du deinen constructor so verwenden. Brauchst du dir Informationen auch im Hintergrund dann musst dir was anderes als diese handler Variante überlegen.
 
  • Danke
Reaktionen: Kardroid
@jogimuc
Danke für das Beispiel

@deek
Es ist mir nicht um die Klarheit deiner Aussage gegangen (damit hast du vollkommen Recht) sondern um die fehlende Alternative.
Ich habe die App jetzt - dank eurer Hints - so verändert, dass sie jetzt für mich auch eleganter und hoffentlich sicherer ist.

Code:
package com.app.heinz.batterymanager;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

/**
 * Diese Beispiel zeigt wie man den BatteryManager verwenden kann.
 * Der Abruf der Daten kann individuell (z.B. zeitgesteuert) und/oder
 * ereignisgesteuert (hier Ladeaktionen) erfolgen.
 */
public class MainActivity extends AppCompatActivity {

    private Context mContext;           //wird in CheckBattery benötigt

    private TextView t1;
    private TextView t2;
    private TextView t3;
    private TextView t4;
    private TextView t5;
    private TextView t6;
    private TextView t7;
    private TextView t8;

    // Instanz der Klasse
    private CheckBattery checkB;

    /**
     * Initialisieren beim App-Start
     * @param savedInstanceState
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        t1 = (TextView) findViewById(R.id.textview_1);
        t2 = (TextView) findViewById(R.id.textview_2);
        t3 = (TextView) findViewById(R.id.textview_3);
        t4 = (TextView) findViewById(R.id.textview_4);
        t5 = (TextView) findViewById(R.id.textview_5);
        t6 = (TextView) findViewById(R.id.textview_6);
        t7 = (TextView) findViewById(R.id.textview_7);
        t8 = (TextView) findViewById(R.id.textview_8);

        mContext = getApplicationContext();

        // Registriert die Aktionen Laden beginnt und Laden beendet
        registerReceiver(this.mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_POWER_CONNECTED));
        registerReceiver(this.mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_POWER_DISCONNECTED));

        checkB = new CheckBattery(mContext);
    }

    /**
     * Button Start Check gedrückt
     * @param v
     */
    public void onStartCheck(View v) {
        checkB.check();
        viewData();
    }

    /**
     * Anzeige der Batterie-Daten
     */
    private void viewData() {

        t1.setText("Status: " + checkB.getStatus());
        t2.setText("Charging: " + checkB.getCharging());
        t3.setText("ChargePlug: " + checkB.getChargePlug());
        t4.setText("USB Charge: " + checkB.getUsbCharge());
        t5.setText("AC Charge: " + checkB.getAcCharge());
        t6.setText("Level: " + checkB.getLevel());
        t7.setText("Scale: " + checkB.getScale());
        t8.setText("BatteryPct: " + checkB.getBatteryPct());
    }

    /**
     * Hier werden die Battery-Ereignisse Laden und Laden beenden aufgefangen
     */
    private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context c, Intent intent) {
            checkB.check();
            viewData();
        }
    };
 }          //end class MainActivity -------------------------
 

Ähnliche Themen

M
  • MikelKatzengreis
Antworten
5
Aufrufe
118
swa00
swa00
Laser5001
Antworten
3
Aufrufe
647
swa00
swa00
W
Antworten
2
Aufrufe
741
rene3006
R
Zurück
Oben Unten