Thread & SensorEventListener

  • 18 Antworten
  • Neuester Beitrag
Diskutiere Thread & SensorEventListener im Android App Entwicklung im Bereich Betriebssysteme & Apps.
ui_3k1

ui_3k1

Gesperrt
Hallo ihr Guten,

ich möchte einen Sleep-Timer in Kombination mit einem Bewegungssensor ablaufen lassen.
Es geht darum:
Man stellt am Handy eine Zeit ein, die runterläuft, gleichzeitig soll während des Herunterzählens geprüft werden, ob das Handy zu stark geschüttelt wurde.


Bei meinem S4 klappt das auch schon sehr gut, allerdings funktioniert der Code auf einem S2 wiederum nicht. Ich verstehe es nicht. :confused2:
Bzw, mir ist aufgefallen, dass es auf meinem S4 doch nicht so reibungslos läuft, wenn der Bewegungssensor aktiviert wurde, wird der Thread nicht beendet sondern läuft weiter und aktiviert sich irgendwann im Hintergrund.

Hier der Code:
Code:
public class WaitingForBomb extends Activity {

    float sensibility = 2.5f;
    boolean isOver = false;
    private SensorManager mSensorManager;
    private float mAccel; // Beschleunigung
    private float mAccelCurrent; // aktuelle Beschleunigung (in Verbindung mit
                                    // Erdanziehung)?
    private float mAccelLast; // letzte Beschleunigung (in Verbindung mit
                                // Erdanziehung)?
    TextView anzeige;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.waiting);


        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        mSensorManager.registerListener(mSensorListener,
                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_NORMAL);
        mAccel = 0.00f;
        mAccelCurrent = SensorManager.GRAVITY_EARTH;
        mAccelLast = SensorManager.GRAVITY_EARTH;
        bombTimer.start();

    }

    // Sleep-Timer
    Thread bombTimer = new Thread() {
        public void run() {
            try {
                // Intent-Übergabe des Counters
                Intent mIntent = getIntent();
                int counterValue = mIntent.getIntExtra("pushCounter", 0);
                Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
                v.vibrate(counterValue);
                sleep(counterValue);
                isOver = true;
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                isOver = true;
            }
        }
    };

    // Verhindert, dass die "Back-Taste" erkannt wird und somit das Spiel
    // vorzeitig beendet wird.
    @Override
    public void onBackPressed() {
    }

    private final SensorEventListener mSensorListener = new SensorEventListener() {

        public void onSensorChanged(SensorEvent se) {
            float x = se.values[0];
            float y = se.values[1];
            float z = se.values[2];
            mAccelLast = mAccelCurrent;
            mAccelCurrent = (float) Math.sqrt((double) (x * x + y * y + z * z));
            float delta = mAccelCurrent - mAccelLast;
            mAccel = mAccel * 0.9f + delta; // perform low-cut filter

            SharedPreferences getPrefs = PreferenceManager
                    .getDefaultSharedPreferences(getBaseContext());
            boolean checkSense1 = getPrefs.getBoolean("sensi1", true);
            boolean checkSense2 = getPrefs.getBoolean("sensi2", false);

            if (checkSense1 == true) {
                sensibility = 1.25f;
            }

            if (checkSense2 == true) {
                sensibility = 0.75f;
            }

            // Hier wird geprüft ob das Handy zu stark geschüttelt wurde
            if (mAccel > sensibility) {
                Intent gameOver = new Intent("android.intent.action.BOOM");
                startActivity(gameOver);
            }
            if (isOver == true) {
                Intent gameOver = new Intent("android.intent.action.BOOM");
                startActivity(gameOver);
            }
        }

        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    };

    @Override
    protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(mSensorListener,
                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        mSensorManager.unregisterListener(mSensorListener);
        super.onPause();
        finish();
    }
}
Wenn ich ehrlich bin habe ich noch nicht so wirklich verstanden wie das mit den Threads funktioniert. Wie bekomme ich diese Abfrage
Code:
if (mAccel > sensibility)
in meine run()-Methode? Ich denke jedenfalls das sie da rein müsste. :sad:

Vielen Dank im Voraus!
Martin
 
ui_3k1

ui_3k1

