I have question about handler a Message. Anybody know how to retreieve the data from a message? Currently I have a method called handleMessage
#Override
public void handleMessage(Message message) {
Bundle bundle = message.getData();
String text = message.obtain().toString();
If I run the debug mode, the message contain:
I would like to get the object (which means "www.google.com") and put it as a string. Anybody know how to get it? I tried with message.obtain.toString, it doesn't succeed.
Thanks
Message.obtain() returns an empty message from the pool. What your are looking for is in obj.
String text = (String) message.obj;
message.obj is an Object, so it has to be casted to the exacted type
Set the data to the Message.obj first, then you can get from the obj.
To set data in message
Message msg = new Message();
msg.obj = "do";
msg.what = 1;
handler.sendMessage(msg);
To fetch data from message
Handler handler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message message) {
if(message.what == 1){
String value = (String) message.obj;
}
}
return false;
}
});
Related
I have read questions related to this question and I have come to the conclusion that my variable which is of reference type has not been initialized or its object has not been created to be used for dereferencing. However I am not sure of how to initialize my variable of type String with the way it's being used. Here is part of the codes:
public class ManualControlsFragment extends Fragment {
private MqttAndroidClient client;
String payload1;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_manual_controls, container, false);
switchLed = (Switch) view.findViewById(R.id.LEDManControl);
switchLed.setChecked(true);
switchLed.setTextOn("On");
switchLed.setTextOff("Off");
String clientId = MqttClient.generateClientId();
client =
new MqttAndroidClient(this.getActivity(), "tcp://192.168.100.6:1883",
clientId);
//Start of Manual Automation
try {
IMqttToken token = client.connect();
token.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
String topic = "rpi/gpio";
switchLed.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// If ischecked means if it is ON the it will show true else
// show false
if (isChecked) {
/*Toast.makeText(getActivity().getApplicationContext(),
"Switch is : " + isChecked, Toast.LENGTH_SHORT)
.show();*/
payload1 ="ledOn";
} else {
/*Toast.makeText(getActivity().getApplicationContext(),
"Switch is : " + isChecked, Toast.LENGTH_SHORT)
.show();*/
payload1 ="ledOff";
}
}
});
try {
/*if(payload1!=null){
MqttMessage message1 = new MqttMessage(payload1.getBytes());
client.publish(topic, message1);
}*/
MqttMessage message1 = new MqttMessage(payload1.getBytes());
client.publish(topic, message1);
This is what appears on the logcat:
java.lang.NullPointerException: Attempt to invoke virtual method 'byte[] java.lang.String.getBytes()' on a null object reference
at com.example.teerna.smartagriculturev5.ManualControlsFragment$1.onSuccess(ManualControlsFragment.java:294)
at org.eclipse.paho.android.service.MqttTokenAndroid.notifyComplete(MqttTokenAndroid.java:124)
at org.eclipse.paho.android.service.MqttAndroidClient.simpleAction(MqttAndroidClient.java:1497)
at org.eclipse.paho.android.service.MqttAndroidClient.connectAction(MqttAndroidClient.java:1439)
at org.eclipse.paho.android.service.MqttAndroidClient.onReceive(MqttAndroidClient.java:1368)
at android.support.v4.content.LocalBroadcastManager.executePendingBroadcasts(LocalBroadcastManager.java:308)
at android.support.v4.content.LocalBroadcastManager.access$000(LocalBroadcastManager.java:46)
at android.support.v4.content.LocalBroadcastManager$1.handleMessage(LocalBroadcastManager.java:118)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5912)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1405)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1200)
The error appears at this line:
MqttMessage message1 = new MqttMessage(payload1.getBytes());
I tried the following but they didn't work:
if (isChecked) {
payload1 = new String("ledOn");
} else {
payload1 = new String("ledOff");
}
And I tried to see if the payload is null. That stopped the app from crashing (and displaying the NullPointException) and it didn't send the payload:
try {
if(payload1!=null){
MqttMessage message1 = new MqttMessage(payload1.getBytes());
client.publish(topic, message1);
}
I suppose the cause of the error lies in the payload not being initialized which makes it null. I would like to know where I should initialize it or how I should use it because putting the variable inside the try block gives me errors such it should be declared final and when I declare it as final I am not able to assign a value to it as it cannot be changed after I make it final.
Would greatly appreciate any help.
Thanks for all the answers.
I actually reconsidered the approach I used to send the payload and I realized that the reason why the server was not getting the payload was because a null payload was being sent and it was not sending the payload based on the changes in the switch. The aim of the switch was to send a payload to a server to tell my microcontroller to turn a LED on or off based on the status of the switch. I rewrote it as I have posted below and it worked perfectly fine:
switchLed.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// If ischecked means if it is ON the it will show true else
// show false
if (isChecked) {
String payload1="ledOn";
MqttMessage message1 = new MqttMessage(payload1.getBytes());
try {
client.publish(topic, message1);
} catch (MqttException e) {
e.printStackTrace();
}
} else {
String payload2 = "ledOff";
MqttMessage message2 = new MqttMessage(payload2.getBytes());
try {
client.publish(topic, message2);
} catch (MqttException e) {
e.printStackTrace();
}
}
}
});
Before your onCreateView you declare your variable String payload1; but it isn't initialized.
This will only work when you change the switch, if it's never changed your variable will never be initialized.
if (isChecked) {
payload1 = new String("ledOn");
} else {
payload1 = new String("ledOff");
}
What I advise you to do is to initialized it with one of those two states, or with an empty string. That way it will never be null:
String payload1 = "ledOn";
You just declare your variable String payload1;
If you want to use payload1.getBytes() you just need to initialize String variable.
IN your case i don't no why but switchLed.setOnCheckedChangeListener is not call so variable is not initialized.
That's why you have an error in your code
i use asmack buddycloud 2010 for a chat app and im trying to send chat messages from my servie to activity using handler here is the code part of my service:
public void processPacket(Packet packet) {
Message message = (Message) packet;
if (message.getBody() != null) {
String fromName = StringUtils.parseBareAddress(message.getFrom());
Log.i("XMPPChatDemoActivity ", " Text Recieved " + message.getBody() + " from "
+ fromName);
messages.add(fromName + ":");
messages.add(message.getBody());
Log.i("XMPPChatDemoActivity",message.getBody());
mHandler.obtainMessage(123, "Message or data");
mHandler.sendMessage(message);
here on the mhanlder.sendmessage i have an error saying the method sendMessage(Message message) in the type handler is not applicable for arguments (org.jivesoft.smack.packet.message)
and here in the activity :
Public CLass XMPPActivity extends Activity {
.
.
.
private class getmessage extends Handler{
public void handleMessage(Message msg) {
setListAdapter();
}
}
here i cant override the handlemessage, it says i must override a supertype method !!!! do you guys know what's up? am i missing some thing? thanks
also when i replace it with
mHandler.obtainMessage(123, message).sendToTarget();
i get nothing, because i can not override the handleMessage()
You can do it by following way.
Step 1
Declare Handler inside your activity say inside onCreate method.
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case PASS:
String obj = msg.obj.toString();
Toast.makeText(YourActivity.this, "PASS",
Toast.LENGTH_SHORT).show();
break;
case FAIL:
Toast.makeText(YourActivity.this, "FAIL",
Toast.LENGTH_SHORT).show();
break;
}
}
};
Step 2
Declare 2 constants which are used in Handler
public static final int PASS = 1;
public static final int FAIL = 2;
Step 3
To pass message, use following code.
Message msg = new Message();
msg.what = PASS;
msg.obj = fromName;
Here, you can change msg.what to any integer constant. And you can set any type of object to msg.obj. But make sure that what type of object you are setting to it, you need to type cast it based on that only. Otherwise exception will be thrown.
I've already bound an activity to my service following this tutorial.
http://developer.android.com/guide/components/bound-services.html
I'm able to call service functions, but what if I want to for example, change some of my textviews or disable some of the toggle buttons because of work done on the service (and from the service). Would there be an easy to way to do this?
You can use messages to send information between activities and services. This is an easy way to send simple data, but may not be the best option if you need to send data very frequently, or send complicated data. This is an example of some code I have in one of my apps with a service and an activity which communicate:
Code in the activity:
//this is where you set what you want to happen
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
//this switch reads the information in the message (usually just
//an integer) and will do something depending on which integer is sent
case 1: do_something();
case 2: do_something_2(); //etc.
default:
super.handleMessage(msg);
}
}
}
final Messenger myMessenger = new Messenger(new IncomingHandler());
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
myService = new Messenger(service);
myCallbackText = (TextView)findViewById(R.id.tv01); //This is a text view which will display status information as needed
myCallbackText.setText("Attached.");
try {
Message msg = Message.obtain(null,
1);
msg.replyTo = mMessenger; //here we send an instance of our messenger implementation as the replyTo address
mService.send(msg);
msg = Message.obtain(null,
3, this.hashCode(), 0);
mService.send(msg); //send a message with the value "3"
} catch (RemoteException e) {
//nothing you can do if the server isn't active
}
Toast.makeText(Service_testActivity.this, R.string.remote_service_connected,
Toast.LENGTH_SHORT).show();//confirmation that the connection happened successfully
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mCallbackText = (TextView)findViewById(R.id.tv01);//same textview as before
mCallbackText.setText("Disconnected.");
Toast.makeText(Service_testActivity.this, R.string.remote_service_disconnected,
Toast.LENGTH_SHORT).show();
}
};
Code in the service:
In the service, you will want to have code (very similar to the code in the activity) to receive a message and save the msg.replyTo field as a Messenger object. There is an example somewhere which will have you make an object and then use an IncomingHandler like this:
ArrayList<Messenger> mClients = new ArrayList<Messenger>();
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REGISTER_CLIENT:
mClients.add(msg.replyTo);
break;
case MSG_UNREGISTER_CLIENT:
mClients.remove(msg.replyTo);
break;
default:
super.handleMessage(msg);
}
}
}
This can allow your service to keep track of multiple clients at once and send messages to specified clients. To send a message simply use something like this:
mClients.get(1).send(Message.obtain(null, 3, new Random().nextInt(), 0));
//sends a message to the first client saved in the list
actually, the problem is when my xmpp client send a friend invitation, and then the recipient have Approve the invitation, the openfire server push again to the initiator/ invitation sender a subscription packet to be authorized, that's why I want to prevent this by automatically filter it using IQ tag and then automatically authorize it.
but with PacketListener, I can't get IQ tag...
How can I do this?
#Override
public void processPacket(Packet packet) {
Log.i(TAG, "SECOND subscription");
Log.d(TAG, "SECOND: "+packet.toXML());
if (packet instanceof Presence) {
Presence p = (Presence) packet;
Log.d(TAG, "TYPE-Presence: "+p.getType());
if (p.getType() != Presence.Type.subscribe)
return;
String from = p.getFrom();
Log.d(TAG, "PACKET from: "+from);
Notification notification = new Notification(android.R.drawable.stat_notify_more, mService.getString(
R.string.AcceptContactRequest, from), System.currentTimeMillis());
notification.flags = Notification.FLAG_AUTO_CANCEL;
Intent intent = new Intent(mService, Subscription.class);
intent.setData(Contact.makeXmppUri(from));
notification.setLatestEventInfo(mService, from, mService
.getString(R.string.AcceptContactRequestFrom, from), PendingIntent.getActivity(mService, 0,
intent, PendingIntent.FLAG_ONE_SHOT));
int id = p.hashCode();
mService.sendNotification(id, notification);
}
}
The incoming IQs can be filtered out by using the "IQTypeFilter" filter. This is a sample code that illustrates the method.
connection.connect();
/* packet listener: listen for incoming messages of type IQ on the connection (whatever the buddy) */
PacketFilter filter = new IQTypeFilter(IQ.Type.SET); // or IQ.Type.GET etc. according to what you like to filter.
connection.addPacketListener(new PacketListener() {
public void processPacket(Packet packet) {
// HERE YOU PUT YOUR CODE TO HANDLE THE IQ MESSAGE
}
}, filter);
You may achieve it by using IQTypeFilter, which is a filter for IQ packet types:
public final class IQTypeFilter extends FlexibleStanzaTypeFilter<IQ> {
public static final StanzaFilter GET = new IQTypeFilter(Type.get);
public static final StanzaFilter SET = new IQTypeFilter(Type.set);
public static final StanzaFilter RESULT = new IQTypeFilter(Type.result);
public static final StanzaFilter ERROR = new IQTypeFilter(Type.error);
public static final StanzaFilter GET_OR_SET = new OrFilter(GET, SET);
private final IQ.Type type;
private IQTypeFilter(IQ.Type type) {
super(IQ.class);
this.type = Objects.requireNonNull(type, "Type must not be null");
}
#Override
protected boolean acceptSpecific(IQ iq) {
return iq.getType() == type;
}
#Override
public String toString() {
return getClass().getSimpleName() + ": type=" + type;
}
As defined in Javadoc, IQTypeFilter is a filter for IQ packet types. Returns true only if the packet is an IQ packet and it matches the type provided in the constructor. There are some examples for the use of IQTypeFilter
Here is an updated answer using Smack 4.3.4. I explicitly put comments in order to make my code clear.
/**
* packet listener: listen for incoming messages of whith IQ as elelement
* exmaple of IQ : <iq from="mbula#domain" to="dedi#domain" type="get" >.......</iq>
*/
public static void listenToStanzas(AbstractXMPPConnection connection){
// IQ filter type. it can Be GET, SET, RESULT, ERROR
//in my case I filter SET IQs
StanzaFilter filter = IQTypeFilter.SET;
connection.addSyncStanzaListener(new StanzaListener() {
#Override
public void processStanza(Stanza packet) {
//Put yoour code Here
}
}, filter);
}
I know this question has been asked multiple times, but nobody has been able to come up with a working answer from what I have seen.
Im working on an app to intercept text messages and depending on the sending #, pop up with a custom alert. I have it working beautifully with a broadcast receiver, however if the user has goSms installed the onReceive() method is never called as goSms aborts it before it ever reaches my app.
To get around this, Im trying a content observer on content://sms/
Its working just fine, however the onChange() is called twice, with exactly the same parameters. Ive tried to check the time stamps, but they are the same, as is the type and every other parameter I have set.
From what I've seen, this is a common issue, but not one that I've seen answered anywhere.
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
querySMS();
}
protected void querySMS() {
Cursor cur = getContentResolver().query(u, null, null, null, null);
cur.moveToNext(); // this will make it point to the first record, which is the last SMS sent
String type = cur.getString(cur.getColumnIndex("type"));
String body = cur.getString(cur.getColumnIndex("body")); //content of sms
String add = cur.getString(cur.getColumnIndex("address")); //phone num
if (type.equals("1")) {
if (add.equals(Test.SENDER)) {
String[] bodys = body.split(" ", 7);
if (bodys[0].equals("test")) {
test = true;
}
cat = bodys[1];
level = bodys[2];
urgency = bodys[3];
certainty = bodys[4];
carrier = bodys[5];
message = bodys[6];
final Intent intent = new Intent(context, AlertActivity.class);
Bundle b = new Bundle();
b.putString("title", cat);
b.putString("certainty", certainty);
b.putString("urgency", urgency);
b.putString("level", level);
b.putString("message", message);
b.putBoolean("test", test);
intent.putExtras(b);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
carrierName = manager.getNetworkOperatorName();
if (carrierName.replaceAll(" ", "").equals(carrier)) {
context.startActivity(intent);
} else {
//testing
Toast.makeText(context, carrierName.replaceAll(" ", ""), Toast.LENGTH_LONG).show();
}
}
}
}
Because of the onChange() being fired twice, Im getting two alerts as well. I cannot for the life of me figure out a way around this.
If the two are identical:
store each message recv'd
compare it to previous messages recv'd
if not found, process
if found, discard the message
The life of the messages stored should be infinitesimal, a little circular buffer of 5 messages should be fine.
here is my code, it works fine for me
public class SmsObserver extends ContentObserver {
private Context context;
private static int initialPos;
private static final String TAG = "SMSContentObserver";
private static final Uri uriSMS = Uri.parse("content://sms/sent");
public SmsObserver(Handler handler, Context ctx) {
super(handler);
context = ctx;
initialPos = getLastMsgId();
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
queryLastSentSMS();
}
public int getLastMsgId() {
Cursor cur = context.getContentResolver().query(uriSMS, null, null, null, null);
cur.moveToFirst();
int lastMsgId = cur.getInt(cur.getColumnIndex("_id"));
Log.i(TAG, "Last sent message id: " + String.valueOf(lastMsgId));
return lastMsgId;
}
protected void queryLastSentSMS() {
new Thread(new Runnable() {
#Override
public void run() {
Cursor cur =
context.getContentResolver().query(uriSMS, null, null, null, null);
if (cur.moveToNext()) {
try {
if (initialPos != getLastMsgId()) {
// Here you get the last sms. Do what you want.
String receiver = cur.getString(cur.getColumnIndex("address"));
System.out.println(" Receiver Ph no :"+receiver);
// Then, set initialPos to the current position.
initialPos = getLastMsgId();
}
} catch (Exception e) {
// Treat exception here
}
}
cur.close();
}
}).start();
}
}//End of class SmsObserver
You can save last message's id and compare it to the id of the message that is returned by cur in onChange. you then can simply disregard the message if ids are the same.
// might contain mistakes, but you'll get the idea:
protected void querySMS() {
Cursor cur = getContentResolver().query(u, null, null, null, null);
cur.moveToNext();
if (lastId == cur.getLong(cur.getColumnIndex("_id")))
return;
lastId = cur.getLong(cur.getColumnIndex("_id"));
... //continue as it was
}
However - GO SMS only prevents other app's from recieving Broadcast if the user selected this option (Recieve Settings - Disable other message notification) - so if the user does not want other apps to disturb him - I think it's good idea not to do so.
I just use SharedPreference to remark last SMS info (like: id\type ...). if it is the same, I will return.