Consider the following:
package com.example.savag.bcapplication;
import android.app.Activity;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements SensorEventListener {
//define global variable types
int counter = 9;
String strcounter;
int buttoncounter = 0;
String strbcounter;
//Define the sensor Manager
SensorManager sm;
//Define the Motion Sensor objects
Sensor accelerometer;
Sensor gravity;
Sensor gyroscope;
Sensor uncalgyro;
Sensor lineaccel;
Sensor rotatevector;
Sensor sigmotion;
Sensor stepcounter;
Sensor stepdetector;
//Define the changing Motion Sensor text values
//Define the position sensor objects
Sensor gamerotatevector;
ImageButton arrowup;
ImageButton arrowdown;
ImageView navbar;
TextView dynamictext;
TextView dynamicheader;
private final Handler handler = new Handler();
SenseThread myThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Need to declare here if findviewbyid is being run
arrowup = (ImageButton) findViewById(R.id.uparrow);
arrowdown = (ImageButton) findViewById(R.id.downarrow);
navbar = (ImageView) findViewById(R.id.infospace);
dynamictext = (TextView) findViewById(R.id.dynamictxt);
dynamicheader = (TextView) findViewById(R.id.dynamiched);
//Global counter variables
counter = 9;
strcounter = Integer.toString(counter);
buttoncounter = 0;
strbcounter = Integer.toString(buttoncounter);
//Set Nav bar invisible for now
arrowup.setVisibility(View.GONE);
arrowdown.setVisibility(View.GONE);
navbar.setVisibility(View.GONE);
dynamictext.setVisibility(View.GONE);
dynamicheader.setVisibility(View.GONE);
sm = (SensorManager) getSystemService(SENSOR_SERVICE);
myThread = new SenseThread();
myThread.start();
arrowup.setOnClickListener( //This is for the up arrow
new ImageButton.OnClickListener() {
public void onClick(View v) {
if ((strcounter.equals("10")) || (strcounter.equals("9"))) { //Further than limit or limit
//do nothing if strcounter is 10 or 9
}
if ((strbcounter.equals("1")) && (strcounter.equals("8"))) { // Check if we are on limit and motion button
if (sm.getSensorList(Sensor.TYPE_ACCELEROMETER).size() != 0) { // Add check to see if we have this sensor
dynamicheader.setText("Acceleration:");
sm.registerListener(MainActivity.this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL, myThread.handler2);
} else if (sm.getSensorList(Sensor.TYPE_ACCELEROMETER).size() == 0) {
dynamictext.setText("Sensor not detected");
}
counter++; //Increment to 9 (limit)
strcounter = Integer.toString(counter); // Set the appropriate conversion
return;
}
if ((strbcounter.equals("1")) && (strcounter.equals("7"))) {
sm.unregisterListener(MainActivity.this, gyroscope);
if (sm.getSensorList(Sensor.TYPE_ROTATION_VECTOR).size() != 0) { // Add check to see if we have this sensor
dynamicheader.setText("Rotation Vector:");
sm.registerListener(MainActivity.this, rotatevector, SensorManager.SENSOR_DELAY_NORMAL, myThread.handler2);
} else if (sm.getSensorList(Sensor.TYPE_ROTATION_VECTOR).size() == 0) {
dynamictext.setText("Sensor not detected");
}
counter++; //Increment to 8
strcounter = Integer.toString(counter); // Set the appropriate conversion
return;
}
if ((strbcounter.equals("1")) && (strcounter.equals("6"))) {
sm.unregisterListener(MainActivity.this, gravity);
if (sm.getSensorList(Sensor.TYPE_GYROSCOPE).size() != 0) { // Add check to see if we have this sensor
dynamicheader.setText("Gyroscope:");
sm.registerListener(MainActivity.this, gyroscope, SensorManager.SENSOR_DELAY_NORMAL, myThread.handler2);
} else if (sm.getSensorList(Sensor.TYPE_GYROSCOPE).size() == 0) {
dynamictext.setText("Sensor not detected");
}
counter++; //Increment to 7
strcounter = Integer.toString(counter); // Set the appropriate conversion
return;
}
if ((strbcounter.equals("1")) && (strcounter.equals("5"))) {
sm.unregisterListener(MainActivity.this, sigmotion);
if (sm.getSensorList(Sensor.TYPE_GRAVITY).size() != 0) { // Add check to see if we have this sensor
dynamicheader.setText("Gravity Sensor:");
sm.registerListener(MainActivity.this, gravity, SensorManager.SENSOR_DELAY_NORMAL, myThread.handler2);
} else if (sm.getSensorList(Sensor.TYPE_GRAVITY).size() == 0) {
dynamictext.setText("Sensor not detected");
}
counter++; //Increment to 6
strcounter = Integer.toString(counter); // Set the appropriate conversion
return;
}
if ((strbcounter.equals("1")) && (strcounter.equals("4"))) {
sm.unregisterListener(MainActivity.this, lineaccel);
if (sm.getSensorList(Sensor.TYPE_SIGNIFICANT_MOTION).size() != 0) { // Add check to see if we have this sensor
dynamicheader.setText("Significant Motion:");
sm.registerListener(MainActivity.this, sigmotion, SensorManager.SENSOR_DELAY_NORMAL, myThread.handler2);
} else if (sm.getSensorList(Sensor.TYPE_SIGNIFICANT_MOTION).size() == 0) {
dynamictext.setText("Sensor not detected");
}
counter++; //Increment to 5
strcounter = Integer.toString(counter); // Set the appropriate conversion
return;
}
if ((strbcounter.equals("1")) && (strcounter.equals("3"))) {
sm.unregisterListener(MainActivity.this, uncalgyro);
if (sm.getSensorList(Sensor.TYPE_LINEAR_ACCELERATION).size() != 0) { // Add check to see if we have this sensor
dynamicheader.setText("Linear Acceleration:");
sm.registerListener(MainActivity.this, lineaccel, SensorManager.SENSOR_DELAY_NORMAL, myThread.handler2);
} else if (sm.getSensorList(Sensor.TYPE_LINEAR_ACCELERATION).size() == 0) {
dynamictext.setText("Sensor not detected");
}
counter++; //Increment to 4
strcounter = Integer.toString(counter); // Set the appropriate conversion
return;
}
if ((strbcounter.equals("1")) && (strcounter.equals("2"))) {
if (sm.getSensorList(Sensor.TYPE_GYROSCOPE_UNCALIBRATED).size() != 0) { // Add check to see if we have this sensor
dynamicheader.setText("Uncalibrated Gyroscope:");
sm.registerListener(MainActivity.this, uncalgyro, SensorManager.SENSOR_DELAY_NORMAL, myThread.handler2);
} else if (sm.getSensorList(Sensor.TYPE_GYROSCOPE_UNCALIBRATED).size() == 0) {
dynamictext.setText("Sensor not detected");
}
counter++; //Increment to 3
strcounter = Integer.toString(counter); // Set the appropriate conversion
//return;
}
if ((strbcounter.equals("1")) && (strcounter.equals("1"))) {
sm.unregisterListener(MainActivity.this, stepdetector);
if (sm.getSensorList(Sensor.TYPE_STEP_COUNTER).size() != 0) { // Add check to see if we have this sensor
dynamicheader.setText("Steps Counted:");
sm.registerListener(MainActivity.this, stepcounter, SensorManager.SENSOR_DELAY_NORMAL, myThread.handler2);
} else if (sm.getSensorList(Sensor.TYPE_STEP_COUNTER).size() == 0) {
dynamictext.setText("Sensor not detected");
}
counter++; //Increment to 2
strcounter = Integer.toString(counter); // Set the appropriate conversion
return;
}
if ((strbcounter.equals("1")) && (strcounter.equals("0"))) {
if (sm.getSensorList(Sensor.TYPE_STEP_DETECTOR).size() != 0) { // Add check to see if we have this sensor
dynamicheader.setText("Steps Detected:");
sm.registerListener(MainActivity.this, stepdetector, SensorManager.SENSOR_DELAY_NORMAL, myThread.handler2);
} else if (sm.getSensorList(Sensor.TYPE_STEP_DETECTOR).size() == 0) {
dynamictext.setText("Sensor not detected");
}
counter++; //Increment to 1
strcounter = Integer.toString(counter); // Set the appropriate conversion
}
}
}
);
@Override
public void onSensorChanged(SensorEvent event) {
if (sm.getSensorList(Sensor.TYPE_ACCELEROMETER).size() != 0) {
TextView dynamictext = (TextView) findViewById(R.id.dynamictxt);
dynamictext.setText("X: " + event.values[0] + " MS^-2 \nY: " + event.values[1] + " MS^-2 \nZ: " + event.values[2] + " MS^-2");
} else if (sm.getSensorList(Sensor.TYPE_ROTATION_VECTOR).size() != 0) {
TextView dynamictext = (TextView) findViewById(R.id.dynamictxt);
dynamictext.setText("X: " + event.values[0] + "\nY: " + event.values[1] + "\nZ: " + event.values[2] + "scalar: " + event.values[3]);
} else if (sm.getSensorList(Sensor.TYPE_GYROSCOPE).size() != 0) {
TextView dynamictext = (TextView) findViewById(R.id.dynamictxt);
dynamictext.setText("X: " + event.values[0] + " rad/s \nY: " + event.values[1] + " rad/s \nZ: " + event.values[2] + " rad/s");
} else if (sm.getSensorList(Sensor.TYPE_GRAVITY).size() != 0) {
TextView dynamictext = (TextView) findViewById(R.id.dynamictxt);
dynamictext.setText("X: " + event.values[0] + " MS^-2 \nY: " + event.values[1] + " MS^-2 \nZ: " + event.values[2] + " MS^-2");
}
//else if (sm.getSensorList(Sensor.TYPE_GRAVITY).size() != 0) { // significant motion needs a different process
// TextView dynamictext = (TextView) findViewById(R.id.dynamictxt);
// dynamictext.setText("X: " + event.values[0] + "\nY: " + event.values[1] + "\nZ: " + event.values[2]);
//}
else if (sm.getSensorList(Sensor.TYPE_LINEAR_ACCELERATION).size() != 0) {
TextView dynamictext = (TextView) findViewById(R.id.dynamictxt);
dynamictext.setText("X: " + event.values[0] + " MS^-2 \nY: " + event.values[1] + " MS^-2 \nZ: " + event.values[2] + " MS^-2");
} else if (sm.getSensorList(Sensor.TYPE_GYROSCOPE_UNCALIBRATED).size() != 0) {
TextView dynamictext = (TextView) findViewById(R.id.dynamictxt);
dynamictext.setText("X: " + event.values[0] + " rad/s \nY: " + event.values[1] + " rad/s \nZ: " + event.values[2] + " rad/s"
+ "X: " + event.values[3] + " rad/s \nY: " + event.values[4] + " rad/s \nZ: " + event.values[5] + " rad/s");
}
//else if (sm.getSensorList(Sensor.TYPE_STEP_COUNTER).size() != 0) { // MAY need a different process
// TextView dynamictext = (TextView) findViewById(R.id.dynamictxt);
// dynamictext.setText("X: " + event.values[0] + "\nY: " + event.values[1] + "\nZ: " + event.values[2]);
//}
//else if (sm.getSensorList(Sensor.TYPE_STEP_DETECTOR).size() != 0) { // Like sig, needs a different process
// TextView dynamictext = (TextView) findViewById(R.id.dynamictxt);
// dynamictext.setText("X: " + event.values[0] + "\nY: " + event.values[1] + "\nZ: " + event.values[2]);
//}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
class SenseThread extends Thread{
Handler handler2;
public SenseThread() {
}
public void run() {
Looper.prepare();
handler2=new Handler();
Looper.loop();
}
}
This flags up:
10-14 07:22:01.304 2333-2349/com.example.savag.babcockapplication E/SensorManager﹕ Exception dispatching input event.
--------- beginning of crash
10-14 07:22:01.333 2333-2349/com.example.savag.babcockapplication E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-123
Process: com.example.savag.babcockapplication, PID: 2333
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6556)
at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:907)
at android.view.View.requestLayout(View.java:18722)
at android.view.View.requestLayout(View.java:18722)
at android.view.View.requestLayout(View.java:18722)
at android.view.View.requestLayout(View.java:18722)
at android.view.View.requestLayout(View.java:18722)
at android.view.View.requestLayout(View.java:18722)
at android.view.View.requestLayout(View.java:18722)
at android.widget.TextView.checkForRelayout(TextView.java:7172)
at android.widget.TextView.setText(TextView.java:4342)
at android.widget.TextView.setText(TextView.java:4199)
at android.widget.TextView.setText(TextView.java:4174)
at com.example.savag.babcockapplication.MainActivity.onSensorChanged(MainActivity.java:382)
at android.hardware.SystemSensorManager$SensorEventQueue.dispatchSensorEvent(SystemSensorManager.java:481)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:323)
at android.os.Looper.loop(Looper.java:135)
at com.example.savag.babcockapplication.SenseThread.run(MainActivity.java:500)
10-14 07:22:03.691 2333-2350/com.example.savag.babcockapplication E/Surface﹕ getSlotFromBufferLocked: unknown buffer: 0xab97bd40
10-14 07:22:04.988 2333-2349/? I/Process﹕ Sending signal. PID: 2333 SIG: 9
So I know my problem I just don't know how to solve it.
And in actual fact this problem is three-fold.
First:
I've created a looper in the handler at the bottom tied to a looper, passed this handler into the registerlistener for my sensor. As you can see above, the error flags up "Only the original thread that created a view hierarchy can touch its views.". And this refers to the onSensorchanged for updating the dynamic text. How could I rectify this? I don't mind the dynamic text updating on the UIThread but in this case, sensorchanged would be tied to the new thread for the handling of the eventlisteners.
Second: The looper currently will run forever, how exactly do I stop and reuse the looper for the handler. Furthermore if I unregisterlistener will this automatically stop the running of the handler/looper for me? Documents everywhere tell me not to quit the looper and to just re-use but don't specify how to. Deleting and restarting the thread continuously is not an option either as this operation is expensive.
Thirdly:
Will this continuously update the sensor when changed or so I need to set-up a service coupled with an alarm? Slightly confused on the operation of this.
Please add me some clarification or suggestions. Thank you!