Gesperrt
Wird man aus meiner Fragestellung eigentlich schlau?^^
 
Y

Yuck

Neues Mitglied
magst du deinen code etwas erläutern?
 
StefMa

StefMa

Experte
Ähm.. in dem:
Code:
 // Hier wird geprüft ob das Handy zu stark geschüttelt wurde
            if (mAccel > sensibility) {
                Intent gameOver = new Intent("android.intent.action.BOOM");
                startActivity(gameOver);
            }
            if (isOver == true) {
                Intent gameOver = new Intent("android.intent.action.BOOM");
                startActivity(gameOver);
            }
Muss einfach noch eingebaut werden, dass der Thread beendet werden soll.

Die einfachste Methode:
Beim starten des Thread ein boolean setzten (true). In dem Thread prüfst du jedesmal
Code:
while(boolean-Var)
{...}
In dem Code, der sagt das zu dolle geschüttelt wird, setzt du die variable auf false... Schon rennt dein thread zu ende, aber ohne noch iwas zu machen... (Und wird später autoamtisch von garbage collection zerstört)

Gruß
 
ui_3k1

ui_3k1

Gesperrt
Vielen Dank schon mal so weit, aber das behebt das Problem auch nicht :(

Derzeit sieht mein Code so aus:
Code:
Thread bombTimer = new Thread() {
            public void run() {
                loopThread = true;
                while (loopThread) {
                    try {
                        // Intent-Übergabe des Counters
                        Intent mIntent = getIntent();
                        int counterValue = mIntent
                                .getIntExtra("pushCounter", 0);
                        Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
                        v.vibrate(counterValue);
                        sleep(counterValue);

                        loopThread = false;

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {

                        loopThread = false;
                        Intent gameOver = new Intent(
                                "android.intent.action.BOOM");
                        startActivity(gameOver);
                        finish();
                    }
                }
            }
        };

        bombTimer.start();

    }
und die Prüfung des Sensors so

Code:
if (mAccel > sensibility) {
                loopThread = false;
                Intent gameOver = new Intent("android.intent.action.BOOM");
                startActivity(gameOver);

            }

            if (loopThread == false) {
                Intent gameOver = new Intent("android.intent.action.BOOM");
                startActivity(gameOver);

            }
Muss ich in den Thread noch das finish reinschreiben? Der Thread wird einfach nicht beendet. Er ruft sich immer wieder selbst auf, sobald die Zeit abgelaufen ist, obwohl schon längst eine neue Activity aufgerufen wurde und loopThread (die boolsche Variable) auf false gesetzt wurde.

NACHTRAG:
Ich bekomme es so einfach nicht hin. Mir erscheint das relativ wirr... manchmal wird der Thread (scheinbar) gestoppt, manchmal nicht. Ich verstehe es nicht. Hatte jemand schon mal ähnliche Probleme?
Und was mich an der Sache am meisten stört:
Egal wo ich nachlese: "Thread.stop() macht man nicht mehr - ist nicht merh zeitgemäß" tzz... gibts denn keine Möglichkeit einfach einen Thread zu stoppen?
 
Zuletzt bearbeitet:
StefMa

StefMa

Experte
Du setzt loopThread als Klassenvariable. Wenn du den code oben nimmt hast du immer true :)
Wenn du die activity beenden willst, mjsst du noch finisb machen. Aber nicht zwingend notwenid...

Gesendet von meinem Nexus 10 mit Tapatalk 4
 
ui_3k1

ui_3k1

Gesperrt
Nochmals vielen Dank für den Hinweis, das stimmt, habe ich nicht bedacht :-(
Allerdings muss ich ja auch bei einer Bewegung den Thread stoppen und der Sensor erkennt die loopThread-Variable nicht, wenn ich sie nicht in der Klasse deklariere.

Ich glaube mein Problem liegt in der Kombination zwischen Timer und Bewegungssensor.

Der ursprüngliche Beitrag 09.09.2013 von 23:27 Uhr wurde 10.09.2013 um 00:36 Uhr ergänzt:

Das Projekt gebe ich auf. Die App funktioniert auf meinem Handy halbwegs, während es auf einem anderen Gerät gar nicht klappt. Wie in aller Welt kann das sein?!

Fazit: Android != Android ?!
 
StefMa

StefMa

Experte
Du musst nur deine Klasse etwas umbauen.
Statt eine eigene Instanz vom Sensorlistener imlemtentierst du sie besser.
Dann hätten wir es da schon mal einfacher...

Desweiteren kannst du in der Activity eine getLoopVar()-Methode anlegen die nur den wert der varaible zurück gibt.
Im Thread rufst du einfach diese Methode auf und schon bekommst du deine Variable...

Wenn du es aber aufgibst, dann spar ich mir alles :)
 
