Sending Messages Through handler from Service - java

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.

Related

How to get every time messages from service to activity using runOnUiThread

I have been stuck with one problem. I need some people which check a part of my code and help me with problem and critize my code (I write code but I haven't people which can say this is wrong or something in this pattern)
Generally.
My service get message from bluetooth (HC-05) and I can see values in Log.d, in service.
A part code of my service which get message.
private class ConnectedThread extends Thread{
private final BluetoothSocket bluetoothSocket;
private final InputStream inputStream;
private final OutputStream outputStream;
public ConnectedThread(BluetoothSocket socket){
Log.d(TAG,"ConnectedThread: Starting");
bluetoothSocket=socket;
InputStream tmpInput = null;
OutputStream tmpOutput = null;
try{
tmpInput = bluetoothSocket.getInputStream();
tmpOutput = bluetoothSocket.getOutputStream();
}catch (IOException e){
e.printStackTrace();
active=false;
}
inputStream=tmpInput;
outputStream=tmpOutput;
}
#Override
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while(active){
try {
bytes = inputStream.read(buffer);
final String comingMsg = new String(buffer,0,bytes);
Log.d(TAG,"InputStream: " + comingMsg);
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Message message = new Message();
message.obj = comingMsg;
message.what = 1; // I need it to prevent NullObjReference
Log.d(TAG,"Handler run(): " + message.obj);
mHandler.sendMessage(message);
}
});
}catch (IOException e){
Log.e(TAG,"Write: Error reading input." + e.getMessage());
active=false;
break;
}
}
}
...some code is hidden because it is diploma thesis
}
The problem is get message every time from this service to another activity where all is happen.
I tried a lot of things (with Threads,Looper,runOnUiThread, handleMessage and callback), checked a lot of posts in stackoverflow and I tried to combine with my project but all time I had nullobjectreference (for that i tried to use msg.what to check) , black screen when tried to move to my home activity (it is main) and update my textView or typical crash app.
Now I want only to get message from service to textview. When everything starts working fine, I want to parse string (for example 3 first chars) and send message to one of six textviews.
A part of codes from onCreate before method runThread() is started:
Log.d(TAG,"Check intent - result");
if(getIntent().getIntExtra("result",0)==RESULT_OK){
mDevice = getIntent().getExtras().getParcelable("bonded device");
startConnection(mDevice,MY_UUID);
Log.d(TAG,"Check is active service ");
checkIfActive();;
}
Log.d(TAG,"Check intent - connect_to_paired");
if(getIntent().getIntExtra("connect_to_paired",0)==RESULT_OK){
mDevice = getIntent().getExtras().getParcelable("bonded_paired_device");
startConnection(mDevice,MY_UUID);
Log.d(TAG,"Check is active service ");
checkIfActive();
}
public void checkIfActive(){
Log.d(TAG,"CheckIfActive: Started");
while(myBluetoothService.active!=true) {
Log.d(TAG,"CheckIfActive() active is "+ myBluetoothService.active);
if (myBluetoothService.active) {
Log.d(TAG, "CheckIfActive: Running method runOnUiThread - myBluetoothService.active is "+myBluetoothService.active);
runThread();
}
}
}
Method runThread() which should work everytime after connected with bluetooth device:
public void runThread(){
//I used there Thread but when connection was fail,
// method created multiply threads when I tried to connect next time
runOnUiThread(new Runnable() {
#Override
public void run() {
handler = new Handler(Looper.getMainLooper()){
#Override
public void handleMessage(Message msg) {
while (true) {
switch (msg.what) {
//when is one, service has messages to send
case 1:
String message = myBluetoothService.mHandler.obtainMessage().toString();
rearLeft.setText(message);
break;
default:
super.handleMessage(msg);
}
}
}
};
}
});
}
UPDATE:
Is it good idea ? Maybe I can put JSON Object to service to send message and in the HomeActivity, I can try get values from JSON. Is it fast ? I send a lot of data, because bluetooth receive data of distance from 4 ultrasound sensors in 4 times in lasts until few milliseconds, everytime.
Here is screen how sees my data in service when I have debug logs.
Next idea, but still nothing:
HomeActivity (my main)
public void runThread(){
runOnUiThread(new Runnable() {
#Override
public void run() {
//Looper.prepare();
new Handler() {
#Override
public void handleMessage(Message msg) {
rearLeft.setText(msg.obj.toString());
}
};
//Looper.loop();
//Log.d(TAG, myBluetoothService.mHandler.getLooper().toString());
//rearLeft.setText(myBluetoothService.mHandler.getLooper().toString());
}
});
}
Service which should send data from bluetooth to UI Thread is the same (Check first code).
Screen from HomeActivity where you can see 6 text views. Now I want put all text to one view which will be refresh by get next message.
Ok this post a bit help me to solve problem:
Sending a simple message from Service to Activity
Maybe this link could help another people.
Thanks for help, now understand why i should use broadcast receiver to do this.

