I'm receiving data through a Bluetooth Service and would like to pass it to MainActivity with handleMessage, MainActivity has received the message but the object was "null"...Can anyone advise? Thanks in advance!
In Bluetooth Service: (the variable data is a String.)
mHandler.obtainMessage(MainActivity.MessageConstants.MESSAGE_ADD_ENTRY_L, data).sendToTarget();
In MainActivity:
problem- String data here is null, while I have double checked the data sent from bluetooth service is not null.
D/Main Activity: data at handler: null
mHandler = new Handler() {
#Override
public void handleMessage(#NonNull final Message msg) {
switch ((msg.what)) {
case MessageConstants.MESSAGE_ADD_ENTRY_L:
try {
Log.d(TAG, "handler add entry");
Thread dataParseThread = new Thread(new Runnable() {
#Override
public void run() {
String data = (String) msg.obj;
Log.d(TAG, "data at handler: " + data);
SensorData.parseDataL(data))
exportData.logEntryL();
}
});
dataParseThread.start();
} catch (Exception e) {
Log.d(TAG, "handler went wrong: " + e);
}
break;
}
}
};
While using sendToTarget() make sure your target is pointing to your mHandler as in
Message message = new Message();
message.what = MainActivity.MessageConstants.MESSAGE_ADD_ENTRY_L;
message.setData(data);
message.setTarget(mHandler);
message.sendToTarget();
UPDATE
you can still use your existing approach to get data as Object, but at some point you need to set the Target to Message so it can post
Message message = mHandler.obtainMessage(MainActivity.MessageConstants.MESSAGE_ADD_ENTRY_L, data);
message.setTarget(mHandler);
message.sendToTarget();
Related
I have a classe for download files by an executor :
this.getFreshGoolgletoken(new CallBackTokenRefresh() {
#Override
public void getFreshGoogleToken(String token,String userEmail) {
ArrayList<ExecuteSynchroneRequest> mesRequetes = new ArrayList<>();
Intent mServiceIntent = new Intent(context, TraitementPermisLoaded.class);
for (CollectionPermis permis : collectionPermis){
// stocker les permis + les s3Key
int revision = permis.revision;
final String uuid = permis.uuid;
Log.i(LOG_TAG,"synchro OnLoop permis num & revision :"+uuid+"/"+revision);
Map<String,String> params = new HashMap<>();
params.put("uuid",uuid);
params.put("revision",String.valueOf(revision));
mesRequetes.add(new ExecuteSynchroneRequest(AwsEworkPermitsRoutes.PERMITS,params,context,token,apiClient,uuid,handler,mServiceIntent,callBack));
}
ExecutorService execute = Executors.newSingleThreadExecutor();
for(Runnable r : mesRequetes){
execute.execute(r);
}
execute.shutdown();
}
In this methode i have an IntentService(mServiceIntent) for handle a long treatement on my download. My executor class handle intentService like this in switch command :
case PERMITS:
if(mServiceIntent == null) break;
mServiceIntent.setData(Uri.parse(responseData));
mServiceIntent.putExtra("myHandler", new Messenger(handler));
mServiceIntent.putExtra("ptUuid", uuid);
context.startService(mServiceIntent);
break;
mServiceIntent Class is :
public class TraitementPermisLoaded extends IntentService {
static final String LOG_TAG = "ewp-executor ";
SharedPreferences sharedPreferences;
Handler handler;
public TraitementPermisLoaded() {
super("TraitementPermisLoaded");
setIntentRedelivery(true);
Log.i(LOG_TAG," service traitement permis called 2 ");
}
#Override
protected void onHandleIntent(Intent workIntent) {
this.sharedPreferences = getApplicationContext().getSharedPreferences("DATA", Context.MODE_PRIVATE);
// Gets data from the incoming Intent
String responseData = workIntent.getDataString();
Messenger messenger = null;
String ptUuid = "";
Bundle extras=workIntent.getExtras();
if (extras!=null) {
messenger=(Messenger)extras.get("myHandler");
ptUuid = extras.getString("ptUuid");
}
String permisUuid = "";
PtWrapper pt = null;
try {
ObjectMapper mapper = new ObjectMapper();
pt = mapper.readValue(responseData, PtWrapper.class);
HandleJson handleJson = HandleJson.getInstance(getApplicationContext());
permisUuid = pt.getPermisTravailFormContext().permisTravail.uuid;
if (permisUuid != null) {
handleJson.writeInInterneFileSysteme(sharedPreferences.getString("email",null),pt, permisUuid);
} else {
throw new HandleJsonNoPermisException("le UUID est null on ne peut pas enregistrer ce permis");
}
handleJson.setKpi(pt);
Message message = Message.obtain();
Bundle bundle= new Bundle();
bundle.putString("myevent", "un permis ok");
message.setData(bundle);
messenger.send(message);
} catch (IOException e) {
Log.i(LOG_TAG, e.getMessage());
e.printStackTrace();
Message message = Message.obtain();
Bundle bundle= new Bundle();
bundle.putString("error", ErrorsCodes.CODE_40.toString()+" / permit uuid : "+ptUuid);
message.setData(bundle);
try {
messenger.send(message);
} catch (RemoteException e1) {
e1.printStackTrace();
Log.i(LOG_TAG,"erreur messager : "+e1.getMessage());
}
} catch (HandleJsonNoPermisException e) {
Log.i(LOG_TAG, e.getMessage());
e.printStackTrace();
} catch (RemoteException e) {
Log.i(LOG_TAG,e.getMessage());
e.printStackTrace();
}catch(Exception e){
Log.i(LOG_TAG,e.getMessage());
e.printStackTrace();
}
}
}
I load 27 files but only 14 get a treatment, the Intentservice stop to work, it'seems to be after activity change but not sure. After loaded files, I change my activity by another, but intentService get all request in the queue. I have use IntentService because it will finish working all process before stopping?
What did I do wrong?
Thanks
the error source is the size of data in myService.setData(mydata>250ko). For all data more than 250 ko the service stop with this error message :
A/ActivityManager: Service done with onDestroy, but executeNesting=2:
ServiceRecord{5c8e958 u0
com.alit.aws.android.eworkpermit/.lib.TraitementPermisLoaded
There is another way to pass large data more than 250 k to my intentService ? I have tried :
->mServiceIntent.setData(Uri.parse(responseData));
->mServiceIntent.putExtra("myData",responseData);
I have found a solution, remove the "setData(responseData)" and replace it by a globalHasMap. After the end of treatment I remove item in hashMap.
May be it's not awesome but i have not found a better solution.
If someone can show me a better way, do it ;-)
Thanks
This question already has answers here:
How do you display a Toast from a background thread on Android?
(14 answers)
Closed 9 years ago.
How to add a toast method inside a thread. I want to debug by replacing the system.out with a toast method to display results to the display.
I know that using the application Context from within the thread, like so:
Toast.makeText(getApplicationContext(), "help", Toast.LENGTH_LONG).show();
will not work.
I don't know how to use the Runnable with the Toast call and calling runOnUiThread(runnable) from the Thread
Could someone help me out.
public class NetworkServer extends Thread
{
DatagramSocket mSocket = null;
boolean isFinish = false;
private SimplestPossibleActivity activity;
public NetworkServer(SimplestPossibleActivity activity)
{
this.activity = activity;
}
public void run()
{
try
{
Log.d("UDP", "Listening");
mSocket = new DatagramSocket( 2010); //4444
mSocket.setBroadcast(true);
while (!isFinish)
{
Log.d("UDP", "C: socket create success");
byte[] recvbuffer = new byte[12];
DatagramPacket packet = new DatagramPacket(recvbuffer,recvbuffer.length);
Log.d("UDP", "receiving...");
mSocket.receive(packet);
Log.d("UDP", "received packet");
ByteBuffer bb = ByteBuffer.allocate(recvbuffer.length).order(ByteOrder.LITTLE_ENDIAN);
bb.put(recvbuffer);
bb.rewind();
//System.out.println(bb.getFloat());
//System.out.println(bb.getFloat());
//System.out.println(bb.getFloat());
Bundle data = new Bundle();
data.putFloat("latitude", bb.getFloat());
data.putFloat("longitude", bb.getFloat());
data.putFloat("altitude", bb.getFloat());
Message msgHandle = new Message();
msgHandle.setData(data);
mhandler.sendMessage(msgHandle);
} //end while
} catch (Exception e) {
Log.e("UDP", "C: Error", e);
}
}
private Handler mhandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
Bundle data = msg.getData();
Log.d("NetworkServer","adding position" + "lat = " + data.getFloat("latitude") +
"lon = " + data.getFloat("longitude") +
"alt = " + data.getFloat("altitude"));
activity.addPosition(data.getFloat("latitude"),
data.getFloat("longitude"),
data.getFloat("altitude"));
}
};
}
Use library Xdroid:
dependencies {
compile 'com.shamanland:xdroid-toaster:0.2.4'
}
There are quite good approaches:
Context variable is not required.
runOnUiThread() is not required.
Just invoke the single method!
// using the resource string
Toaster.toast(R.string.my_msg);
// or hard-coded string
Toaster.toast("Hello Xdroid!");
There are more examples here: https://github.com/shamanland/xdroid-toaster-example
You can do it like this
Handler handler = new Handler(); //Before your Thread
//Within your thread
handler.post(new Runnable(){
public void run() {
Toast.makeText(getApplicationContext(), "help", Toast.LENGTH_LONG).show();
}
});
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
//pick one:
//if activity
Toast.makeText(YOURACTIVITYNAME.this, "help", Toast.LENGTH_LONG).show();
//if fragment
Toast.makeText(getActivity(), "help", Toast.LENGTH_LONG).show();
} catch (final Exception e) {
}
}
});
My test app below is roughly based on this threads tutorial by Cristian Baita.
It works as expected, with the exception that the message sent from myThread's run() method is never received by the MainActivity's handler.
I am passing the MainActivity's handler to myThread in the thread's constructor. I then use that handler's sendMessage() method to send a message back to the MainActivity, but the handler never seems to receive it. Why is this?
Note: I've found using breakpoints for debugging in eclipse is a pain with threads, so I ended up going over the top with Log statments instead to help follow the apps execution.
I've put the full code at the end of this post, but to summarise:
The constructor for the MyThread class takes a handler from the calling activity as shown below.
public class MyThread extends Thread {
// Reference to mainHandler from the mainThread
private Handler parentHandler;
// Constructor
public MyThread(Handler pHandler) {
parentHandler = pHandler;
}
When I create the thread in MainActivity's onCreate() method I pass it the handler mainHandler:
myThread = new MyThread(mainHandler);
myThread.start();
Then in MyThread's run() method I have:
Message messageToParent = Message.obtain();
messageToParent.what = 2;
Log.i("myThread", "About to send message to parent ...");
parentHandler.sendMessage(messageToParent);
The message should then be received by mainHandler defined in MainActivity:
public Handler mainHandler = new Handler() {
public void handleMessages(Message msg){
Log.i("MainActivity", "Message Received");
switch(msg.what) {
case 2:
Log.i("MainActivity", "Handled message. msg.what = " + msg.what);
....
If you watch the LogCat window when this runs, you will see that MainActivity never logs "Message Received" or "Handled message... ". So the message never arrives at it's destination.
The MainActivity:
public class MainActivity extends Activity {
private MyThread myThread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myThread = new MyThread(mainHandler);
myThread.start();
// Message the thread
Message msgToThread = Message.obtain();
msgToThread.what = 4;
Log.i("MainActivity", "About to send message to thread...");
myThread.getHandler().sendMessage(msgToThread);
}
public Handler mainHandler = new Handler() {
public void handleMessages(Message msg){
Log.i("MainActivity", "Message Received");
switch(msg.what) {
case 2:
Log.i("MainActivity", "Handled message. msg.what = " + msg.what);
// Message the thread
Message msgToThread = Message.obtain();
msgToThread.what = 6;
myThread.getHandler().sendMessage(msgToThread);
break;
default:
Log.i("MainActivity", "Unhandled message. msg.what = " + msg.what);
break;
}
}
};
}
The MyThread class:
public class MyThread extends Thread {
// Reference to mainHandler from the mainThread
private Handler parentHandler;
// Constructor
public MyThread(Handler pHandler) {
parentHandler = pHandler;
}
// Local handler for messages to this thread
private Handler myThreadHandler = new Handler() {
public void handleMessage(Message msg) {
switch(msg.what) {
case 4:
Log.i("myThread", "Handled message. msg.what = " + msg.what);
break;
case 6:
Log.i("myThread", "Handled message. msg.what = " + msg.what);
break;
default:
Log.i("myThread", "Unhandled message. msg.what = " + msg.what);
break;
}
}
};
#Override
public void run() {
super.run();
int count = 0;
boolean keepGoing = true;
try {
while(true) {
Log.i("myThread", "run() method - while loop is ticking ..." + count);
// some arbitrary conditions to make stuff happen
switch(count) {
case 5:
Message messageToParent = Message.obtain();
messageToParent.what = 2;
Log.i("myThread", "About to send message to parent ...");
parentHandler.sendMessage(messageToParent);
break;
case 10:
keepGoing = false;
break;
}
if(!keepGoing) {
Log.i("myThread", "myThread is going to stop");
break;
}
count++;
sleep(500);
}
}
catch (Exception e) {
Log.e("My Log", "Thread Loop Exception - " + e);
}
Log.i("myThread", "myThread has reached the end of it's run() method");
}
public Handler getHandler() {
return myThreadHandler;
}
}
From an initial look, it might be because your parent handler is private. change it to public and try once!
I've realized I misunderstood what we are doing when we write the handleMessage() method for our handler.
I thought we were writing a new method for the handler, so I named it something slightly different handleMessages() (notice the plural).
In fact what we are doing is overriding one of the handler's existing method.
In the sample code I was following, Cristian Baita does not use an #Override statement before his handleMessage() method. This is fair enough, since #Override is only a convenience for you and your compiler to highlight bugs. Embarrassingly it is my fault for assuming that because #Override wasn't there, we weren't overriding anything. Hopefully this slip up will help some others in their learning curve.
BTW: I would still thoroughly recommend Cristian Baita's 3 thread tutorials, as they are very clearly explained and easy to follow. The problem was mine, in making assumptions!
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.
I've created a custom handler that will take care of dismissing dialogs, showing dialogs and showing (custom) error messages. However, I'm stuck with the custom error message part. How do I post a message with custom message & how to parse it in the handleMessage?
Now I'm doing:
handler.sendMessage(Message.obtain(handler, HANDLER_MESSAGE_ERROR));
I've read about bundle, but didn't get it working. Preferably (to keep the code neat), I'd like to do something like this:
handler.sendMessage(Message.obtain(handler, HANDLER_MESSAGE_ERROR, "Custom error message"));
and for error dialog:
handler.sendMessage(Message.obtain(handler, HANDLER_MESSAGE_DIALOG, "Custom title", "Custom error message"));
Here's the handler code that I'm using right now:
public class MyHandler extends Handler {
private Activity mContext;
public MyHandler(Activity activity) {
mContext = activity;
}
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyActivity.HANDLER_MESSAGE_ERROR:
try {
Toast.makeText(mContext, "_This should be a custom error message", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
}
break;
}
}
}
I have used handler to pass different messges. This code will work for you.
Pass only simple message:
Message msg = new Message();
msg.what = HANDLER_MESSAGE_ERROR;
Bundle b = new Bundle();
b.putString("message", "Custom error message");
msg.setData(b);
handler.sendMessage(msg);
Pass title and message:
Message msg = new Message();
msg.what = HANDLER_MESSAGE_DIALOG;
Bundle b = new Bundle();
b.putString("title", "Custom title");
b.putString("message", "Custom error message");
msg.setData(b);
handler.sendMessage(msg);
You will get the bundle in your method in the following way
#Override
public void handleMessage(Message msg) {
//Get bundle
Bundle b = msg.getData();
String title,messag;
switch (msg.what) {
case MyActivity.HANDLER_MESSAGE_ERROR:
try {
message = b.getString("message");
//show toast here
} catch (Exception e) {
}
break;
case MyActivity.HANDLER_MESSAGE_DIALOG:
try {
title = b.getString("title");
message = b.getString("message");
//show toast here
} catch (Exception e) {
}
break;
}
}
The Message object can store key value pairs like this:
final Message msg = new Message();
final Bundle data = new Bundle();
data.putString(ERROR, "error message");
msg.setData(data);
In the Handler extract the data from the bundle:
final String e = m.getData().getString(ERROR);