Pass a Message From Thread to Update UI - android

Ive created a new thread for a file browser. The thread reads the contents of a directory. What I want to do is update the UI thread to draw a graphical representation of the files and folders. I know I can't update the UI from within a new thread so what I want to do is:
whilst the file scanning thread iterates through a directories files and folders pass a file path string back to the UI thread. The handler in the UI thread then draws the graphical representation of the file passed back.
public class New_Project extends Activity implements Runnable {
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Log.d("New Thread","Proccess Complete.");
Intent intent = new Intent();
setResult(RESULT_OK, intent);
finish();
}
};
public void fileScanner(){
//if (!XMLEFunctions.canReadExternal(this)) return;
pd = ProgressDialog.show(this, "Reading Directory.",
"Please Wait...", true, false);
Log.d("New Thread","Called");
Thread thread = new Thread(this);
thread.start();
}
public void run() {
Log.d("New Thread","Reading Files");
getFiles();
handler.sendEmptyMessage(0);
}
public void getFiles() {
for (int i=0;i<=allFiles.length-1;i++){
//I WANT TO PASS THE FILE PATH BACK TU A HANDLER IN THE UI
//SO IT CAN BE DRAWN.
**passFilePathBackToBeDrawn(allFiles[i].toString());**
}
}
}

It seems passing simple messages is int based... What I needed to do was pass a Bundle
using Message.setData(Bundle) and Message.getData(Bundle)
So Happy =0)
//Function From Within The Thread
public void newProjectCreation() {
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putString("Test", "test value");
msg.setData(bundle);
handler2.sendMessage(msg);
}
//Handler in The UI Thread Retreieves The Data
//And Can Update the GUI as Required
private Handler handler2 = new Handler() {
#Override
public void handleMessage(Message msg) {
Bundle bundle = msg.getData();
Toast.makeText(New_Project.this,bundle.getString("Test"),Toast.LENGTH_SHORT).show();
}
};

Check out AsyncTask for this kind of stuff. It's really much more elegant than rolling your own handler and passing messages back and forth.
http://developer.android.com/reference/android/os/AsyncTask.html

Related

in android how to recycle message after sending it to another thread

I am creating two threads A and B both are ofcourse non-GUI threads.
A wants to send message to thread B.
A has the handler reference of thread B.
When A has called handler.sendMessage(msg). Should it be the responsibility of A to call recyle on it ?
Or should the thread B in the handleMessage() after unpacking the msg, call recyle on it ?
I have taken a look at the documents but its not so clear..
Thread B looks like this
class B extends Thread {
public Handler mHandler;
public Handler getHandler()
{
return mHandler;
}
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
Thread A sends message to thread B like this
Bundle b = new Bundle();
b.putString("message", "hello world");
msg.setData(b);
msThread.getHandler().sendMessage(msg);

Handler wont SetText on Button

In my Application I am trying to simply setText() on my Button purchaseButton.
I have an Alert Dialog that takes a value and initializes an AsyncTask to complete the server call to find the discount.
All of that works fine, its when I get to the onPostExecute().
onPostExecute():
protected void onPostExecute(String result) {
Log.d(tag,"Result of POST: " + result);
if(result != null){
if(result.equals("NO")){
createAlert(1);
}else{
result = result.replaceAll("YES", "");
String discount = result;
discountPrice = price - Double.parseDouble(discount);
Log.d(tag, "Discount price after pull:" + discountPrice);
//setPurchase("Purchase $" + String.valueOf(discountPrice));
new Thread(new Runnable()
{
#Override
public void run()
{
Message msg = handler.obtainMessage();
msg.what = (int) discountPrice;
handler.sendMessage(msg);
}
}).start();
}
}
You can see that I make a call to a handler from a new Thread(). This allows me to get to the handler but never sets the text of the button from the handler.
Handler Method:
final static Handler handler = new Handler(){
#Override
public void handleMessage(Message msg){
Log.d(tag, "entered handler");
if(msg.what == discountPrice)
{
setPurchaseText(msg.what);
}
}
};
setPurchaseText() method:
private static void setPurchaseText(int value){
Log.d(tag, "Entered setPurchaseText");
purchaseButton.setText("Purchase $" + String.valueOf(value));
}
From my knowledge this should allow me to set the text from the handler. Why is it not setting the text and how can I get it to set the text with my string value?
Any help is much appreciated!
If the setText() is not working in onPostExecute(), they you might not be creating your AsyncTask on the UI thread. AsyncTask runs onPostExecute() on the thread you create it.
Again, Handler is created on the currently executed Thread. May be your Handler is initialized on a background thread. Try using final static Handler handler = new Handler(Looper.getMainLooper()). This ensures the handler to be attached to the main thread.

Sending Message from Service to Activity

I have a Service and i try to send message to my primary Activity just like this:
public void callAsynchronousTask() {
final Handler handler = new Handler();
Timer timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
try {
Message m = new Message();
m.arg1 = 10;
m.arg2 = 15;
handler.sendMessage(m);
Log.i("Sent", "!");
} catch (Exception e) {}
}
});
}
};
timer.schedule(doAsynchronousTask, 0, 3000);
}
How can i fetch this message data in my Activity ?
In your activity, you should make a handler like this, and pass the reference to the handler to the service before you start it...
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
//msg.arg1
}
};
but right now you are creating a handler inside the service but thats not what you wanted to do!
Another way would be to bind your Activity to your Service so that they can communicate.
Reference
http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int)
put your data in message.obj and take it from this field in your activity. Your data can be a class that you can define how you want it.
There is simple example project (which is created by CommonsWare) which shows how to send messages from Service to Activity via Handler. Check it out
//use this code to send data to activity
Bundle data = new Bundle();
data.putString("data", result);
Message msg = Message.obtain();
msg.setData(data);
replyTo.sendMessage(msg); //replyTo is handler declared in your main_Activity
//Pass this **replyTo** handler when you call your service from mainActivity..
Handler replyTo= new Handler() {
public void handleMessage(Message msg) {
//get data here and do what you want..
};
};
Hope it helps..!

