I'm making an app which establishes USB communication between an Arduino UNO R3 and an android tablet. Arduino board is sending data correctly and it is even being received by tablet correctly and when tried to display, the text does get printed but with a rather continuous flicker.
class MyThread extends Thread
{
#Override
public void run()
{
mCallback = new UsbSerialInterface.UsbReadCallback()
{ //Defining a Callback which triggers whenever data is read.
#Override
public void onReceivedData(byte[] arg0) //data received in bytes
{
String data = null;
try
{
data = new String(arg0, "UTF-8");
handler.post(new newthread(data));
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
}
};
}
}
class newthread implements Runnable
{
String str1;
public newthread(String STR1)
{
str1 = STR1;
}
#Override
public void run()
{
DoseRateDisplay = (TextView) findViewById(R.id.DoseRateDisplay);
if(str1.contains("L"))
{ tv6.append("Health OK"); }
else
{
DoseRateDisplay.settext(str1);
}
}
}
I think the reason for flicker can be that the data is incoming too fast. Using Thread.sleep does not help. What can be the possible solution to this problem ? Also, using append instead of settext doesn't cause any flickering problems, but then data gets appended to textview.
From my comment: try to check if the text received and the text already in the TextView are equal:
if(!DoseRateDisplay.getText().toString().equals(str1)) {
DoseRateDisplay.settext(str1);
}
Related
I need to make an app which, when a button is pressed, a character is sent to Arduino via Bluetooth with a delay of 50ms. I'm new to Android and surfing on the internet I found this solution:
base_destra.setOnHoverListener(new View.OnHoverListener() {
#Override
public boolean onHover(View v, MotionEvent event) {
while(event.getAction() == MotionEvent.ACTION_DOWN){
sendData("d");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(event.getAction() == MotionEvent.ACTION_UP){
sendData("10");
}
return false;
}
});
Where sendData is this:
private void sendData(String data){
if(OutStream == null){
return;
}
byte[] comando = data.getBytes();
try {
OutStream.write(comando);
}
catch (IOException e){
Toast.makeText(getBaseContext(),"Errore: comando non mandato",Toast.LENGTH_SHORT).show();
}
}
I saw a tutorial on YouTube but although I copy-pasted the code shown, the app doesn't send anything.
PS: Arduino and the phone are correctly connected.
PPS: sorry for my bad English.
You can use a Timer. In the toggle button onClick method you can call timedDataSender() and in the button off method you can set shouldCancel boolean variable to true and the sending task should be finished. Here is a sample code:
/* A sendTimer is used to periodically send data */
private Timer sendTimer;
private Boolean shouldCancel = false;
private void timedDataSender(){
TimerTask task = new TimerTask() {
public void run() {
runOnUiThread(new Runnable(){
#Override
public void run() {
sendData("10");
}
});
if(shouldCancel)
cancel();
}
};
sendTimer = new Timer("Timer");
/* TimerTask, startDelay, period */
sendTimer.scheduleAtFixedRate(task,0,50);
}
I'm making an app in Android Java, using Android Studio.
Every 0.1 seconds I want to update the text within a certain TextView.
I already managed to use a Handler to execute a method every 0.1 seconds (100 ms), but it doesn't automatically update the TextView.
It only updates the TextView to what I want when the user interacts with the app. It only updates it when, for example, the user slides the SeekBar or presses a button. It doesn't update when the user clicks on the screen, and not automatically without input either.
How can I make it such that it will update the value automatically, without user input?
Thanks in advance.
P.S: I'm new to Android and Java, and I'm using threads to get the value, in xml format, from a website.
Should I post any code, and if so, what exactly?
you can try updating the value of text view on the UI thread.
runOnUiThread(new Runnable() {
#Override
public void run() {
//update TextView here
}
});
Thread t = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(100);
runOnUiThread(new Runnable() {
#Override
public void run() {
// update TextView here!
}
});
}
} catch (InterruptedException e) {
}
}
};
t.start();
You can update your textview using thread also, like this.
int prStatus = 0;
new Thread(new Runnable() {
public void run() {
while (prStatus < 100) {
prStatus += 1;
handler.post(new Runnable() {
public void run() {
tv.setText(prStatus + "/");
}
});
try {
Thread.sleep(150);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(prStatus == 100)
prStatus = 0;
}
}
}).start();
In the below code I am trying to run a thread when a button is clicked. In the button listener I create a new thread and run it...but at run time, when the button is pressed, the button itself freezes and the app does not respond and I receive ANR dialog. Moreover, when the socket is connected successfully even the TexView
mtvStatus.setText("RFC-SOCKET CONNECTED");
displays nothing.
Please let me know why this is happening.
button listener:
this.mbtnConnect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
BluetoothSocket rfcSocket = mSPPCtrl.rfcConnect();
if (rfcSocket.isConnected()) {
mtvStatus.setText("RFC-SOCKET CONNECTED");
Thread rx = new Thread(new RxRun(rfcSocket));
rx.run();
} else {
mtvStatus.setText("RFC-SOCKET NOT CONNECTED");
}
}
});
runnable class
private class RxRun implements Runnable {
private BluetoothSocket mRFCSocket = null;
private OutputStream mRFCOS = null;
private InputStream mRFCIS = null;
public RxRun(BluetoothSocket rfcSocket) {
this.mRFCSocket = rfcSocket;
try {
this.mRFCOS = rfcSocket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
try {
this.mRFCIS = rfcSocket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
try {
this.mRFCOS.write(DIRON.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
while (this.mRFCSocket.isConnected()) {
try {
int readBytes = this.mRFCIS.read(new byte[5120]);
Log.d(TAG, CSubTag.bullet("RxRun", "readBytes:" + readBytes));
//mtvRx.setText(""+readBytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
...when the button is pressed, the button itself freezes and the app does not respond and I receive ANR dialog. Moreover, when the socket is connected successfully even the TexView displays nothing.
It's expected, because you haven't actually started the rx thread. Here is what is going on:
mSPPCtrl gets connected,
mtvStatus's text is set to "RFC-SOCKET CONNECTED", but you cannot visually see it because
run() method of the RxRun instance is called manually where the loop while (this.mRFCSocket.isConnected()) may last as long as the socket is connected.
All the above said is invoked on UI-thread and that's the reason of ANR.
You should not call run() manually. Start the rx thread with
rx.start();
Also I highly recommend to move all the rfcSocket logic inside of the thread and notify the UI-thread on success/failure of connection.
EDIT
Here is one the option mentioned in my comment.
Start the rx thread on a button click
this.mbtnConnect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Thread(new RxRun(rfcSocket)).start();
}
});
Move your logic inside of the run() method:
public void run() {
BluetoothSocket rfcSocket = mSPPCtrl.rfcConnect();
if (rfcSocket.isConnected()) {
mtvStatus.post(new Runnable() {
#Override
public void run() {
mtvStatus.setText("RFC-SOCKET CONNECTED");
}
});
} else {
mtvStatus.post(new Runnable() {
#Override
public void run() {
mtvStatus.setText("RFC-SOCKET NOT CONNECTED");
}
});
return;
}
// the rest of your logic
}
Some links that might help:
Android documentation on Threads
SO question Android basics: running code in the UI thread
another SO post on Update UI from Thread
The error here is really simple - do not use run() on the Thread instance, as this will actually run it's Runnable on the current Thread! Use start() and it will work fine :-)
Sorry for my bad english,
I'm doing a project for school where i have to move a vehicle via WiFi with an Android App. I achieved my goal but I got surprised to see that, most of the times when I pressed any button, my vehicle took some time to actually do something. On the other hand, when I press any button a few times quickly, the events stack, and after, even when I'm not pressing any button, the vehicle moves. Needless to say, both are several problems. Is there any way to fix them?.
The Android App conects via REST API to an Arduino Yun. With each touch on a button i'm making an HTTP Request in order to move the vehicle Forward, Backwards, Left or Right.
Here's my code (Despite the spanish, I think it's understandable):
public class MainActivity extends Activity {
private Button boton1,
boton2,
boton3,
boton4;
private String valor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
configuracion();
}
public void configuracion(){
StrictMode.ThreadPolicy policy = new StrictMode.
ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
establecerBotones();
try{
definir("continua/0/0");
definir("direccion/0/0");
}
catch(Exception e){
Alerta();
}
}
public void establecerBotones(){
boton1= (Button)findViewById(R.id.boton1); //all buttons do something similar
boton1.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch(action){
case MotionEvent.ACTION_DOWN:
v.setPressed(true);
conectar("continua/1/0");
break;
case MotionEvent.ACTION_OUTSIDE:
case MotionEvent.ACTION_UP:
v.setPressed(false);
try {
conectar("continua/0/0");
} catch (Exception e) {
}
break;
}
return true;
}
});
boton2= (Button)findViewById(R.id.boton2);
boton2.setOnTouchListener(new OnTouchListener() {
});
boton3= (Button)findViewById(R.id.boton3);
boton3.setOnTouchListener(new OnTouchListener() {
});
boton4= (Button)findViewById(R.id.boton4);
boton4.setOnTouchListener(new OnTouchListener() {
});
}
private void conectar(final String selector) {
new Thread() {
#Override
public void run() {
try {
// code runs in a thread
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
definir (selector);
} catch (Exception e) {
System.out.println("holi");
}
}
});
} catch (final Exception ex) {
}
}
}.start();
}
public void definir(String selector) throws Exception{
valor = "http://192.168.240.1/arduino/" + selector;
URL url = new URL(valor);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
leer(in);
}
finally {
urlConnection.disconnect();
}
}
public void leer(InputStream in) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
if ((reader.readLine()) != "1") throw new IOException();
//Arduino is programmed to print "1" when connection succedes
}
public void Alerta(){
Context context = getApplicationContext();
CharSequence text = "Conexion erronea";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
PD: I'm kind of a beginner at programming, and I started learning java (and android) purely on my own this year. I'm probably doing some "dumb" errors on my code. I would appreciate any help or advice. Thank you for reading.
You have a problem with the code, as mentioned in comments. Android behaves badly if you do things that take any time on the UI thread. You need to move external connections onto a separate thread and find a way to communicate through it. As a newbie programmer you are going to find this hard, but there are lots of code samples around to help.
But this (and the code you posted) has nothing to do with your real problem. You have an "open loop" control mechanism and you need to close the loop. You need a way for the controlled device to respond with some information about whether it has moved or is moving, and you need to modify your control strategy accordingly.
Alternatively, you can send more complex commands to the vehicle (like "left 3" or "straight ahead") and leave the loop monitoring to the vehicle's on-board processor.
These are all common problems and you will find plenty of general reading material with very little searching. When you have very specific questions, Stack Overflow may be able to help better.
I'm trying to make a simple little program that will increment a number once a second. In this case, I'm implementing a thread that should loop once per second and add 1 to "potato" each time it loops. This works fine until it gets back to the display method potatoDisp(). For some reason this causes my app to crash. Removing potatoDisp() from run() fixes the problem, but the display is not updated as "potato" increases.
public int potato = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
potatoDisp();
start();
}
public void potatoDisp() {
TextView text = (TextView) findViewById(R.id.textView1);
text.setText("You currently have " + potato + " potatoes");
}
public void start() {
Thread thread = new Thread(this);
thread.start();
}
#Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return;
}
potato++;
potatoDisp();
}
}
I'm doing this for an Android app, if that helps. I've tried searching for an answer but I'm pretty lost when it comes to the proper way to work threads.
You need a runnable / handler like this:
private Runnable potatoRun = new Runnable() {
#Override
public void run () {
potatoDisp();
}
};
then change
potatoDisp();
to:
runOnUiThread(potatoRun);
You can't update the views when you're not on the UI thread.
You are probably getting an exception for updating the UI in the background. Since, potatoDisp(); is called from a background Thread but that function updates the UI it will give you problems. You need to call it with runOnUiThread().
#Override
public void run() {
while (true) {
try
{
Thread.sleep(1000);
} catch (InterruptedException e) {
return;
}
potato++;
runOnUiThread(new Runnable()
{
#Override
public void run()
{
potatoDisp();
}
});
}
}
Something like this should work.
The issue is that you are trying to update the UI (calling text.setText(...)) on a thread other than the main UI thread.
While I would suggest using a TimerTask instead of calling Thread.sleep(...), there are two main ways to edit your current code to work as expected.
-- Use a Handler
Define a Handler class that will accept messages and update your UI as needed. For example:
private final String POTATO_COUNT = "num_potatoes";
Handler handler = new Handler() {
public void handleMessage(Message msg) {
int numPotatoes = msg.getData.getInt(POTATO_COUNT);
mText.setText("You currently have " + numPotatoes + " potatoes");
}
}
Then in your code where you want to call your handler to update your text view, whether or not you are on the main UI thread, do the following:
Bundle bundle = new Bundle();
bundle.putInt(POTATO_COUNT, potato);
Message msg = new Message();
msg.setData(bundle);
handler.sendMessage(msg);
-- Call runOnUiThread(...)
#Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return;
}
potato++;
runOnUiThread(new Runnable()
{
public void run()
{
potatoDisp();
}
}
}
}
I think you should be using Async Task to update the UI from a thread: http://developer.android.com/reference/android/os/AsyncTask.html