Method Called Before Previous Method Finishes

I'm working on a simple translation app as part of a university project. For the translation process, I query MyMemory's Translate API using Retrofit and I retrieve the translated output as a String. This is working fine for the most part, but it's causing some issues in other areas of my program.
When I make a call to retrieve a translation from the library, subsequent methods begin to run before the translation is fully recieved - this then prevents those methods from working fully since they rely on the received translation.
Here are some relevant snippets of my code that might explain the question better:
TranslateAPI: (Interface that i use to retrieve a translation)
public class TranslateAPI {
private static final String ENDPOINT = "http://api.mymemory.translated.net";
public final static String FRENCH = "FR";
public final static String ENGLISH = "EN";
public final static String ITALIAN = "IT";
public final static String GREEK = "EL";
public final static String SPANISH = "ES";
private final TranslateService mService;
String translation = "";
public interface TranslateService {
#GET("/get")
Call<TranslatedData> getTranslation(
#Query("q") String textToTranslate,
#Query(value = "langpair", encoded = true)
String languagePair);
}
public TranslateAPI() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ENDPOINT)
.addConverterFactory(GsonConverterFactory.create())
.build();
mService = retrofit.create(TranslateService.class);
}
public String translate(final String textToTranslate, final String fromLanguage, final String toLanguage) {
mService.getTranslation(textToTranslate, URLEncoder.encode(fromLanguage + "|" + toLanguage))
.enqueue(new Callback<TranslatedData>() {
#Override
public void onResponse(Response<TranslatedData> response, Retrofit retrofit) {
String output =
String.format(response.body().responseData.translatedText);
String.format("Translation of: %s, %s->%s = %s", textToTranslate,
fromLanguage, toLanguage, response.body().responseData.translatedText);
System.out.println("Result: " + output);
translation = output;
System.out.println("The result of the field translation is: " + translation);
}
#Override
public void onFailure(Throwable t) {
System.out.println("[DEBUG]" + " RestApi onFailure - " + "");
}
});
return translation;
}
}
In the code above, the translate(final String textToTranslate, final String fromLanguage, final String toLanguage) method successfully returns the translated output as a string.
Now, to demonstrate exactly what goes wrong, assume the following code snippet for my main activity:
private void runChatBot() {
translateOutput(input, targetLanguage); //calls the translate method of the TranslateAPI class
System.out.println("translatedOutput value in MainActivity: " + translatedOutput);
//Use translated output here
}
What happens here is that the print statement in runChatbot() executes before the call to the translation API. This is not the desired behaviour, as I would like the translateOutput() method to execute fully before any following instructions.
Any help is much appreciated. Thanks in advance :)
UPDATE: Current code after initial answers
TranslateAPI - Declarations
public interface Callbacks {
void onTranslationReceived(String result);
void onTranslationFailed();
}
TranslateAPI - translate()
public void translate(final String textToTranslate, final String fromLanguage, final String toLanguage) {
mService.getTranslation(textToTranslate, URLEncoder.encode(fromLanguage + "|" + toLanguage))
.enqueue(new Callback<TranslatedData>() {
#Override
public void onResponse(Response<TranslatedData> response, Retrofit retrofit) {
String output =
String.format(response.body().responseData.translatedText);
String.format("Translation of: %s, %s->%s = %s", textToTranslate,
fromLanguage, toLanguage, response.body().responseData.translatedText);
System.out.println("Result: " + output);
translation = output;
System.out.println("The result of the field translation is: " + translation);
}
#Override
public void onFailure(Throwable t) {
System.out.println("[DEBUG]" + " RestApi onFailure - " + "");
}
});
}
MainActivity:
#Override
public void onTranslationReceived(String result) {
runChatBot();
}
#Override
public void onTranslationFailed() {
//Handle failure here
}
public void runChatBot() {
translatedOutput = translateAPI.getTranslation();
System.out.println("translatedOutput value in MainActivity: " + translatedOutput);
userOutputView.setText(translatedOutput);
ttsResponse(translatedOutput, TTSLanguage);
setVisualCue(chatBot.getVisualMatch());
chatBot.clearResults();
}
Since your translate() method is asynchronous, you should define a callback in TranslateAPI to send the result back to your Activity when the result is received. By doing this, you would then only perform work on the translation result once you know you've received a response from TranslateAPI.
So in TranslateAPI you would define a callback interface:
public interface Callbacks {
void onTranslationReceived(String result);
}
Then you would have your Activity implement TranslateAPI.Callbacks and implement the callback like this:
public void onTranslationReceived(String result) {
//do something with the result
runChatBot(result); //or something similar
}
Then, once you receive the response in the callback, you do whatever it is you have to do with the translation result. This way, you know you will never be executing anything on the translated result until the translation is complete.
EDIT IN RESPONSE TO COMMENTS
So in order to actually send the response to your Activity once the translate response is received, you need to pass a reference to your Activity into TranslateAPI. Since your Activity implements the callbacks, you can simply pass this in: TranslateAPI translateApi = new TranslateAPI(this);
Then in your TranslateAPI, you'll need to take this reference and use it as the "listener" of your callbacks. So in TranslateAPI you'll want to define a variable like this private Callbacks listener; and you'll assign this in your TranslateAPI constructor the value that's passed in from the Activity. So your TranslateAPI constructor might look like this:
public TranslateAPI(Callbacks listener) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ENDPOINT)
.addConverterFactory(GsonConverterFactory.create())
.build();
mService = retrofit.create(TranslateService.class);
//this is the line you would add...
this.listener = listener;
}
And then in your onResponse() callback in TranslateAPI, you simply pass the value to the listener, which passes it back to the implemented method in your Activity. Like this:
#Override
public void onResponse(Response<TranslatedData> response, Retrofit retrofit) {
String output = String.format(response.body().responseData.translatedText);
String.format("Translation of: %s, %s->%s = %s", textToTranslate, fromLanguage, toLanguage, response.body().responseData.translatedText);
System.out.println("Result: " + output);
translation = output;
System.out.println("The result of the field translation is: " + translation);
//this is the line you would add...
listener.onTranslateReceived(translation);
}
Hope this helps clarify things. Let me know if you have any more questions!
this happens because code is executed asynchronous. Your retrofit network request takes some time to complete, so by default, java will execute the next line of code before it concludes. To solve this you must use the retrofit callback onResponse and onFailure.
I sugest you to create a new interface and pass it on constructor os method of your TranslateApiCode. Something like:
public interface OnTranslate {
void onSuccess(); // here you can pass any object you need later
void onError(); // here you can pass any object you need later
}
public String translate(final String textToTranslate, final String fromLanguage, final String toLanguage) {
mService.getTranslation(textToTranslate, URLEncoder.encode(fromLanguage + "|" + toLanguage))
.enqueue(new Callback<TranslatedData>() {
#Override
public void onResponse(Response<TranslatedData> response, Retrofit retrofit) {
String output =
String.format(response.body().responseData.translatedText);
String.format("Translation of: %s, %s->%s = %s", textToTranslate,
fromLanguage, toLanguage, response.body().responseData.translatedText);
System.out.println("Result: " + output);
translation = output;
System.out.println("The result of the field translation is: " + translation);
myOnTranslateVariable.onSuccess();
}
#Override
public void onFailure(Throwable t) {
System.out.println("[DEBUG]" + " RestApi onFailure - " + "");
myOnTranslateVariable.onError();
}
});
return translation;
}
private void runChatBot() {
translateOutput(input, targetLanguage, new OnTranslate() {
void onSucess() {
System.out.println("translatedOutput value in MainActivity: " + translatedOutput);
}
void onError() {
System.out.println("some error happened");
}
}); //calls the translate method of the TranslateAPI class
//Use translated output here
}
Try Using Handler to notify when translation is completed and then perform the required operations. Thanks

Handle a Message

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

Communicate from Service to Activity via bound service

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

How to get IQ tag using smack Java?

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

Categories

Resources