Android update TextView with Handler - android

I am having problems with updating the TextView, I used the Handler method to pass the message to the UI. My application receives data(type integers) true io stream and shows in TextView.
My Activity class looks like this:
public class DeviceView extends Activity {
TextView dataX;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.device_view);
dataX = (TextView) findViewById(R.id.datax);
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
dataX.setText(String.valueOf(msg.arg1));
}
};
}
}
I also have a separate class it extends Thread:
public class IOThread extends Thread {
public void run() {
byte[] buffer = new byte[1024];
int data;
while (true) {
try {
data = in.read(buffer);
Message message= Message.obtain();
message.arg1= data;
DeviceView.handler.sendMessage(message);
} catch (IOException ex) {
break;
}
}
}
}
Do I have to make a separate variable type String and point it to variable data and at last calling the count? Would that be enough to update TextView?

Can you try using an interface. Let the Activity implement it, pass it to the IOThread class. Once you get the result, pass the result to the Activity.
Interface named InterfaceData
public void getData(int data);
public class DeviceView extends Activity implements InterfaceData{
TextView dataX;
Handler handler;
IOThread ioThread;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.device_view);
handler = new Handler();
ioThread = new IOThread(this);
dataX = (TextView) findViewById(R.id.datax);
}
#Override
public void getData(int data){
handler.postDelayed(new Runnable(){
public void run(){
dataX.setText(data);
};
},100);
}
}
> Thread class
public class IOThread extends Thread {
InterfaceData interfaceData;
public IOThread(InterfaceData interfaceData){
this.interfaceData = interfaceData;
}
public void run() {
byte[] buffer = new byte[1024];
int data;
while (true) {
try {
data = in.read(buffer);
interfaceData.getData(data);
} catch (IOException ex) {
break;
}
}
}
}

I have found my problem it was not the Handler issue. THe code i posted at the beginning is coorect. The problem lyis on the way i read the received bytes[] array from the InputStream. I have tested by sending an integer int numbers = (int) 2 and when print this receivd data in terminal in Android app, it receivs only 1, even if i send int 3 or 4, i stil receive 1.
So i preceiated your example code #dcanh121 , but my question is actualy how do i read properly the integers that the server sends?
public void run() {
byte[] buffer = new byte[1024];
int data;
while (true) {
try {
data = in.read(buffer);
Log.d(TAG + data, "test");
Message message = Message.obtain();
message.arg1 = data;
Log.d(TAG + message.arg1, "test");
DeviceView.handler.sendMessageDelayed(message, 100);
} catch (IOException ex) {
Log.e(TAG_IOThread, "disconnected", ex);
break;
}
}
}

Related

Set text in thread class from activity

