I have a problem handling messages in a Thread. My run-method looks like this
public void run() {
Looper.prepareLooper();
parserHandler = new Handler {
public void handleMessage(Message msg) {
Log.i("","id from message: "+msg.getData.getString("id"));
// handle message
this.wait();
}
}
}
I have several Activities sending messages to this thread, like this:
Message parserMessage = new Message();
Bundle data = new Bundle();
data.putString("id", realId);
data.putString("callingClass", "CategoryList");
parserMessage.setData(data);
parserMessage.what = PARSE_CATEGORIES_OR_PRODUCTS;
parserHandler = parser.getParserHandler();
synchronized (parserHandler) {
parserHandler.notify();
Log.i("","message ID: " + parserMessage.getData().getString("id"));
}
parserHandler.sendMessage(parserMessage);
The problem is that the run-method logs "id from message: null" though "message ID" has a value in the Log-statement. Why does the message "lose" it's data when being send to the thread? Has it something to do with the notify? Thanks for your help
So I think I figured out the problem. It was the MessageQueu in combination with an OnScrollListener I used in an other location of my code. The onScrollListener was called multiple times and so the MessageQueu was blocked with messages from this listener.
Related
I have a bluetooth printer integrated to my app and if I do some transactions, I can print the receipt to the customer. I have a method to handle the printing of receipts. Currently, I can print only one receipt but I would like to print the receipts twice.
Should I run the for loop twice so the method which prints my receipt is executed twice.
private void printReceipt(final Transaction transaction) {
showProgressPopup(getString(R.string.printing_dialog_message));
Runnable printThread = new Runnable() {
#Override
public void run() {
final BitSet resultBit = new BitSet(1);
try {
final ReceiptMetadata receiptMetadata =
AirFiUtils.getPaymentDeviceReceiptMetaData(getAirlineProfile(),
AirFiUtils.getMerchantAccount(getAirFiActivity()));
if (null != receiptMetadata) {
PrinterManager.printReceipt(PrinterType.valueOf(receiptMetadata.getPrinter().get(0)),
ReceiptType.CASH, receiptMetadata, transaction, getActivity().getApplicationContext(),
transaction.isSignatureCard());
resultBit.set(0, true);
}
} catch (Exception e) {
LOG.error("Error in printing ", e);
resultBit.set(0, false);
}
}
};
new Thread(printThread).start();
}
use for loop inside your if statement e.g
if(your_condition){
for(int i=0;i<2;i++){
//your desired code to print receipt
}}
or call your specific function two time which is need to be print receipt by applying for loop
I have an interesting issue that I have been trying to fix for over a week. Its on Android and involves a service running in the background to send a message on an app.
It is quite complex so I'll list the stages below:
1 - User enters message
2 - User selects 'send' button which launches the apps main service (ComService/START_STICKY) and activity (HomeScreen) hides the EditText box used for the message, replacing it with a TextView with the words 'Sending'
3 - Service spawns worker thread
4 - Service gets entered text off of activity and connects to server
5 - Service sends the message and then gets result from server
6 - Service disconnects from server
7 - Service updates activity to show sent message and shows the edit text
box again, as well as hides the TextView with the 'Sending' word
The issue is with stage 7. It uses a handler and message to communicate with the activity, as well as a separate class which holds the state of all of the activities in the app (to check if the UI is ok to update), but I commented this out from the code and the issue still exists so it is not this. The current set up works completely fine when the debugger is attached without any issues (why there is no logcat) and on the odd occasion when closing the app down and starting it up again. The problem begins when the debugger is detached and the app closed (via recent apps) for over around 5 seconds. The service completed its job by sending the message, as the message is added to the database and the user on the other end gets it, it is only the updating of the UI that is a problem, everything else seems to work fine!
Before sending the message, the service also connects to the server if there are any unread messages to indicate to other users that the user just read it. It follows very similar steps as above but was commented out and the issue still stays the same.
Ill post the code for the relevant steps below:
Stage 2
// Starts service to communicate with the server to send a message
Intent service = new Intent(this, ComService.class);
service.putExtra(ComService.requestType, ComService.sendTextMessage);
startService(service);
Stage 3
// Run when the service is being created
#Override
public int onStartCommand(Intent newIntent, int flags, int startId)
{
intent = newIntent;
currentInstance = this;
// Launches processing thread
ServiceHelper serviceHelper = new ServiceHelper(newIntent, this);
serviceHelper.start();
return Service.START_STICKY;
}
Stage 4/5/6/7
// Sends a message with only text content
public void startText()
{
// Initialises the class holding activity data
StateManager sm = new StateManager(context);
// Gets the data ready to be sent
if(sm.getHomeScreen())
{
// Friend id and time
friendId = HomeScreen.getFriendId();
// Gets the message text
messageTextContent = HomeScreen.getTextMessage(); // STAGE 4
}
else
{
allGood = false;
}
try
{
// Checks if any errors
if(allGood)
{
// Checks if message to be sent is blank
if(!messageTextContent.equals("") & messageTextContent.equals(" ") & !(messageTextContent == "") & !(messageTextContent == " "))
{
// Connects
(sh.new Utility()).connect(); // STAGE 4
// Checks if logged in
if((sh.new CheckLogin()).start())
{
// Sends request
sh.getNetwork().sendData(ServiceHelper.sendMessageTextRequest);
// Sends the friend id who message is addressed to
sh.getNetwork().sendData(friendId);
// Gets message date
messageDate = sh.getNetwork().getDataAsString();
// Sends the message type
sh.getNetwork().sendData(textType);
// Sends the message text
sh.getNetwork().sendData(messageTextContent); // STAGE 5
// Gets the message number
messageNumber = Integer.parseInt(sh.getNetwork().getDataAsString());
// Gets result and check if successful
String result = sh.getNetwork().getDataAsString(); // STAGE 5
if(!result.equals(ServiceHelper.requestSuccessful))
{
// Not successful
allGood = false;
errorMessage = result;
}
else
{
// Successful and saves data to database
addDatabaseTextMessage();
}
// Sends received indicator
sh.getNetwork().sendData(ServiceHelper.receivedIndicator);
}
else
{
allGood = false;
errorMessage = tryAgainMsg;
}
// Closes connection
(sh.new Utility()).finishConnection(); // STAGE 6
// Gets current friend record
UserDatabase db = new UserDatabase(context);
FriendRecord fr = db.getFriendRecord(Integer.parseInt(friendId));
// Increments message numbers by one and updates database
fr.setTotalExchanged(fr.getTotalExchanged() + 1);
db.updateFriendRecord(fr);
}
else
{
allGood = false;
errorMessage = msgBlank;
}
}
else
{
allGood = false;
errorMessage = tryAgainMsg;
}
} catch(IOException e)
{
allGood = false;
errorMessage = checkConnectionMsg;
// Adds to log cat
Log.e(this.getClass().getSimpleName(), e.getMessage());
} catch(Exception e2)
{
allGood = false;
errorMessage = tryAgainMsg;
// Adds to log cat
Log.e(this.getClass().getSimpleName(), e2.getMessage());
}
// Decides on result
if(allGood)
{
// Refreshes the ui
if(sm.getHomeScreen()) // STAGE 6
{
Message msg = HomeScreen.homeScreenInterface.obtainMessage(HomeScreen.sendSuccess); // STAGE 7
HomeScreen.homeScreenInterface.sendMessage(msg); // STAGE 7
}
}
else
{
// Indicates error on ui
if(sm.getHomeScreen())
{
Message msg = HomeScreen.homeScreenInterface.obtainMessage(HomeScreen.messageSendError); // STAGE 7
msg.obj = errorMessage; // STAGE 6
HomeScreen.homeScreenInterface.sendMessage(msg); // STAGE 7
}
}
}
State 7 (updating UI)
// Deals with service responses
public static Handler homeScreenInterface = new Handler()
{
#Override
public void handleMessage(Message msg)
{
switch(msg.what)
{
...
...
case HomeScreen.sendSuccess:
// Enables and clears input
HomeScreen.messageInput.setEnabled(true);
HomeScreen.messageInput.setText("");
// Shows the message send menu and hides sending text
HomeScreen.sendMenu.setVisibility(View.VISIBLE);
HomeScreen.sendingText.setVisibility(View.GONE);
// Clears message variable
message = "";
attachment = null;
try
{
// Reloads the message list
messageFriendId = "";
currentInstance.loadMessageList(true);
} catch (Exception e)
{
currentInstance.loadingScreen.open("Error", "Try again later!", true, "Ok", currentInstance);
}
// Checks if the message is sending
isMessageSending = false;
break;
...
...
}
}
};
Try using Broadcast Receiver instead of a handler to refresh your ui.
http://developer.android.com/reference/android/content/BroadcastReceiver.html
private BroadcastReceiver bReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("UPDATE")) {
String text = intent.getStringExtra("output");
updateUI(text);
}
else if(intent.getAction().equals("RESTART")) {
//other stuff
Board.this.startService(i);
}
}
};
//from Service
Intent intent = new Intent();
intent.setAction("UPDATE");
intent.putExtra("output",modifiedSentence);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
//onStart
LocalBroadcastManager bManager = LocalBroadcastManager.getInstance(this);
IntentFilter filter = new IntentFilter();
filter.addAction("UPDATE");
filter.addAction("RESTART");
bManager.registerReceiver(bReceiver, filter);
//onPause
LocalBroadcastManager bManager = LocalBroadcastManager.getInstance(this);
bManager.unregisterReceiver(bReceiver);
I am building a chat application using asmack xmpp client. Chat works fine and I have implemented ChatStateListener but stateChanged method never gets called. Currently to get composing status I am parsing the message xml. Below is the message format for composing,text, active.
<message id='5ec7d' to='admin#testserver123.net' from='praveenraj#testserver123.net/682e3641' type='chat'><composing xmlns="http://jabber.org/protocol/chatstates" /></message>
<message id='9a93f22' to='admin#testserver123.net' from='praveenraj#testserver123.net/682e3641' type='chat'><body>hi</body><active xmlns="http://jabber.org/protocol/chatstates" /></message>
<message to='admin#testserver123.net' from='praveenraj#testserver123.net/682e3641' type='chat'><active xmlns="http://jabber.org/protocol/chatstates" /></message>
But parsing xml to get the composing status is not a good idea. Can someone help me to understand why stateChanged never get called.
I am working on a project right now using aSmack as well, this is how I solved the problem, hopefully it helps you out.
I assume that you have created an instance of ChatStateManager such as:
ChatStateManager chatStateManager = ChatStateManager.getInstance(connection);
Then to send the composing state, where connection is your current xmpp connection and currentChat is the Chat you created for the current conversation
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(connection != null){
try {
chatStateManager.setCurrentState(ChatState.composing, currentChat);
} catch (Exception e) {
e.printStackTrace();
}
}
}
The other client will send you a Packet with the different states, in the case below is a composing state
<message id='16vn2-83' to='jabberusername#ip-address' from='jabberusername#ip-address' type='chat'><thread>781de2f5-8883-4b16-a3b2-3bf7aff1efe9</thread><composing xmlns="http://jabber.org/protocol/chatstates" /></message>
Now this is where it gets fun, (to answer your question). I grab every incoming Packet and send it to a BroadcatsReceiver to notify me of it. Note that if the incoming packet has a null body that means it's not an actual message with text but a ChatState message.
if (packet.getBody() == null) {
Intent i = new Intent();
i.setAction(Constants.ACTION_TYPING_LISTENER);
i.putExtra(Constants.ACTION_EXTRA_WHO_TYPING, getSimpleUsername(packet.getFrom()));
if (isIncomingComposingMessage(msg.toXML().toString())) {
i.putExtra(Constants.ACTION_EXTRA_MESSAGESTATE, ChatState.composing.toString());
} else {
i.putExtra(Constants.ACTION_EXTRA_MESSAGESTATE, ChatState.paused.toString());
}
sendBroadcast(i);
}
And
public boolean isIncomingComposingMessage(String xmlMessage) {
if (xmlMessage.indexOf(ChatState.composing.toString()) == -1) {
return false;
} else {
return true;
}
}
I know this might be just a "workaround" and if somebody reading this has a better answer please post it so we can all learn from it.
Thank you and I hope it helps.
If you look-up the Asmack lib then you can see method updateChatState(Chat paramChat, ChatState paramChatState) will check whether your current state are same as old state , if yes then that method return false and this is the reason why you are not getting callback every time .
Why this happens ?
//Asmack lib method
private boolean updateChatState(Chat paramChat, ChatState paramChatState) {
ChatState localChatState = (ChatState) this.chatStates.get(paramChat);
if (localChatState != paramChatState) {
this.chatStates.put(paramChat, paramChatState);
return true;
}
return false;
}
If you want to receive callback every time you can do something like
below ,
public class ChatlListener implements MessageListener, ChatStateListener{
#Override
public void stateChanged(Chat paramChat, ChatState paramChatState) {
// this method will call only if status change , not on same status
}
#Override
public void processMessage(Chat paramChat, Message paramMessage) {
ChatStateExtension chatStateExtension = (ChatStateExtension) paramMessage.getExtension("http://jabber.org/protocol/chatstates") ;
Log(TAG,"Current chat status : " + chatStateExtension.getElementName());
}
}
I have been able to create the if statement that checks for the string and it returns the toast message that i created but it keeps showing the toast message every time i open the chat. even if the most recent message doesn't contain the string I am looking for so i am assume it isn't checking to see if it is the last message received and it doesn't check to see if it is unread. the code is below. the reason i am trying to do this is because my parents share a facebook account and i want an easy way to display if the message is signed mom or dad. the code below only has the check for mom once it works i will be adding the check for dad signature. I am using the open source message client Xabber. Thank you for help.
public void setVisibleChat(String account, String user) {
final boolean remove = !AccountManager.getInstance()
.getArchiveMode(account).saveLocally();
AbstractChat chat = getChat(account, user);
if (chat == null)
chat = createChat(account, user);
else {
// Mark messages as read and them delete from db if necessary.
final ArrayList<MessageItem> messageItems = new ArrayList<MessageItem>();
for (MessageItem messageItem : chat.getMessages()) {
if (!messageItem.isRead()) {
messageItem.markAsRead();
messageItems.add(messageItem);
}
if (chat.getLastText().contains("Mom") && (!messageItem.isRead()));{
Toast.makeText(Application.getInstance(), "Message from Mom!", Toast.LENGTH_SHORT).show();
}
}
Application.getInstance().runInBackground(new Runnable() {
#Override
public void run() {
Collection<Long> ids = getMessageIds(messageItems, remove);
if (remove)
MessageTable.getInstance().removeMessages(ids);
else
MessageTable.getInstance().markAsRead(ids);
}
});
}
visibleChat = chat;
}
You've got an extra semi-colon here
if (chat.getLastText().contains("Mom") && (!messageItem.isRead())); <------
So your next block of code containing the Toast show statement will always be executed.
Remove the semi-colon
Is there a tooling or maybe a log, where I can see what caused my application running on a android mobile phone, to hung or eventually crash?
I have programmed a signed application that is a runnable, it checks for messages on my server and send sms messages to a receiver, and after two or maybe 3 days, the application hungs or crashes.
How can I see what caused the crash?
Regards.
Shafqat
private void startservice() {
r = new Runnable()
{
public void run()
{
//execute the sms class and get the url
//build the url
SendSMS sms = null;
//TODO get the url from a database
Map<String, String> jsonitems = new JSONParser().parse(urlsmsservice+getDeviceId());
if(!jsonitems.isEmpty()){
sms = new SendSMS(context, jsonitems.get("PHONENUMBER").toString(), jsonitems.get("MESSAGE").toString());
sentReceiver.setCallbackUrl(jsonitems.get("CALLBACKURL").toString());
deliveredReceiver.setCallbackUrl(jsonitems.get("CALLBACKURL").toString());
sms.send();
}else{
Log.d(TAG, "No messages in Queue");
}
//handler.postDelayed(this, getInterval());
}
};
handler = new Handler();
thread = new Thread()
{
#Override
public void run() {
try {
while(thbool) {
sleep(getInterval());
handler.post(r);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
Make sure ADB tools are installed (they will be with the SDK). Then run adb logcat, which will show the system log output (useful is an exception is thrown). There are also free market applications which will show you the logcat buffer (aLogCat comes to mind).