How to show custom error message in a Toast from Handler? - android

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);

Related

HandleMessage Failed to Pass Object

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();

IntentService lost work in executor

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

Communication between an Application class and Service in Android

I have a requirement where I have already extended an "Application" class in my Android Project.
eg:
public class myApp extends Application implements
myReceiver.Receiver {...}
Is it possible for me to communicate through a "Service" using my - "Message.obtain" or should I use other things? Please advice.
I also want to pass data to my Service which is a String/constant value. Can I do it like this :
private void sendMsg(int arg1, int arg2) {
if (mBound) {
Message msg = Message.obtain(null, MyService.Hello,
arg1, arg2);
try {
mService.send(msg);
} catch (RemoteException e) {
Log.e(TAG, "Error sending a message", e);
}
}
}
try this:
in the extends Application class create one inner class
private class MyMessageHandler extends Handler {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle bundelData = msg.getData();
if (bundelData != null) {
String mString = (String) bundelData.get(IConstants.HOME_SCREEN_LISTUPDATE);
if (mString != null) {
// your logic
}
}
}
starting the service by passing the Messenger
Intent serviceIntent = new Intent(this, WatchService.class);
serviceIntent.putExtra(IConstants.MYMESSAGE_HANDLER, new Messenger(new MyMessageHandler));
startService(serviceIntent);
in the service onStartCommand get the messenger
if (intent != null) {
Bundle mExtras = intent.getExtras();
if (mExtras != null) {
Messenger innrMessenger = (Messenger)mExtras.get(IConstants.MYMESSAGE_HANDLER);
}
}
if you want to send data from service to that class
Message message = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString(IConstants.HOME_SCREEN_LISTUPDATE, state);
message.setData(bundle);
innrMessenger.send(message);//get call back for handleMessage(Message msg)

Android Handler: Send 8 different messages: handler finds 8 messages but only used the last message