I have two classes, one is Activity, and one is Thread class:
Activity:
public class MainActivity extends AppCompatActivity {
ObjectInputStream inFromServer = null;
ObjectOutputStream outToServer=null;
Socket clientSocket = null;
String userName;
EditText message;
static TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
message = (EditText)findViewById(R.id.txtMessage);
textView = (TextView)findViewById(R.id.textView);
try {
clientSocket = new Socket("10.0.0.41", 10002);
outToServer =
new ObjectOutputStream(clientSocket.getOutputStream());
inFromServer =
new ObjectInputStream((clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
ReceiveMessages receiveMessages = new ReceiveMessages(inFromServer);
receiveMessages.start();
}
public void onClickSend(View view) throws IOException {
outToServer.writeObject("Eliran!" + message.getText().toString());
}
public void btnUserName(View view) throws IOException {
EditText editText = (EditText)findViewById(R.id.userName);
userName = editText.getText().toString();
outToServer.writeObject(userName + "!");
}
}
Thread class:
public class ReceiveMessages extends Thread {
ObjectInputStream inFromServer = null;
public ReceiveMessages(ObjectInputStream inFromServer)
{
this.inFromServer = inFromServer;
}
public void run() {
try {
while (true) {
String message = (String) inFromServer.readObject();
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
I want to set text in the text view of the activity in the Thread class.
How can I do it? InflateLayout isn't helping I think.
I would go about it by creating a Callback that gets called when the String is received from the aerver.
interface ReceiveMessageListener {
void onMessageReceived (String message);
}
Then have my Activity implement the interface and set the text in the onMessageReceived call back.
#Override
public void onMessageReceived (String message) {
runOnUiThread(new Runnable() {
#Override
public void run () {
textView.setText(message);
}
});
}
You'll also have to change the constructor for your MessageReceive class to take a MessageReceiveListener.
From your Activity:
ReceiveMessages receive = new ReceiveMessages(input, this);
Only the UI thread can interact with ui elements (such textview). Try using runOnOiThread or mainHandler.post ()

Get a string value out of a thread

I have a String variable, and I set it's value inside a thread, since it's using a netwok operation.
How can I access the values stored in the Strings?
public class HomeActivity extends AppCompatActivity {
// Initialize AWS DynamoDB Client
public static AmazonDynamoDBClient ddbClient;
public static DynamoDBMapper mapper;
public static Aqua aqua;
// App details
public static String a = "A";
public static String b;
public static Boolean c;
public static String d;
public static String e;
public static String f;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
// Initialize the Amazon Cognito credentials provider
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
getApplicationContext(),
"******", // Identity Pool ID
Regions.**** // Region
);
// Initialize AWS DynamoDB
ddbClient = new AmazonDynamoDBClient(credentialsProvider);
mapper = new DynamoDBMapper(ddbClient);
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
// Get app details
aqua = mapper.load(Aqua.class, a);
b = aqua.getB();
c = aqua.getC();
d = aqua.getD();
e = aqua.getE();
f = aqua.getF();
} catch (Exception e) {
Log.e("error", e.getMessage());
}
}
});
thread.start();
}
}
Use ExecutorService and submit Callable (below assumes you want the data that is stored inside b,c,d,e,f):
ExecutorService exec = Executors.newSingleThreadExecutor();
Future<String[]> future = exec.submit(new Callable<String[]>() {
#Override
public String[] call() {
try {
// Get app details
aqua = mapper.load(Aqua.class, a);
b = aqua.getB();
c = aqua.getC();
d = aqua.getD();
e = aqua.getE();
f = aqua.getF();
} catch (Exception e) {
Log.e("error", e.getMessage());
}
return new String[] {b, c, d, e, f};
}
});
// ... b will be at value[0], c at value[1]
String[] value = future.get();
Declare the string globally in your Activity/Fragment. This way you can acces it from everywhere.
You could also use handler.sendMessage(message); with your String as message to send it whenever your Thread has finished or whenever you want to. You can then retrieve your String int
protected Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
String status = (String) msg.obj;
Log.i("Got a new message", "MESSAGE: "+status);
}
};
Hope it helps :)

Read and Write to file in the same time

I want to write and read from file in the same time without errors.
For example, I will starting new Thread for writing to file from my running service.
In my activity i will starting new Thread for reading from the same file.
I wan't to do this synchronously. Some thing like this :
To wait execution of next thread until previous finished.
Next thread must not start until previous thread stops, irrespective of time consumption.
My code for read and write:
public static final String ROUTE_FILE_NAME = "route.txt";
public static void savePointToFile(Context context, String point) throws IOException {
FileOutputStream fOut = context.openFileOutput(ROUTE_FILE_NAME, Context.MODE_APPEND);
OutputStreamWriter osw = new OutputStreamWriter(fOut);
osw.write(point);
osw.flush();
osw.close();
}
public static String readRouteFromFile(Context context) {
StringBuffer fileContent = new StringBuffer(UIUtils.emptyString());
byte[] buffer = new byte[1024];
try {
FileInputStream fis = context.openFileInput(ROUTE_FILE_NAME);
int length;
while ((length = fis.read(buffer)) != -1) {
fileContent.append(new String(buffer));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return fileContent.toString();
}
Thanks in advance.
If you just want the read method called from a thread to wait for the write method called from another thread to be finished, and vice versa, just synchronize both methods on a common object:
private static final Object fileLock = new Object();
public static String readFile() {
synchronize(fileLock) {
[your current read code here]
}
}
public static void write(String data) {
synchronize(fileLock) {
[your current write code here]
}
}
You can look at a special thread pool executor service.
final ExecutorService threadpool = Executors.newSingleThreadExecutor();
Its fairly easy, just create runnables and put it in the threadpool. It contains a single thread so all your runnables are queued sequentially. Otherwise you could create a normal executorservice and set the threadpool to 1. Effectively its the same. Hope this helps
http://www.concretepage.com/java/newsinglethreadexecutor_java
So its like
WorkerThread.get(context).read()
WorkerThread.get(context).write()
You can even implement future calls instead of defining an explicit callback.
Just a general idea of how it can work. You need to save filepointers so you know where to pause and continue read/write. Other you will always start from the first data position in the file.
class WorkerThread {
interface Callback {
void onCompleteRead(String buffer, int pauseReadPointer);
void onCompleteWrite(int pauseWritePointer);
}
enum Action {
READ,
WRITE
}
private static WorkerThread singleton;
public static synchronized WorkerThread get(final Context context) {
if (instance == null) {
instance = new WorkerThread(context);
}
return instance;
}
private final Context context;
private final ExecutorService threadPool;
private WorkerThread(context) {
threadPool = Executors.newSingleThreadExecutor()
}
// PUBLIC READ CALL
public void read(int resumeReadPointer, Callback callback, "other params") {
queueJob(READ, null, resumeReadPointer, callback);
}
// PUBLIC WRITE CALL
public void write(String in, int resumeWritePointer, Callback callback, "other params") {
queueJob(WRITE, in, resumeWritePointer, callback);
}
private void queueJob(final Action action, String buffer, final int pointer, final Callback callback) {
/* Create handler in UI thread. */
final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
ResultPack pack = (ResultPack) msg.obj;
if (Action.READ == action) {
callback.onCompleteRead(pack.result, pack.pointer);
} else {
callback.onCompleteWrite(pack.pointer);
}
}
};
// single threadpool. everything is FIFO
threadPool.submit(new FileRunnable(action, buffer, handler, pointer));
}
private class ResultPack {
private final String result;
private final int pointer;
private ResultPack(String s, int p) {
this.result = s;
this.pointer = p;
}
}
private class FileRunnable implements Runnable {
private int pointer = 0;
private final Handler handler;
private final buffer = buffer;
FileRunnable(final Action action, String buffer, final Handler handler, final int pointer) {
this.pointer = pointer;
this.handler = handler;
this.buffer = buffer;
}
#Override
public void run() {
if (Action.READ == action) {
ResultPack pack = readRouteFromFile(..., pointer);
} else { // write
ResultPack pack = savePointToFile(..., buffer, pointer);
}
Message message = Message.obtain();
message.obj = pack;
handler.sendMessage(message);
}
}
}

