I'm new to Android programming and i'm trying to understand the control flow in android programs. I've been working on a program to log and display sensor data.
public class MainActivity extends ActionBarActivity implements SensorEventListener
This is the main class with onCreate(), btnStart.setOnClickListener(new OnClickListener(), btnStop.setOnClickListener(new OnClickListener(), onSensorChanged(SensorEvent event) which do most of the important tasks.
onCreate() has all this code:
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
title = (TextView)findViewById(R.id.titleView);
acc_x = (TextView)findViewById(R.id.acc_x_values);
acc_y = (TextView)findViewById(R.id.acc_y_values);
acc_z = (TextView)findViewById(R.id.acc_z_values);
x = (TextView)findViewById(R.id.acc_x);
y = (TextView)findViewById(R.id.acc_y);
z = (TextView)findViewById(R.id.acc_z);
btnStart = (Button)findViewById(R.id.button_start);
btnStop = (Button)findViewById(R.id.button_stop);
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mAccel = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(this,sensorManager.getDefaultSensor(sensorType), 20000);
And the start and stop button funtionalities are defined here.
btnStart.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
startFlag = true;
String storepath = Environment.getExternalStorageDirectory().getPath();
System.out.println("Stored at" +storepath); // /storage/sdcard
Toast.makeText(getBaseContext(), "Started Recording Data and Storing at"+storepath, Toast.LENGTH_SHORT).show();
try {
myFile = new File(storepath + "/GaitApp/" + name.getText() + "_acc.csv");
myFile.createNewFile();
fOut = new FileOutputStream(myFile);
myOutWriter = new OutputStreamWriter(fOut);
myBufferedWriter = new BufferedWriter(myOutWriter);
myPrintWriter = new PrintWriter(myBufferedWriter);
} catch (Exception e) {
Toast.makeText(getBaseContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
} //onclick
}); //startbutton
btnStop.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Toast.makeText(getBaseContext(), "Stopped Recording",Toast.LENGTH_SHORT).show();
startFlag = false;
try {
fOut.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}// onClick
}); // btnstopButton
onSensorChanged() is:
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
if(startFlag){
float[] values = event.values;
// Movement
float x_float = values[0];
float y_float = values[1];
float z_float = values[2];
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String currentDateandTime = sdf.format(new Date());
long curTime = System.currentTimeMillis();
if ((curTime - lastUpdate) > 20) {
long diffTime = (curTime - lastUpdate);
lastUpdate = curTime;
x_float = event.values[0];
y_float = event.values[1];
z_float = event.values[2];
acc_x.setText(Float.toString(x_float));
acc_y.setText(Float.toString(y_float));
acc_z.setText(Float.toString(z_float));
String res=String.valueOf(currentDateandTime+", "+x_float)+", "+String.valueOf(y_float)+", "+String.valueOf(z_float+"\n");
Log.d("test", res);
for (int i = 0; i % 1 == 0; i++) {
if (startFlag) {
try{
fOut = new FileOutputStream(myFile);
myOutWriter = new OutputStreamWriter(fOut);
myBufferedWriter = new BufferedWriter(myOutWriter);
myPrintWriter = new PrintWriter(myBufferedWriter);
myPrintWriter.append(curTime - lastUpdate + ", " + x_float + ", " + y_float + ", " + z_float+ "\n");
}
catch (IOException e){
System.out.println("Exception: "+e);
}
//myPrintWriter.write(curTime - lastUpdate + ", " + x_float + ", " + y_float + ", " + z_float+ "\n");
} //startFlag is true
else {
try {
myOutWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fOut.close();
} catch (IOException e) {
e.printStackTrace();
} // catch
} // else
} //for
} // if -- time
} // startFlag
} //accelerometer -- sensor
} // onSensorChanged
I'm trying to understand how the onSensorChanged() transfers control and in the process the acceleration data to onCreate() to be displayed and stored.
The onCreate method is only used to initially setup the view. Updates to the display must occur by deliberately invoking them. Furthermore updates to the UI must occur on the UI thread. Since the onSensorChanged call can occur asynchronously, if you wish sensor updates to trigger a display update you must send yourself a UI thread event. One option is to use a handler such as in the following untested code.
private Handler mHandler;
public void onCreate() {
mHandler = new Handler();
}
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
saveData(event);
final long currentTime = System.currentTimeMillis();
if (isResumed() && currentTime > (lasttime + SOME_DELAY)) {
lasttime = currentTime;
handler.post(new Runnable() {
#Override
public void run() {
updateDisplay(event);
}
});
}
}
}
private void updateDisplay(SensorEvent event) {
acc_x.setText(...);
acc_y.setText(...);
acc_z.setText(...);
x.setText(...);
y.setText(...);
z.setText(...);
}
Depending on your application you may wish to log your data in a service.
onSensorChanged() is the handler in this case. This call back function takes care of updating the UI and writing to the file.
Related
I am using Raspberry pi3 and DHT11 sensor for temperature monitoring project.
I have following pin positions
VCC to pin no : 2
Ground to pin no : 6
Output to GPIO : BCM22 i.e pin no 15
Code that I have used:
public class WeatherStationActivity extends Activity {
private Handler mHandler = new Handler();
private TextView mTxtStatus;
private PeripheralManagerService service = new PeripheralManagerService();
private Gpio tempGpio;
private int i = 0;
int[] dht11_dat = {0, 0, 0, 0, 0};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("Weather station", "Started Weather Station");
setContentView(R.layout.activity_main);
mTxtStatus = (TextView) findViewById(R.id.txtStatus);
try {
tempGpio = service.openGpio("BCM22");
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (i == 10) {
handler.removeCallbacks(this);
} else {
getTemp();
handler.postDelayed(this, 5000);
}
i++;
}
}, 5000);
} catch (Exception e) {
e.printStackTrace();
}
}
private void getTemp() {
boolean laststate = false;
try {
laststate = tempGpio.getValue();
} catch (IOException e) {
e.printStackTrace();
}
int j = 0;
final int MAXTIMINGS = 85;
dht11_dat[0] = dht11_dat[1] = dht11_dat[2] = dht11_dat[3] = dht11_dat[4] = 0;
try {
tempGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
// tempGpio.setActiveType(Gpio.ACTIVE_LOW);
tempGpio.setValue(false);
// Thread.sleep(18);
TimeUnit.MILLISECONDS.sleep(18);
// tempGpio.setActiveType(Gpio.ACTIVE_HIGH);
// tempGpio.setActiveType(Gpio.ACTIVE_HIGH);
tempGpio.setValue(true);
TimeUnit.MICROSECONDS.sleep(40);
tempGpio.setDirection(Gpio.DIRECTION_IN);
/* tempGpio.setActiveType(Gpio.ACTIVE_HIGH);
tempGpio.setValue(true);*/
// tempGpio.setValue(true);
StringBuilder value = new StringBuilder();
for (int i = 0; i < MAXTIMINGS; i++) {
int counter = 0;
while (tempGpio.getValue() == laststate) {
counter++;
TimeUnit.MICROSECONDS.sleep(1);
if (counter == 255) {
break;
}
}
laststate = tempGpio.getValue();
mTxtStatus.append("\nLast State of Sensor " + laststate);
if (counter == 255) {
break;
}
//* ignore first 3 transitions *//*
if ((i >= 4) && (i % 2 == 0)) {
//* shove each bit into the storage bytes *//*
dht11_dat[j / 8] <<= 1;
if (counter > 16) {
dht11_dat[j / 8] |= 1;
}
j++;
}
}
// check we read 40 bits (8bit x 5 ) + verify checksum in the last
// byte
if ((j >= 40) && checkParity()) {
value.append(dht11_dat[2]).append(".").append(dht11_dat[3]);
Log.i("Logger", "temperature value readed: " + value.toString());
mTxtStatus.append("\nTemp " + value.toString());
} else {
mTxtStatus.append("\nNothing is working ");
Log.i("Logger", "Nothing is working ");
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private boolean checkParity() {
return dht11_dat[4] == (dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3] & 0xFF);
}
}
Above code is giving me "Nothing is working" as output.
Any suggestion where I might be doing wrong?
You can't read data from DHT11 using Raspberry Pi 3 with Android Things because duration of DHT11 response pulses is from 26-28 us to 70 us, but max frequency of RP3 with AT GPIO is around 3kHz, which means around 300 us pulse duration. Take a look at answers to this question.
I want to get accelerometer sensor data which is in earth axis through a service. I read about a way to do it as well on one of the posts on stackoverflow. But I have an issue.
#Override
public void onSensorChanged(SensorEvent event) {
Toast.makeText(this, "Hollyy shiiitt",Toast.LENGTH_SHORT);
String acceldata = "";
float[] gravityValues = null;
float[] magneticValues = null;
if (event.sensor.getType() == Sensor.TYPE_GRAVITY) {
gravityValues = event.values.clone();
Toast.makeText(this, "The gra data is " + String.valueOf(gravityValues), Toast.LENGTH_SHORT);
}
if ((gravityValues != null) && (magneticValues != null)
&& (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)) {
// float for use in conversion device relative acceleration to earth axis acceleration
float[] deviceRelativeAcceleration = new float[4];
deviceRelativeAcceleration[0] = event.values[0];
deviceRelativeAcceleration[1] = event.values[1];
deviceRelativeAcceleration[2] = event.values[2];
deviceRelativeAcceleration[3] = 0;
// Change the device relative acceleration values to earth relative values
// X axis -> East
// Y axis -> North Pole
// Z axis -> Sky
float[] R = new float[16], I = new float[16], earthAcc = new float[16];
SensorManager.getRotationMatrix(R, I, gravityValues, magneticValues);
float[] inv = new float[16];
android.opengl.Matrix.invertM(inv, 0, R, 0);
android.opengl.Matrix.multiplyMV(earthAcc, 0, inv, 0, deviceRelativeAcceleration, 0);
acceldata = String.valueOf(lat) + "," + String.valueOf(lon) + "," + String.valueOf(speed)+","+ String.valueOf(earthAcc[0]) + "," + String.valueOf(earthAcc[1]) + "," + String.valueOf(earthAcc[2])+ "," + String.valueOf(event.values[0])+ "," + String.valueOf(event.values[1])+ "," + String.valueOf(event.values[2]);
}
//SDK version check
if(Build.VERSION.SDK_INT > 18) {
File file;
FileWriter filew; // Internal Storage writing
try {
file = new File(getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS) + "/" + filename); //Android 4.4 and above
filew = new FileWriter(file, true); //true for append
filew.write(acceldata + String.valueOf(gravityValues) + String.valueOf(magneticValues) + "\n");
filew.close();
} catch (Exception e) {
e.printStackTrace();
}
}
else{
String data = acceldata + "\n" ;
try {
FileOutputStream fOut = openFileOutput("/" + filename,Context.MODE_APPEND);
fOut.write(data.getBytes());
fOut.close();
Toast.makeText(getBaseContext(),"file saved",Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getBaseContext(),"file not saved API < 19",Toast.LENGTH_SHORT).show();
}
}
}
The if statement for gravity sensor on location changed doesn't return any value so the next statement also doesn't work as gravityValues has a null value.
The sensors registered are
mAccelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mMagnetsensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
mGravity = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
They are then registered as
int SamplingFrequency = 2 * 100000; // delay in microsecond. in this case 0.2 second
sensorManager.registerListener(this, mAccelerometer,SamplingFrequency);
sensorManager.registerListener(this, mMagnetsensor, SamplingFrequency);
sensorManager.registerListener(this,mGravity,SamplingFrequency);
I am a newbie in app development so any help would be appreciated.
Your device probably does not have gravity sensor. Check if it's available
if (mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null) {
Toast.makeText(ActivitySensor1Availability.this, "Gravity AVAILABLE", Toast.LENGTH_SHORT).show();
} else {
// Failure! No Gravity Sensor.
Toast.makeText(ActivitySensor1Availability.this, "Failure! No Gravity Sensor", Toast.LENGTH_SHORT).show();
}
I calculate decibels using the formula double dB = 20 * Math.log10(p/p0);
p = recorder.getMaxAmplitude()/51805.5336;
p0 = 0.0002;
But what this class does is representing the sound amplitude in a scale between 40 to 70, and it goes to 70 (maximum value) very easily, just tapping my fingers on the device.
final Runnable updater = new Runnable(){
public void run(){
updateTv();
};
};
final Handler mHandler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv = (TextView)findViewById(R.id.textView1);
tv.setText("Start");
startRecording();
if (runner == null)
{
runner = new Thread(){
public void run()
{
while (runner != null)
{
try
{
Thread.sleep(500);
Log.i("Noise", "Tock");
} catch (InterruptedException e) { };
mHandler.post(updater);
}
}
};
runner.start();
Log.d("Noise", "start runner()");
}
}
public void onResume()
{
super.onResume();
}
protected void updateTv() {
double decibel = Math.rint(100*getAmplitudeEMA())/100;
tv.setText("" + decibel + " dB");
AppLog.logString(Double.toString((getAmplitudeEMA())) + " dB");
}
private double getAmplitudeEMA() {
double p = getAmplitude()/51805.5336;
double p0 = 0.0002;
//mEMA = EMA_FILTER * amp + (1.0 - EMA_FILTER) * mEMA;
double mEMA2 = 20 * Math.log10(p/p0);
Log.i("MY", "" + recorder.getMaxAmplitude());
return mEMA2;
}
private double getAmplitude() {
if(recorder != null){
return recorder.getMaxAmplitude(); }
else
return 0;
}
private String getFilename(){
String filepath = Environment.getExternalStorageDirectory().getPath();
File file = new File(filepath,AUDIO_RECORDER_FOLDER);
AppLog.logString(filepath);
if(!file.exists()){
file.mkdirs();
}
AppLog.logString(file.getAbsolutePath() + "/" + System.currentTimeMillis() + file_exts[currentFormat]);
return (file.getAbsolutePath() + "/" + System.currentTimeMillis() + file_exts[currentFormat]);
}
private void startRecording(){
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(output_formats[currentFormat]);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(getFilename());
recorder.setOnErrorListener(errorListener);
recorder.setOnInfoListener(infoListener);
try {
recorder.prepare();
recorder.start();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
I have a SurfaceView in an Activity, and I want to open up a new Activity when something occurs in the SurfaceView(when you run out of lives - lives == 0). I've tried different things, but I keep having problems with it. If I stop my UIThread first, then of course it won't keep running and so won't be able to execute the startActivity statement. If I do start the activity, it freezes up on me and force closes - having to do with my UIThread I believe. Has anybody run into this problem before - and if so, do you have any idea how I might go about achieving this. At the very least, if I can't open up a new Activity, how could I CLOSE this current Activity (from inside the SurfaceView).
public class BoardView extends SurfaceView implements SurfaceHolder.Callback{
Context mContext;
// thread initialization
private BoardThread thread;
Thread timer;
Thread timer2;
// box variables
Bitmap box =
(BitmapFactory.decodeResource
(getResources(), R.drawable.box));
private int box_x = 140;
private int box_y = 378;
private int boxWidth = box.getWidth();
private int boxHeight = box.getHeight();
// storage
private Vector<Blossom> blossomVector = new Vector<Blossom>();
Iterator<Blossom> dataIterator = blossomVector.iterator();
// counters
private int blossomNum = 0;
private String score;
private int currentScore = 0;
private int lives = 3;
boolean mode = false;
boolean game = false;
OutputStreamWriter out = null;
FileOutputStream fOut = null;
private static final String TAG = "Debug";
final Paint scorePaint = new Paint();
public BoardView(Context context){
super(context);
scorePaint.setColor(Color.BLACK);
scorePaint.setTextSize(12);
scorePaint.setTypeface(Typeface.MONOSPACE);
//surfaceHolder provides canvas that we draw on
getHolder().addCallback(this);
//set up read/write data
File root = Environment.getExternalStorageDirectory();
File highscoresFile = new File(root, "highscores.txt");
// controls drawings
thread = new BoardThread(getHolder(),this, blossomVector, dataIterator, box_x, box_y,
boxWidth, boxHeight);
timer2 = new Thread(){
public void run(){
while(game == false){
uiCallback.sendEmptyMessage(0);
try{
Thread.sleep(5000); // change to be random
}
catch (InterruptedException e){
e.printStackTrace();
}
}
}
};
timer = new Thread(){
public void run(){
//makes sure the player still has 3 lives left
while(game == false){
uiCallback.sendEmptyMessage(0);
try {
Thread.sleep(2000); // wait two seconds before drawing the next flower
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //sleep for 2 seconds
}
}
};
timer.start();
timer2.start();
//intercepts touch events
setFocusable(true);
}
#Override
public void onDraw(Canvas canvas){
canvas.drawColor(Color.WHITE);
score = "SCORE: " + currentScore;
//note: pay attention to order you draw things
//don't change order or else blossoms will fall
//on top of box, not "into" it.
//display the scoreboard
canvas.drawText(score,240,420,scorePaint);
// uses a synchronized method to prevent concurrent modification
DrawBlossoms(canvas);
canvas.drawBitmap(box, box_x, box_y, null);
}
#Override
public boolean onTouchEvent(MotionEvent event){
//handles movement of box
if(event.getAction() == MotionEvent.ACTION_DOWN){
if(event.getX() > box_x & event.getY() > box_y &
event.getX() < box_x + boxWidth & event.getY() < box_y + boxHeight)
{
mode = true;
}
}
if(event.getAction() == MotionEvent.ACTION_MOVE) {
if(event.getX() > box_x & event.getY() > box_y &
event.getX() < box_x + boxWidth & event.getY() < box_y + boxHeight)
{
mode = true;
}
if(mode == true){
box_x = (int)event.getX();
}
}
if(event.getAction() == MotionEvent.ACTION_UP){
mode = false;
}
invalidate();
return true;
}
#Override
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height ){
Log.v(TAG, "Surface Changed");
//somehow these don't seem to be working
}
#Override
public void surfaceCreated(SurfaceHolder holder){
thread.startRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder){
Log.v(TAG, "Surface Destroyed");
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private Handler uiCallback = new Handler(){
public synchronized void handleMessage(Message msg){
//add a new blossom to the blossom Vector!!
blossomVector.add(new Blossom(
(BitmapFactory.decodeResource
(getResources(), R.drawable.blossom))));
dataIterator = blossomVector.iterator();
blossomNum++;
Log.v(TAG, "Number of Blossoms =" + blossomNum);
}
};
private synchronized void DrawBlossoms(Canvas c) // method to draw flowers on screen and test for collision
{
Canvas canvas = c;
dataIterator = blossomVector.iterator();
while (dataIterator.hasNext())
{
Blossom tempBlossom = dataIterator.next();
tempBlossom.Draw(canvas);
if (tempBlossom.hit(box_x,box_y, box_x + boxWidth, box_y + boxHeight, blossomVector) == true)
{
Log.v(TAG, "ITERATOR WORKS!");
dataIterator.remove();
currentScore += 100;
}
if (tempBlossom.dropped() == true)
{
dataIterator.remove();
Log.v(TAG, "Blossom dropped");
lives--;
}
if (lives == 0)
{
// stop the thread that makes blossoms
game = true;
//save the highscore
try {
File root = Environment.getExternalStorageDirectory();
if(root.canWrite()){
File highscoresFile = new File(root, "highscores.txt");
FileWriter writer = new FileWriter(highscoresFile);
BufferedWriter out = new BufferedWriter(writer);
//out.newLine();
out.write(score);
out.close();
}
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
File root = Environment.getExternalStorageDirectory();
File highscoresFile = new File(root, "highscores.txt");
FileReader reader = new FileReader(highscoresFile);
BufferedReader in = new BufferedReader(reader);
try {
String scoreTest = in.readLine();
Log.v(TAG, "Score: " + scoreTest);
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
Board Thread`public class BoardThread extends Thread {
private SurfaceHolder surfaceHolder;
private BoardView boardView;
private Vector<Blossom> blossomVector;
private int boxX;
private int boxY;
private int boxWidth;
private int boxHeight;
private boolean mrun =false;
private Iterator<Blossom> iterator;
private static final String TAG = "Debug";
public BoardThread(SurfaceHolder holder, BoardView boardView2,
Vector<Blossom> blossomVector1, Iterator<Blossom> dataIterator,
int box_x, int box_y, int boxW, int boxH) {
surfaceHolder = holder;
boardView=boardView2;
blossomVector = blossomVector1;
iterator = dataIterator;
boxX = box_x;
boxY = box_y;
boxW = boxWidth;
boxH = boxHeight;
}
public void startRunning(boolean run) {
mrun=run;
}
#Override
public void run() {
super.run();
Canvas canvas;
while (mrun) {
canvas=null;
try {
canvas = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
//update position
//Position(blossomVector, boxX, boxY, boxWidth, boxHeight);
// draw flowers
boardView.onDraw(canvas);
}
} finally {
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
private synchronized void Position(Vector<Blossom> blossomVector,int box_x, int box_y,
int boxWidth, int boxHeight)
{
//for(Blossom blossom: blossomVector)
iterator = blossomVector.iterator();
while (iterator.hasNext())
{
Blossom tempBlossom = iterator.next();
tempBlossom.UpdatePosition();
}
}
}
`
Sounds like the SurfaceView is running in a different thread than the main UI thread and can't modify the View objects. You'll want to create a Handler in your activity and make it accessible to your SurfaceView. Then you can send a message to the handler and it can update the UI (or launch a new activity) in the main UI thread.
I have the following main class and thread-TCP Client. The client runs in a loop, receives messages and passes it to main class. In the main class, I parse the message and try to show different images based on the name and value of the message received.
Ex: shiftDirection1
name: shiftDirection & value: 1
But I can show only the image corresponding to the first received message and the images corresponding to the remaining received messages cannot be displayed.
Please go through the code below and kindly suggest the mistake/problem and alternative ways.
Thank you for your time and efforts.
Madhu
main class:
public class TCPListen extends Activity implements TCPListener {
private TextView mTitle;
public String recData[] = new String[2];
String PresentGear = "0";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TcpServiceHandler handler = new TcpServiceHandler(this,this);
Thread th = new Thread(handler);
th.start();
}
public String[] callCompleted(String source){
//Log.d("TCP", "Std parser " + source);
//mTitle.setText(source);
//String data[] = new String[2];
//if (source.matches("<MSG><N>.*</N><V>.*</V></MSG>")) {
Document doc = null;
try{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
doc = (Document) db.parse(new ByteArrayInputStream(source.getBytes()));
NodeList n = doc.getElementsByTagName("N");
Node nd = n.item(0);
String msgName = nd.getFirstChild().getNodeValue();
NodeList n1 = doc.getElementsByTagName("V");
Node nd1 = n1.item(0);
String tmpVal = nd1.getFirstChild().getNodeValue();
recData[0] = msgName;
recData[1] = tmpVal;
if (recData[0].equals("currGear")) PresentGear = recData[1];
Log.d("TCP", "Inside Std parser " + recData[0] + " " + recData[1]);
actionOnData(recData[0], recData[1]);
}
catch(Exception e){
e.printStackTrace();
}
Log.d("TCP", "Just outside Std parser " + recData[0] + " " + recData[1]);
return recData;
//} else Log.d("TCP", "Message in wrong format " + source);
//mTitle.setText("Message in wrong format " + source);
//return data;
}
//Function to display driver messages/images based on individual messages
public void actionOnData(String name, String value) {
String tempName = name;
String tempVal = value;
setContentView(R.layout.image);
ImageView showImage = (ImageView) findViewById(R.id.imageView1);
//Log.d("TCP", "------------>" + tempName + " " + tempVal);
if (tempName.equals("shiftDirection") && tempVal.equals("1")) {
//setContentView(R.layout.image);
//TextView text_top = (TextView) findViewById(R.id.textView1);
//showImage = (ImageView) findViewById(R.id.imageView1);
//text_bottom.setText(Info[1]);
showImage.setImageResource(R.drawable.shift_up);
Log.d("TCP", "1------------>" + showImage);
} else if (tempName.equals("shiftDirection") && tempVal.equals("-1")) {
//setContentView(R.layout.image);
//TextView text_bottom = (TextView) findViewById(R.id.textView2);
//Resources res = getResources();
//Drawable drawable = res.getDrawable(R.drawable.shift_down);
//showImage = (ImageView) findViewById(R.id.imageView1);
//text_bottom.setText(Info[1]);
showImage.setImageResource(R.drawable.shift_down);
} else if (tempName.equals("recomGear") && tempVal != null) {
Log.d("TCP", "3------------>" + tempName + " " + tempVal);
Integer msgValue = Integer.parseInt(recData[1]);
//Integer CurrentGear = (msgValue) - 1;
//Log.d("TCP","in DA Images. Current gear: " + CurrentGear);
//String Gear = Integer.toString(CurrentGear);
setContentView(R.layout.image);
TextView text_top = (TextView) findViewById(R.id.textView1);
TextView text_bottom = (TextView) findViewById(R.id.textView2);
showImage = (ImageView) findViewById(R.id.imageView1);
showImage.setImageResource(R.drawable.shift_up);
text_bottom.setText(PresentGear);
text_top.setText(tempVal);
} else if (tempName.equals("currGear") && tempVal != null) {
Log.d("TCP", "4------------>" + tempName + " " + tempVal);
PresentGear = tempVal;
//Log.d("TCP","in DA Images. Present gear1: " + PresentGear);
setContentView(R.layout.image);
TextView text_bottom = (TextView) findViewById(R.id.textView2);
text_bottom.setText(PresentGear);
} else if (tempName.equals("shiftDirection") && tempVal.equals("0")) {
Log.d("TCP", "5------------>" + tempName + " " + tempVal);
Log.d("TCP","in DA Images. Present gear: " + PresentGear);
setContentView(R.layout.image);
TextView text_bottom = (TextView) findViewById(R.id.textView2);
//TextView text_top = (TextView) findViewById(R.id.textView1);
//text_top.setText("Go on");
text_bottom.setText(PresentGear);
}
}
}
Only the image corresponding to the first if case is displayed. The program control enters the second if loop but does not show the image there.
Interface:
public interface TCPListener {
public String[] callCompleted(String msg);
}
Thread (TCP Client):
public class TcpServiceHandler implements Runnable {
TCPListener _listener;
private Activity _act;
public BufferedReader in;
public TcpServiceHandler(TCPListener listener, Activity act){
_listener = listener;
_act = act;
}
public synchronized void run() {
// TODO Auto-generated method stub
//if(socket==null){
try {
//InetAddress serverAddr = InetAddress.getByName("192.168.178.25");
Socket socket = new Socket("192.168.62.23", 1200, true);
//
//while(true){
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
final int delay = 100;
final Timer _timer = new Timer();
_timer.scheduleAtFixedRate(new TimerTask() {
public void run(){
String str;
try {
str = in.readLine();
_listener.callCompleted(str);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, 0, delay);
//final String str = in.readLine();
//this._act.runOnUiThread(new Runnable(){
//public void run() {
// _listener.callCompleted(str);
// }
//});
}
catch(Exception e){
e.printStackTrace();
}
//}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
You might check 2 things:
Your TcpServiceHandler is a Runnable of a thread but there is no loop in run(). The _timer you define inside this method might be dead and gone before it's work is done.
Are you changing the UI from a background thread? This is not a good idea in general.
Check AsyncTask which is a handy tool to run operations in the background.