1. Mitglieder surfen ohne Werbung auf Android-Hilfe.de! ✔ Jetzt kostenlos Mitglied in unserer Community werden.
  1. znieh99, 11.07.2018 #1
    znieh99

    znieh99 Threadstarter Android-Hilfe.de Mitglied

    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;
        }
    }
     
  2. deek, 11.07.2018 #2
    deek

    deek Android-Experte

    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
     
  3. znieh99, 11.07.2018 #3
    znieh99

    znieh99 Threadstarter Android-Hilfe.de Mitglied

    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>
     
  4. deek, 11.07.2018 #4
    deek

    deek Android-Experte

    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)
     
    znieh99 bedankt sich.
  5. znieh99, 11.07.2018 #5
    znieh99

    znieh99 Threadstarter Android-Hilfe.de Mitglied

    Ok, nicht gut. Ich schau mir mal an was EventBus ist,
    lg heinz
    -- Dieser Beitrag wurde automatisch mit dem folgenden Beitrag zusammengeführt --
    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
     
  6. deek, 11.07.2018 #6
    deek

    deek Android-Experte

    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?
     
  7. znieh99, 11.07.2018 #7
    znieh99

    znieh99 Threadstarter Android-Hilfe.de Mitglied

    Nun, ich setze den Handler in onCreate und denke das vorher nichts getriggert werden kann ?? Oder ??

    Kritik ist etwas gutes wenn man daraus etwas lernen kann, deine Kritik ist nur abwertend,
    lg heinz
     
  8. jogimuc, 11.07.2018 #8
    jogimuc

    jogimuc Android-Hilfe.de Mitglied

    Zuletzt bearbeitet: 11.07.2018
  9. deek, 12.07.2018 #9
    deek

    deek Android-Experte

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

    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.
     
    Kardroid bedankt sich.
  10. znieh99, 12.07.2018 #10
    znieh99

    znieh99 Threadstarter Android-Hilfe.de Mitglied

    @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 -------------------------
     
Du betrachtest das Thema "BroadcastReceiver und BatteryManager" im Forum "Android App Entwicklung",
  1. Android-Hilfe.de verwendet Cookies um Inhalte zu personalisieren und dir den bestmöglichen Service zu gewährleisten. Wenn du auf der Seite weitersurfst stimmst du der Cookie-Nutzung zu.  Ich stimme zu.