Interaction with user on Thread cause my app crash [duplicate]

This question already has answers here:
Android "Only the original thread that created a view hierarchy can touch its views."
(33 answers)
Closed 7 years ago.
My app crashes if TextView.setText is inside Thread:
NOTE: The following class is inside of MainActivity.
private class StreamThread extends Thread {
public StreamThread() {
}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
String message = new String(buffer, 0, bytes);
//THIS IS IMPORTANT, READ THIS PLEASE
//I tested many times my app to find the problem, and I found, my app crashes when TextView.setText() is executed
//Here starts the problem
((TextView) findViewById(R.id.textView)).setText(message);
} catch (IOException e) {
break;
}
}
}
This should do the trick:
private class StreamThread extends Thread {
public StreamThread() {}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
String message = new String(buffer, 0, bytes);
runOnUiThread(new Runnable() {
#Override
public void run() {
((TextView) findViewById(R.id.textView)).setText(message);
}
});
} catch (IOException e) {
break;
}
}
}
}
Sooo, what was wrong?
Android's UI is single threaded.
This means you are not allowed to change the ui from another thread than the ui thread.
You can post changes to the ui thread using the runOnUiThread-Method or using a Handler.
Threads are designed for execute code by separated allowing another codes execute to the same time.
Unafortunately Threads are not compatible with UI, but I have a solution.
runOnUiThread(new Runnable() {
#Override
public void run () {
//Some stuff that needs to interact with the user (UI).
}
}
You must update visual components in the ui thread. For your purpose you should use an AsyncTask, Service or a Runnable which runs in the ui thread.
For example, you use an AsyncTask like in the following code:
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textview = (TextView) findViewById(R.id.textView);
new StreamAsyncTask(textview).execute();
}
private class StreamAsyncTask extends AsyncTask<Void, String, Void> {
private TextView textview;
public StreamAsyncTask(TextView textview) {
this.textview = textview;
}
#Override
protected Void doInBackground(Void... voids) {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
String message = new String(buffer, 0, bytes);
publishProgress(message);
} catch (IOException e) {
break;
}
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
textview.setText(values[0]);
}
}
}
Or you can use the Activity's method runOnUiThread:
runOnUiThread(new Runnable() {
#Override
public void run() {
((TextView) findViewById(R.id.textView)).setText(message);
}
});
The last way is easier to understand but the first one is more flexible.
Read about AsyncTasks: http://developer.android.com/reference/android/os/AsyncTask.html