ui_3k1

ui_3k1

Gesperrt
Ich weiß nicht wie ich dir danken soll. Dass du das alles so mitmachst und dir die Zeit nimmst finde ich sau stark. :)
Allerdings bin ich ehrlich gesagt doch ziemlich überfordert mit der Thematik :sad:

Ich habe jetzt nochmal das versucht umzusetzen, was du mir empfohlen hast. Die Activity schließt sich nach Ablauf der Zeit schon mal reibungslos, aber der Bewegungssensor wird nicht mehr erkannt.
Und ich habe den Code nochmal genauer kommentiert (auch selbst nochmal logisch alles in einzelnen Schritten durchdacht)... Aber irgendwas passt noch nicht

Aktueller Stand der Dinge:
Code:
public class WaitingForBomb extends Activity implements SensorEventListener {

    float sensibility = 2.5f;
    SensorEventListener mSensorListener;
    private SensorManager mSensorManager;
    private float mAccel; // Beschleunigung
    private float mAccelCurrent; // aktuelle Beschleunigung (in Verbindung mit
                                    // Erdanziehung)?
    private float mAccelLast; // letzte Beschleunigung (in Verbindung mit
                                // Erdanziehung)?
    TextView anzeige;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.waiting);

        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

        mSensorManager.registerListener(mSensorListener,
                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_NORMAL);
        mAccel = 0.00f;
        mAccelCurrent = SensorManager.GRAVITY_EARTH;
        mAccelLast = SensorManager.GRAVITY_EARTH;

        // Sleep-Timer
        Thread bombTimer = new Thread() {

            public void run() {
               [COLOR=SeaGreen] // Übergabe der Daten aus der vorherigen Activity (PASST)
                Intent mIntent = getIntent();
                int counterValue = mIntent.getIntExtra("pushCounter", 0);[/COLOR]

                // loopThread = Bedingung die erfüllt sein muss damit der Thread
                // durchlaufen wird
                boolean loopThread = true;
                while (loopThread) {

                    [COLOR=Red]// Hier soll bei zu starker Bewegung loopThread auf false
                    // gesetzt werden (FUNKTION FRAGLICH)
                   [COLOR=Black] loopThread = getLoopVar();[/COLOR][/COLOR]
                    try {
                        Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
                        v.vibrate(counterValue);
                        sleep(counterValue);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        loopThread = false;
                    }
                    [COLOR=Red]// Wenn loopThread false ist, soll die nächste Activity
                    // geladen werden[/COLOR]
                    if (!loopThread) {
                        Intent gameOver = new Intent(
                                "android.intent.action.BOOM");
                        startActivity(gameOver);
                    }
                }
            }

           [COLOR=Red] // Methode: Prüfung der Bewegung des Geräts (RICHTIGE ANORDNUNG FRAGLICH)
            [COLOR=Black]private boolean getLoopVar() {
                if (mAccel > sensibility) {
                    return false;
                } else
                    return true;
            }[/COLOR][/COLOR]

        };

        bombTimer.start();
    }

    // Blockt die "Back-Taste"
    @Override
    public void onBackPressed() {
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        float x = event.values[0];
        float y = event.values[1];
        float z = event.values[2];
        mAccelLast = mAccelCurrent;
        mAccelCurrent = (float) Math.sqrt((double) (x * x + y * y + z * z));
        float delta = mAccelCurrent - mAccelLast;
        mAccel = mAccel * 0.9f + delta;

        [COLOR=SeaGreen]// SharedPreferences & checkSense = Menüeinstellung (PASST)
        SharedPreferences getPrefs = PreferenceManager
                .getDefaultSharedPreferences(getBaseContext());
        boolean checkSense1 = getPrefs.getBoolean("sensi1", true);
        boolean checkSense2 = getPrefs.getBoolean("sensi2", false);
        if (checkSense1 == true) {
            sensibility = 1.25f;
        }
        if (checkSense2 == true) {
            sensibility = 0.75f;
        }[/COLOR]
    }

    @Override
    protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(mSensorListener,
                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        mSensorManager.unregisterListener(mSensorListener);
        super.onPause();
        finish();
    }

}
 
