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..!
Related
I create a static Handler to change some UI texts and plots in an activity. There is a timer created in a bluetooth service. Every second it will check the database for last message and update the time. For example, message comes in 1 second ago 2 seconds ago 3 seconds ago... I store the time when last message came in as yyyy/mm/dd hh:mm:ss a java Date long value.
My problem is at a line where "if (HomeActivity.mHandler != null) {" in the service class below, it gives an error "Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()". This happens when I shut down and restart the phone. The ACTION_BOOT_COMPLETED is catch and trying to run that code, then it throws exception. Does anyone know how to fix it?
Here is my codes:
Activity:
public class HomeActivity extends Activity {
public static Handler mHandler = new Handler() {
public void handleMessage(final Message msg) {
super.handleMessage(msg);
final Bundle bundle = msg.getData();
...
}
};
}
Service:
public class BluetoothLeService extends Service {
#Override
public void onCreate() {
// doing some other bluetooth stuffs here
...
int ONE_SECOND = 1*1000;
Timer updateTimer = new Timer();
updateTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
try {
if (HomeActivity.mHandler != null) { // error
final Message msg = HomeActivity.mHandler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putString("input", "update");
msg.setData(bundle);
HomeActivity.mHandler.sendMessage(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}, 0, ONE_SECOND);
}
Broadcast:
public class BluetoothBroadcast extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
Intent i = new Intent(context, BluetoothLeService.class);
context.startService(i);
}
}
}
AndroidManifest:
<!-- Start the service when phone is boot. -->
<receiver android:name="com.example.BluetoothBroadcast" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
probably should be closer to this:
private void createHandler() {
Thread thread = new Thread() {
public void run() {
Looper.prepare();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
// Do Work
handler.removeCallbacks(this);
Looper.myLooper().quit();
}
}, 2000);
Looper.loop();
}
};
thread.start();
}
I have an application which starts a new service. In this service I currently have a handler that does some work every minute and then sends the results to the main activity through a BroadcastReceiver. I want the following thing: Every minute create a new thread inside the service, make it do the work and send a message to the handler that it is finnished and then the handler will send to the main activity through a BroadcastReceiver. How can i combine the Thread and the Handler? Here is what I have so far -only part of code of interest-
private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
try {
getAppResources(); //this is the work i want to place in a new thread
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
intent.putExtra(key,value);
sendBroadcast(intent);
handler.postDelayed(this, 60*1000);
}
};
Here is what i understand i need to do
private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
/* try {
getAppResources();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
Thread t = new Thread() {
#Override
public void run(){
try {
getAppResources();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
handler.sendEmptyMessage(0);
}
};
handler.postDelayed(this, 60*1000);
}
};
And where do i place the handleMessage ? If i place it inside the Runnable it says it is never used locally. I just place it right before the Runnable ?
public void handleMessage(Message msg){
if(msg.what == 0){
intent.putExtra(key,value);
sendBroadcast(intent);
}
}
Is this how I should do it ?
EDIT: Handler code that sends to the main activity some data
private final Handler handler = new Handler(){
public void handleMessage(Message msg){
if(msg.what == 0){
Log.d("HANDLE","Am primit mesaj");
//Notify preparations
intent.putExtra("RunningApps", runningApps.size());
intent.putExtra("CPU", highestDrainPackageCPU);
intent.putExtra("GPS",highestDrainPackageGPS);
intent.putExtra("WIFI", highestDrainPackageWIFI);
//Now i have all my data, time to send them to the activity
//First , send the strings to be set in the TextViews
//Each running app has 7 messages to display -> ArrayList<String>
for(int i=0;i<runningApps.size();i++){
intent.putStringArrayListExtra(String.valueOf(i), appInfo.get(i));
}
//Next send values to plot the chart
//CPU energy consumption for highest draining application
double [] currValues_cpu = new double[tableCPU.get(highestDrainPackageCPU).size()];
Log.d("CPUSIZE",String.valueOf(currValues_cpu.length));
for(int j=0;j<tableCPU.get(highestDrainPackageCPU).size();j++){
currValues_cpu[j]=tableCPU.get(highestDrainPackageCPU).get(j);
Log.d("CPUVALUE",String.valueOf(currValues_cpu[j])+"For application"+highestDrainPackageCPU);
}
intent.putExtra("highestDrainPackageCPU", currValues_cpu);
//GPS energy consumption for highest draining application
double [] currValues_gps = new double[tableGPS.get(highestDrainPackageGPS).size()];
for(int j=0;j<tableGPS.get(highestDrainPackageGPS).size();j++){
currValues_gps[j]=tableGPS.get(highestDrainPackageGPS).get(j);
}
intent.putExtra("highestDrainPackageGPS", currValues_gps);
//WIFI energy consumption for highest draining application
double [] currValues_wifi = new double[tableWIFI.get(highestDrainPackageWIFI).size()];
for(int j=0;j<tableWIFI.get(highestDrainPackageWIFI).size();j++){
currValues_wifi[j]=tableWIFI.get(highestDrainPackageWIFI).get(j);
}
intent.putExtra("highestDrainPackageWIFI", currValues_wifi);
sendBroadcast(intent);
}
}
};
Here is the BroadcastReceiver in the Main Activity and the UpdateUI function:
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateUI(intent);
}
};
public void updateUI(Intent intent){
resourceTab.removeAllViews();
//statisticsTab.removeAllViews();
int apps_no = intent.getIntExtra("RunningApps", 0);
String highestDrainPackageCPU = intent.getStringExtra("CPU");
String highestDrainPackageGPS = intent.getStringExtra("GPS");
String highestDrainPackageWIFI = intent.getStringExtra("WIFI");
//TO-DO: Get information for each app and store it in textview.Then add it to a linearlayout
for(int i=0;i<apps_no;i++){
//Setup delimiter
View delimitator = new View(this);
delimitator.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,1));
delimitator.setBackgroundColor(Color.parseColor("#50FFFFFF"));
//Extract values
ArrayList<String> info = new ArrayList<String>();
info=intent.getStringArrayListExtra(String.valueOf(i));
for(int j=0;j<info.size();j++){
TextView infoApp = new TextView(this);
//////Setup textview//////////
infoApp = new TextView(this);
infoApp.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
infoApp.setTextColor(Color.parseColor("#FFFFFF"));
infoApp.setText(info.get(j));
resourceTab.addView(infoApp);
}
//Add delimiter
resourceTab.addView(delimitator);
}
double [] cpu_values = intent.getDoubleArrayExtra("highestDrainPackageCPU");
double [] gps_values = intent.getDoubleArrayExtra("highestDrainPackageGPS");
double [] wifi_values = intent.getDoubleArrayExtra("highestDrainPackageWIFI");
//Now plot the graph
createGraphOverall(cpu_values, gps_values, wifi_values, highestDrainPackageCPU, highestDrainPackageGPS, highestDrainPackageWIFI);
//Update the table
updateTable(cpu_values, gps_values, wifi_values, highestDrainPackageCPU, highestDrainPackageGPS, highestDrainPackageWIFI);
}
My Activity was successfully updated before I tried to create a new thread to do the heavy work inside the service.
EDIT: Sorry, I think I noticed it earlier, and got side tracked with the handler.
You create Thread t, but you never run it.
t.start();
You define handleMessage() as a method of the handler, like this:
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
//TODO: Handle different types of messages
}
};
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.
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.
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