I am new to Android and found out that to keep updating the main view I had to create a thread to handle various process and then pass back updates to the main view. I decided to use the Handler class to do this. The view in this example has a button to activate the code and a tablelayout to display the messages received - representing a stage of the process.
The problem is that I send 8 different messages and I can see 8 messages coming back in the handler, but all 8 have the same contents as message 8 only.
I was expecting the handler to pick the messages up in sequence.
Any suggestions on a better way of doing this always welcome to learn.
Here is the code:
`
public class messageHandlerTest extends Activity {
protected TextView textView;
protected Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
String[] status = (String[]) msg.obj;
createTableRow(status);
Log.e("Got a new message",status[0]+":"+status[1]);
}
};
Button btnStartProgress;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.statusText);
textView.setText("");
//Getting response from server with Network SSID and Password
Button connectButton = (Button)findViewById(R.id.connectButton);
addListenerOnButton();
} // End of create
protected class connectWiFi extends Thread implements Runnable {
//tokens1 = new String[0];
public void run(){
try {
String[] messageString = new String[2];
Message message = handler.obtainMessage();
messageString[0]="OK";
messageString[1]="Number 1";
message.obj = messageString;
handler.sendMessage(message);
message = handler.obtainMessage();
messageString[0]="OK";
messageString[1]= "Number 2";
message.obj = messageString;
handler.sendMessage(message);
message = handler.obtainMessage();
messageString[0]="OK";
messageString[1] = "Number 3";
message.obj = messageString;
handler.sendMessage(message);
message = handler.obtainMessage();
messageString[0]="OK";
messageString[1] = "Number 4";
message.obj = messageString;
handler.sendMessage(message);
message = handler.obtainMessage();
messageString[0] = "OK";
messageString[1] = "Number 5";
message.obj = messageString;
handler.sendMessage(message);
message = handler.obtainMessage();
messageString[0] = "OK";
messageString[1] = "Number 6";
message.obj = messageString;
handler.sendMessage(message);
message = handler.obtainMessage();
messageString[0] = "OK";
messageString[1] = "Number 7";
message.obj = messageString;
handler.sendMessage(message);
message = handler.obtainMessage();
messageString[0] = "OK";
messageString[1] = "Number 8";
message.obj = messageString;
handler.sendMessage(message);
} catch (Exception e) {
e.printStackTrace();
Log.e("Exception found","bugger");
}
}// End or run
}// End of class
public void addListenerOnButton() {
btnStartProgress = (Button) findViewById(R.id.connectButton);
btnStartProgress.setOnClickListener(
new OnClickListener() {
#Override
public void onClick(View v) {
connectWiFi connectwifi = new connectWiFi();
connectwifi.start();
}
});
}
private void createTableRow(String[] stage) {
TableLayout tl = (TableLayout) findViewById(R.id.statusTable);
TableRow tr = new TableRow(this);
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
tr.setLayoutParams(lp);
tr.setBackgroundColor(0xFFFFFFFF);
TextView tvStatus = new TextView(this);
tvStatus.setLayoutParams(lp);
tvStatus.setPadding(2,1,1,2);
tvStatus.setTextColor(0xFF000000);
tvStatus.setText(stage[0]); // Status
TextView tvStage = new TextView(this);
tvStage.setLayoutParams(lp);
tvStage.setPadding(2,1,1,2);
tvStage.setTextColor(0xFF000000);
tvStage.setText(stage[1]); // Stage
tr.addView(tvStatus);
tr.addView(tvStage);
tl.addView(tr, new TableLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
}
#Override
protected void onDestroy() {
super.onDestroy();
}
}
The result of this code looks like:
For sending data through handler you can use bundle as data of message object that you want to send to handler. Like this code :
// receieve message in handleMessage method of handler of your controller (e.g. on UI thread)
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Bundle b = msg.getData();
Integer value = b.getInt("KEY");
...
}
};
// Sending message in a background thread
new Thread(new Runnable() {
#Override
public void run() {
final Message msg = new Message();
final Bundle b = new Bundle();
Integer value = 1;
b.putInt("KEY", value);
msg.setData(b);
handler.sendMessage(msg);
}
).start();
I suspect what may be happening is that you continually modify the same reference String[] named messageString while never creating a new one. Passing that by reference and then continuing to change the values there are probably what's resulting in this outcome.
A few things,
When using handlers try to use the what field for return code. For instnace, your OK string (if it is just for a status) you would be better off defining int constant return types.
As JanBo mentioned, you don't want to be extending Thread and implementing Runnable.
It really depends on what you're trying to do exactly but the Handler message queue callback pattern is one of many you can choose to accomplish what you want. In the interest of learning another method, take a look at a blog post I wrote here which explains how you can delegate off-UI thread tasks to an IntentService and call back to your Activity when it finishes.
I suppose what's happening is that: messageString, which you create only once, is being updated while message is waiting in the queue. Change your code like this:
String[] messageString1 = new String[2];
Message message = handler.obtainMessage();
messageString1[0]="OK";
messageString1[1]="Number 1";
message.obj = messageString1;
handler.sendMessage(message);
String[] messageString2 = new String[2];
message = handler.obtainMessage();
messageString2[0]="OK";
messageString2[1]= "Number 2";
message.obj = messageString2;
handler.sendMessage(message);
....
....
I am not sure if I am doing this in the right place, but I thought I would post back my refactored code based on the help I received here and it might help someone else. This works well for me and the code looks quite neat, but any feedback on how this could be improved or made more efficient would always be appreciated. Also let me know if I am doing this in the wrong place!
public class messageHandlerTest2 extends Activity {
protected TextView textView;
protected Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
createTableRow((mymessageObject) msg.obj);
}
}; //Set-up handler to be used later
Button btnStartProgress;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button connectButton = (Button) findViewById(R.id.connectButton);
addListenerOnButton();
} // End of create
protected class connectWiFi extends Thread {
public void run() {
try {
sendMessage(true,"Number 1"); // send if OK and a stage message
sendMessage(true,"Number 2");
sendMessage(true,"Number 3");
sendMessage(true,"Number 4");
sendMessage(true,"Number 5");
sendMessage(true,"Number 6");
sendMessage(true,"Number 7");
sendMessage(true,"Number 8");
sendMessage(true,"Number 9");
sendMessage(true,"Number 10");
sendMessage(true,"Number 11");
sendMessage(true,"Number 12");
} catch (Exception e) {
e.printStackTrace();
Log.e("Exception found", "bugger");
}
}// End or run
}// End of class
public void addListenerOnButton() {
btnStartProgress = (Button) findViewById(R.id.connectButton);
btnStartProgress.setOnClickListener(
new OnClickListener() {
#Override
public void onClick(View v) {
connectWiFi connectwifi = new connectWiFi();
connectwifi.start();
}
});
}
private void createTableRow(mymessageObject stage) {
String statusString;
TableLayout tl = (TableLayout) findViewById(R.id.statusTable);
TableRow tr = new TableRow(this);
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
tr.setLayoutParams(lp);
tr.setBackgroundColor(0xFFFFFFFF);
TextView tvStatus = new TextView(this);
tvStatus.setLayoutParams(lp);
tvStatus.setPadding(2, 1, 1, 2);
tvStatus.setTextColor(0xFF000000);
if (stage.Status) {statusString = "OK";} else {statusString = "No";};
tvStatus.setText(statusString); // Status
TextView tvStage = new TextView(this);
tvStage.setLayoutParams(lp);
tvStage.setPadding(2, 1, 1, 2);
tvStage.setTextColor(0xFF000000);
tvStage.setText(stage.statusMessage); // Stage
tr.addView(tvStatus);
tr.addView(tvStage);
tl.addView(tr, new TableLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
}
#Override
protected void onDestroy() {
super.onDestroy();
}
private class mymessageObject { // Creates object of status flag and stage message
boolean Status;
String statusMessage;
mymessageObject(boolean newStatus, String newMessage){
Status = newStatus;
statusMessage = newMessage;
}
}
private void sendMessage (boolean status, String stageMessage) { // Handle sending message back to handler
Message message = handler.obtainMessage();
message.obj = new mymessageObject(status,stageMessage);
handler.sendMessage(message);
}
}
try this
Message m = Message.obtainMessage();
not
Message m = handler.obtainMessage();

How to replace the system.out with Toasts inside a thread [duplicate]

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) {
}
}
});

Categories

Resources