Zuletzt bearbeitet:
StefMa

StefMa

Experte
Code:
mSensorManager.registerListener(mSensorListener,
                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_NORMAL);
Du musst den SensorListener ja auch auf die Activity (also this) setzten. Die Klasse "mSensorListener" existiert ja nicht mehr ;) Nimm auch die Klasssenvariable dazu raus...

Eine getLoopVar() hast du nicht implementiert?! Sehe zumindest keine :)
Code:
public boolean getLoopVar() {
   return loopThread;
}
Dann kannst du sie im thread via:
WaitingForBomb.getLoopVar(); holen...

Das ganze muss auch im Thread schon VOR der while() passieren.

Bisschen verwirrt dein Code ;) du willst grade einfach nur schnell zum ziel kommen :)

Gruß
 
ui_3k1

ui_3k1

Gesperrt
Hehe, ja das mit dem fertig sein wollen stimmt wohl. Liegt aber nicht daran, dass ich nichts lernen will, sondern eher daran, dass ich die App mal fertig bekommen will. :D
Aber du erklärst sehr gut ;)

Damit ich .getLoopVar benutzen kann, sagt mir Eclipse, dass ich loopThread und getLoopVar() in static umwandeln muss. Aber das will ich doch gerade umgehen, oder sehe ich das falsch?
 
StefMa

StefMa

Experte
Ja müsste mit static gehen.. :)
Probiers aus ^^
 
ui_3k1

ui_3k1

Gesperrt
Immer noch das Gleiche.

Irgendwas stimmt nicht bei dem
Code:
if (mAccel > sensibility) {
                            WaitingForBomb.getLoopVar();
                        }
Wenn ich von dort die neue Activity aufrufe geht die App so wie sie soll, nur dass, dort eben nicht der Thread beendet wird.
 
StefMa

StefMa

Experte
Wenn ich von dort die neue Activity aufrufe geht die App so wie sie soll, nur dass, dort eben nicht der Thread beendet wird.
Dan ruf doch dort die neue Activity auf uns setzte loopThread = false;
Dann sollte die while() auch nicht mehr laufen. Ergo auch der Thread beenden...

Gruß
 
ui_3k1

ui_3k1

Gesperrt
Eigentlich gibt es doch 2 Stellen, wie man die Activity und damit auch den Thread beenden könnte.
Einmal ruft man die neue Activity nach der Bewegung auf und eine andere Möglichkeit wäre die neue Activity nach dem Ablauf der Zeit aufzurufen. Aber warum in aller Welt ist es so schwierig diesen Thread einfach zu stoppen?
Ich habe das Gefühl alles was ich in Form von if-Abfragen eingebe wird regelrecht vom Compiler ignoriert. oO

Der ursprüngliche Beitrag von 13:07 Uhr wurde um 13:09 Uhr ergänzt:

StefMa schrieb:
Dan ruf doch dort die neue Activity auf uns setzte loopThread = false;
Dann sollte die while() auch nicht mehr laufen. Ergo auch der Thread beenden...

Gruß
Das habe schon versucht.. Aber das loopThread = false wird nicht ausgeführt.