Android thread encapsulation, cannot get changing variables from the encapsulated class

I am quite new to Android and Java. Basically, I would like to realize an encapsulation of a background thread of Android, and inside this background thread, I have an infinite loop which will periodically take some operations of getting data(like from Internet, or from some hardware devices).
The encapsulated class must provide only a function like getData() for others to get data. But everytime when i call this getData() function from other classes, it never gives me the changing values, but only the initialized values.
I've studied both of the AsyncTask, Handler and Message ways to realize multithread. And both of them give me the initialized values.
Here is the encapsulated class of Handler and Message:
public class getDataFromUSB{
private int usb_data;
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what==1){
usb_data=msg.arg1;
}
}
};
private Thread thread = new Thread(){
#Override
public void run(){
while(!Thread.currentThread().isInterrupted())
{
int a=read_usb();
Message msg = new Message();
msg.arg1 = a;
msg.what = 1;
handler.sendMessage(msg);
try {
Thread.sleep(15);
} catch (InterruptedException e) {
System.err.println("");
this.interrupt();
}
}
}
};
public void start(){
thread.start();
}
public int get_data(){
return usb_data;
}
public int read_usb()
{
int a=10;
return a;
}
}
And then in another class, here is the code of calling getDataFromUSB:
getDataFromUSB usb1= new getDataFromUSB();
usb1.start();
int a=usb1.getData();
Log.e(TAG,"a = " +a);
Then everytime i call this usb1.getData(), the value is always 0. I don't understand why.
Now I proceed to do some more realistic things. I add an object of random in my getDataFrom USB class to provide different numbers, I also change the way of assigning values to usb_data, I think it's better to do it just in the background thread, there is no need to move it to the handlemessage. So it becomes:
public class getDataFromUSB{
private int usb_data;
private Random random = new Random(555L);
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
private Thread thread = new Thread(){
#Override
public void run(){
while(!Thread.currentThread().isInterrupted())
{
int a=read_usb();
usb_data=a;
Message msg = new Message();
handler.sendMessage(msg);
}
}
};
public void start(){
thread.start();
}
public int get_data(){
return usb_data;
}
public int read_usb()
{
return random.nextInt();
}
}
Then I call it from another class like what Nikita suggested:
Handler h = new Handler();
for (int i=0;i<20;i++){
h.postDelayed(new Runnable() {
public void run() {
int data=usb1.get_data();
Log.e(TAG,"data= " +data);
}
},500);
}
The strange thing is that it then gives sometimes all the same numbers, sometimes several some numbers, sometimes all different numbers. As I understand, the usb_data has always been changed inside the background thread, so we are not obliged to wait for handlemessage to proceed. Everytime I call getData(), it should give me the newest value. Isn't that right?
The problem might be following: you run your code from main UI thread. When you new start thread - it sends message to handler. This message is added to main thread's queue and will be processed in main thread when it finishes it's current job. Currently main thread runs your code and there is no chance that message will be processed before you call usb.getData().
To check whether your update thread works properly you can post delayed runnable that will print value of usb1.getData():
final getDataFromUSB usb1= new getDataFromUSB();
usb1.start();
Handler h = new Handler();
h.postDelayed(new Runnable() {
public void run() {
int a=usb1.getData();
Log.e(TAG,"a = " +a);
}
}, 500); // Waits 500 milliseconds and runs runnable on current thread.

Android: handler not working

I am trying to load an object from a server in Android. This object is loaded in a thread. When loading is finished, an _objectHandler is called to get some key - values from the object, for example, the _filename key. Every time a filename is retrieved, I want to display it. For this reason, I am looping over the element of the loaded object in a second thread, and calling a _handler every time a value is loaded. What I want to get is all the _filename values, but what I am getting is only the last value of the _fielName. what I am doing wrong?
ArrayList <myObject> object;
String filename;
Thread thread = new Thread (MyActivity.this);
thread.start();
public void run() {
Looper.prepare();
try {
object = getObjectFromServer();
} catch (Exception e) {
e.printStackTrace();
}
_objectHandler.sendEmptyMessage(0);
Looper.loop();
}
Handler _objectHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
for (int i = 0; i < object.size(); i++) {
myObject obj= object(i);
new Thread(new Runnable() {
public void run() {
filename= obj.getFileName();
Message msg = new Message();
_handler.sendEmptyMessage(0);
}
}).start();
}
}
};
Handler _handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Log.i("The fielname is ", " filename" + filename
}
};
you can use android.os.Handler class. This will provide you a mechanism for enqueue an action to be performed on a different thread than your own.

Categories

Resources