Update UI Android

before writing this I looked at other post but have not found any solution, I would appreciate your help.
In the onCreate method of the class of the application launcher creates a thread TCPServer and display a table with information.
The problem is that this information varies and must be updated when the thread detects TCPServer have sent a new message control.
Then I show the code if I expressed myself well.
//launcher class
public class profesor extends Activity implements OnClickListener {
static TableLayout alumnsTable;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
.
.
.
Thread serverThread = new Thread(null, new TCPServer(), "BackgroundService");
serverThread.start();
.
.
.
//information is added to the table
alumnsTable = (TableLayout)findViewById(R.id.alumnsTable);
List<Alumnos> listaAlumnos = Alumnos.ReadList();
for(Alumnos al:listaAlumnos){
alumnsTable.addView(filaAlumno(al));
}
}
//Eliminates the above information and reloads the table with the new information
public void actualiza(){
alumnsTable.removeAllViews();
setContentView(R.layout.main);
alumnsTable = (TableLayout)findViewById(R.id.alumnsTable);
List<Alumnos> listaAlumnos = Alumnos.ReadList();
for(Alumnos al:listaAlumnos){
alumnsTable.addView(filaAlumno(al));
}
}
}
//TCPServer class
public class TCPServer implements Runnable {
private static Handler handler = new Handler();
public void run() {
ServerSocket serverSocket;
String file;
int filesizeMb = 4;
int filesize = filesizeMb * (1024 * 1024); // filesize temporary hardcoded
int bytesRead;
int current = 0;
try {
serverSocket = new ServerSocket(profesor.COMUNICATION_PORT);
Log.d(profesor.LOG_TAG,"S: Servidor Iniciado.");
while (true) {
final Socket sock = serverSocket.accept();
String ClientAddr=sock.getInetAddress().toString();
ClientAddr = ClientAddr.substring(ClientAddr.indexOf('/') + 1, ClientAddr.length());
final String contacto=DeviceList.getDeviceName(ClientAddr);
Log.d(profesor.LOG_TAG,"S: Conectado con: " + ClientAddr);
// Conection type
DataInputStream dis = new DataInputStream(sock.getInputStream());
final String connectionType =dis.readUTF();
Log.d(profesor.LOG_TAG,"S: Tipo de Conexion " + connectionType);
.
.
.
.
// RECEIVING CONTROL MESSAGE
if (connectionType.contains("CONTROL")) {
String ControlText =dis.readUTF();
String[] Control = ControlText.split(":");
Log.d(profesor.LOG_TAG,"S: Recibido nuevo progreso de prueba. IP: "+Alumnos.getIdAlumno(ClientAddr)+"->"+Integer.parseInt(Control[0])+" ->"+Integer.parseInt(Control[1]));
Alumnos.setProgress(Alumnos.getIdAlumno(ClientAddr), Integer.parseInt(Control[0]), Integer.parseInt(Control[1]));
/****************************************************/
//Here is where I need to call the update method of the
//class teacher to delete the old data and fill the table
//again.
/****************************************************/
}
dis.close();
sock.close();
}
} catch (IOException e) {
Log.d(profesor.LOG_TAG, "IOException"+e);
e.printStackTrace();
}
}
}
Can anyone give me some idea?, I have seen examples handlers but not in a class declaration and the call in another.
I hope that you understand what I mean, my English is not very good.
Thanks for the help
You can try to create the TCPServer with a Handler or Activity references and then use it when you want to update the UI:
refHandler.post(new Runnable(){
public void run() {
//Update
}
});
refActivity.runOnUiThread(new Runnable() {
public void run() {
//Update
}
});
use runOnUiThread for updating ui from Thread:
// RECEIVING CONTROL MESSAGE
if (connectionType.contains("CONTROL")) {
String ControlText =dis.readUTF();
String[] Control = ControlText.split(":");
Log.d(profesor.LOG_TAG,"S: Recibido nuevo progreso de prueba. IP: "+Alumnos.getIdAlumno(ClientAddr)+"->"+Integer.parseInt(Control[0])+" ->"+Integer.parseInt(Control[1]));
Alumnos.setProgress(Alumnos.getIdAlumno(ClientAddr), Integer.parseInt(Control[0]), Integer.parseInt(Control[1]));
/****************************************************/
//Here is where I need to call the update method of the
//class teacher to delete the old data and fill the table
//again.
/****************************************************/
profesor.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// refresh ui here
}
});
}

Categories

Resources