Der Thread beginnt bei mir so:
Code:
WaitingForBomb.getLoopVar();
                while (loopThread) {

                    try {...
Viele Grüße
 
StefMa

StefMa

Experte
Wie gesagt, eigentlich musst du den thread nicht stoppen. Nur das er nichts mehr macht.
Also einfach eine Variable setzten, die vorher prüft ob es noch true ist.. Wenn false ist läuft der Thread und macht drinne... NICHTS!
Irgendwann stirbt er dann von selbst..

Gruß

€dit: DU musst ja auch in der getLoopVar() mnicht true oder false zurück geben sondern loopThread. Und dieser wird irgendwo anders auf false gesetzt,...
 
ui_3k1

ui_3k1

Gesperrt
Die Methode sollte passen. Gerade habe ich das Problem genau anders herum, der Thread wird ignoriert.

Code:
public class WaitingForBomb extends Activity implements SensorEventListener {

    static boolean loopThread;

    public static boolean getLoopVar() {
        return loopThread;
    }

    float sensibility = 2.5f;

    private SensorManager mSensorManager;
    private float mAccel; // Beschleunigung
    private float mAccelCurrent; // aktuelle Beschleunigung (in Verbindung mit
                                    // Erdanziehung)?
    private float mAccelLast; // letzte Beschleunigung (in Verbindung mit
                                // Erdanziehung)?
    TextView anzeige;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.waiting);

        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_NORMAL);
        mAccel = 0.00f;
        mAccelCurrent = SensorManager.GRAVITY_EARTH;
        mAccelLast = SensorManager.GRAVITY_EARTH;

        // Sleep-Timer
        Thread bombTimer = new Thread() {

            public void run() {
                // Übergabe der Daten aus der vorherigen Activity (PASST)
                Intent mIntent = getIntent();
                int counterValue = mIntent.getIntExtra("pushCounter", 0);

                // loopThread = Bedingung die erfüllt sein muss damit der Thread
                // durchlaufen wird
                // boolean loopThread = true;

                // Hier soll bei zu starker Bewegung loopThread auf false
                // gesetzt werden (FUNKTION FRAGLICH)
                WaitingForBomb.getLoopVar();
                while (loopThread) {

                    try {
                        Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
                        v.vibrate(counterValue);
                        sleep(counterValue);
                        
                
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        loopThread = false;
                        Intent gameOverByTime = new Intent("android.intent.action.BOOM");
                        startActivity(gameOverByTime);
                    }
                }
            }

        };

        bombTimer.start();

    }

    // Blockt die "Back-Taste"
    @Override
    public void onBackPressed() {
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        float x = event.values[0];
        float y = event.values[1];
        float z = event.values[2];
        mAccelLast = mAccelCurrent;
        mAccelCurrent = (float) Math.sqrt((double) (x * x + y * y + z * z));
        float delta = mAccelCurrent - mAccelLast;
        mAccel = mAccel * 0.9f + delta;

        // SharedPreferences & checkSense = Menüeinstellung (PASST)
        SharedPreferences getPrefs = PreferenceManager
                .getDefaultSharedPreferences(getBaseContext());
        boolean checkSense1 = getPrefs.getBoolean("sensi1", true);
        boolean checkSense2 = getPrefs.getBoolean("sensi2", false);
        if (checkSense1 == true) {
            sensibility = 1.25f;
        }
        if (checkSense2 == true) {
            sensibility = 0.75f;
        }

        if (mAccel > sensibility) {
            loopThread = false;
            Intent gameOver = new Intent("android.intent.action.BOOM");
            startActivity(gameOver);
        }

    }

    @Override
    protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        mSensorManager.unregisterListener(this);
        super.onPause();
        finish();
    }

}
Ich sehe schon vor lauter Bäumen den Wald nicht mehr. Ich spende dir mal ein Bierchen ;)
 
StefMa

StefMa

Experte
Ja, weil loopThread = null ist ;)
Du musst beim initalisieren loopThread = true setzten,...

Glaube jetzt sollte alles passen :D

Gruß
 
ui_3k1

ui_3k1

Gesperrt
:D

Ja, sieht schon besser aus.
-Bewegungen werden registriert
-Zeit wird heruntergezählt

Aber der Thread wird trotzdem noch nicht beendet. :-/ Sprich wenn man das Gerät schüttelt wird die neue Actitvity geöffnet, und dann wird der Thread trotzdem noch ein zweites Mal irgendwann im Hintergrund geöffnet. Der Thread will nicht sterben.

Der ursprüngliche Beitrag von 13:37 Uhr wurde um 13:42 Uhr ergänzt:

Und die nächste Sache die ich absolut nicht verstehe, ist dass die App auf einem S2 in keinster Weise funktioniert. Dort wird sofort die neue Activity geöffnet.

Ich gebs auf -.-