Communication between an Application class and Service in Android - 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)

Related

Update view when a push notification is received

I would like to update a view from within an open activity when the device receives a push notification.
When a push notification is received the updateBalance function is executed,
a mysql database is queried and an amount is returned.
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private void updateBalance(String messageBody) {
h1 = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
bb = msg.getData();
String str = bb.getString("result");
Log.d(TAG,str);
Message msg=handler.obtainMessage()
}
};
t = new Thread(new MyRunnable(h1));
t.start();
try {
t.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I have another class
public class MyRunnable implements Runnable {
private Handler h2;
public MyRunnable(Handler h) {
this.h2 = h;
}
#Override
public void run() {
String name = "w12";
BalanceActivity NB = new BalanceActivity(name);
Message m = Message.obtain();
Bundle b = new Bundle();
b.putString("result", "10");
m.setData(b);
h2.sendMessage(m);
}
}
I have a MainActivity that I would like to update after the amount is returned. How would I do this possibly with another Handler and Runnable.
public class MainActivity extends Activity {
TextView TV = (TextView) findViewById(package.name.R.id.Balance);
}
Try to check your activity is currently in foreground. if yes then create method where you can update your view.
public static boolean isServiceRunning(Context context) {
Log.i(TAG, "Checking if service is running");
ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
boolean isServiceFound = false;
for (int i = 0; i < services.size(); i++) {
if (Constants.PACKAGE.equals(services.get(i).service.getPackageName())){
if (Constants.BACKGROUND_SERVICE_CLASS.equals(services.get(i).service.getClassName())){
isServiceFound = true;
}
}
}
Log.i(TAG, "Service was" + (isServiceFound ? "" : " not") + " running");
return isServiceFound;
}
Make use of Broadcast Receivers. Register local broadcast receiver in activity. Broadcast data when notification received.

What's the best way to communicate with a Service in every activity of my app without replicating the same code?

I implemented a Service and I use a Messenger with its handler as a communication bridge.
Every time that I start an activity I have to follow these steps:
1) create the service connection
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger(service);
try {
Message msg = Message.obtain(null, ConstantStuff.MSG_REGISTER_CLIENT);
msg.replyTo = mMessenger;
egoService.send(msg);
} catch (RemoteException e) {
Log.e("HELPER", "FAIL - Service crashed" + e.getMessage());
}
}
public void onServiceDisconnected(ComponentName className) {
mService = null;
}
};
2) create the messenger
final Messenger mMessenger = new Messenger(new ActivityOne.IncomingMessageHandler());
class IncomingMessageHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case ConstantStuff.MACRO_SEND_PWD:
if (msg.arg1 == 1) {
Log.e("PWD", "SUCCESS");
} else if (msg.arg1 == 0) {
Log.e("PWD", "FAIL");
}
break;
default:
super.handleMessage(msg);
}
}
}
3) bind the service to my activity
public void doBindService() {
this.bindService(new Intent(this, NetworkService.class), mConnection, Context.BIND_AUTO_CREATE);
isBound = true;
Log.e("HELPER", "DO BIND");
}
4) start using the service
private void sendPwd(String pwd) {
if (isBound) {
if (mService != null) {
try {
Bundle b = new Bundle();
b.putByte("Command", (byte) ConstantStuff.MACRO_SEND_PWD);
b.putString("Password", password);
b.putString("Param0", password);
b.putString("Param1", "dummy");
b.putString("Param2", "dummy");
b.putString("Param3", "dummy");
Message msg = Message.obtain(null, ConstantStuff.MSG_MACRO);
msg.setData(b);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (Exception e) {}
}
}
}
5) at the end of my task unbind the service from my activity
public void doUnbindService() {
if (isBound) {
if (mService != null) {
try {
Message msg = Message.obtain(null, ConstantStuff.MSG_UNREGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
Log.e("HELPER", "FAIL - DO UnBIND" + e.getMessage());
}
}
this.unbindService(mConnection);
isBound = false;
Log.e("HELPER", "DO UnBIND");
}
}
I need to communicate to my service in almost all the activities of my app and I'd like to not repeat all the code every time. Does extend all the activities to a father activity a good solution? Is it possible to write all the communication code in the "Application"?
In whichever Activities you want the service to interact with the UI, use "bindService", its callback methods "onServiceConnected" and "onServiceDisconnected" on those Activities. If you want the service to run even if app is closed, use startService with startsticky/startnonsticky/startforeground. For all the Activities you just need one service class. In your case you have already coded the service class which is perfect, and also an Activity. Now bind in rest of the Activities as mentioned in the beginning. I haven't used Messenger yet, so kindly make sure of that.

Failed to receive data over usb using Usbserial example

I am using following UsbSerial example from below link https://github.com/felHR85/SerialPortExample. I want receive data from over usb from the device shown in the photo.
Device is basically a counter machine which is sending counter data over serial port.
I am able to connect device and open port from it but unable to read data stream from it. Below is the code used. code is not giving any error
Mainactivity class
public class MainActivity extends AppCompatActivity {
/*
* Notifications from UsbService will be received here.
*/
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case UsbService.ACTION_USB_PERMISSION_GRANTED: // USB PERMISSION GRANTED
Toast.makeText(context, "USB Ready", Toast.LENGTH_SHORT).show();
break;
case UsbService.ACTION_USB_PERMISSION_NOT_GRANTED: // USB PERMISSION NOT GRANTED
Toast.makeText(context, "USB Permission not granted", Toast.LENGTH_SHORT).show();
break;
case UsbService.ACTION_NO_USB: // NO USB CONNECTED
Toast.makeText(context, "No USB connected", Toast.LENGTH_SHORT).show();
break;
case UsbService.ACTION_USB_DISCONNECTED: // USB DISCONNECTED
Toast.makeText(context, "USB disconnected", Toast.LENGTH_SHORT).show();
break;
case UsbService.ACTION_USB_NOT_SUPPORTED: // USB NOT SUPPORTED
Toast.makeText(context, "USB device not supported", Toast.LENGTH_SHORT).show();
break;
}
}
};
private UsbService usbService;
private TextView display;
private EditText editText;
private MyHandler mHandler;
private final ServiceConnection usbConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
usbService = ((UsbService.UsbBinder) arg1).getService();
usbService.setHandler(mHandler);
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
usbService = null;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler = new MyHandler(this);
display = (TextView) findViewById(R.id.textView1);
editText = (EditText) findViewById(R.id.editText1);
Button sendButton = (Button) findViewById(R.id.buttonSend);
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!editText.getText().toString().equals("")) {
String data = editText.getText().toString();
if (usbService != null) { // if UsbService was correctly binded, Send data
display.append(data);
usbService.write(data.getBytes());
}
}
}
});
}
#Override
public void onResume() {
super.onResume();
setFilters(); // Start listening notifications from UsbService
startService(UsbService.class, usbConnection, null); // Start UsbService(if it was not started before) and Bind it
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(mUsbReceiver);
unbindService(usbConnection);
}
private void startService(Class<?> service, ServiceConnection serviceConnection, Bundle extras) {
if (!UsbService.SERVICE_CONNECTED) {
Intent startService = new Intent(this, service);
if (extras != null && !extras.isEmpty()) {
Set<String> keys = extras.keySet();
for (String key : keys) {
String extra = extras.getString(key);
startService.putExtra(key, extra);
}
}
startService(startService);
}
Intent bindingIntent = new Intent(this, service);
bindService(bindingIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
private void setFilters() {
IntentFilter filter = new IntentFilter();
filter.addAction(UsbService.ACTION_USB_PERMISSION_GRANTED);
filter.addAction(UsbService.ACTION_NO_USB);
filter.addAction(UsbService.ACTION_USB_DISCONNECTED);
filter.addAction(UsbService.ACTION_USB_NOT_SUPPORTED);
filter.addAction(UsbService.ACTION_USB_PERMISSION_NOT_GRANTED);
registerReceiver(mUsbReceiver, filter);
}
/*
* This handler will be passed to UsbService. Data received from serial port is displayed through this handler
*/
private static class MyHandler extends Handler {
private final WeakReference<MainActivity> mActivity;
public MyHandler(MainActivity activity) {
mActivity = new WeakReference<>(activity);
}
#Override
public void handleMessage(Message msg) {
mActivity.get().display.append("Handle:");
switch (msg.what) {
case UsbService.MESSAGE_FROM_SERIAL_PORT:
String data = (String) msg.obj;
mActivity.get().display.append(data);
break;
}
}
}
}
I know it's bit late, however just to help others who might come across similar issue, did you find solution to your problem? If not, I cannot see the other java file corresponding to the service (USBService.java) as described in the example referred by you. The same file contains following code snippet which you would like to debug to find out what's going wrong (could be a problem with byte to string conversion or so). Hope this helps.
/*
* Data received from serial port will be received here. Just populate onReceivedData with your code
* In this particular example. byte stream is converted to String and send to UI thread to
* be treated there.
*/
private UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback()
{
#Override
public void onReceivedData(byte[] arg0)
{
try
{
String data = new String(arg0, "UTF-8");
if(mHandler != null)
mHandler.obtainMessage(MESSAGE_FROM_SERIAL_PORT,data).sendToTarget();
} catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
}
};

Android Sms Receiver Result to Main Activity

MainActivity.java
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.anaekran);
Thread t = new Thread(new Runnable() {
public void run() {
String smsMsj = getIntent().getStringExtra("sms");
if(smsMsj != null){
Toast.makeText(getApplication(), smsMsj, 2).show();
}
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
}
}
SmsReceiver.java
public class SmsReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Bundle mesaj = intent.getExtras();
SmsMessage[] smsMessage = null;
String msj = "";
if(mesaj!= null){
Object[] pdus = (Object[])mesaj.get("pdus");
smsMessage = new SmsMessage[pdus.length];
for(int i = 0; i < pdus.length; i++){
smsMessage[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
msj = smsMessage[i].getMessageBody();
}
Intent mIntent = new Intent(context, SmsReceiver.class);
mIntent.putExtra("sms", msj);
}
}
}
My receiver working correctly but i have one problem when message coming i want to show on my MainAcitivty toast, so i create mIntent in receiver class, and then im use putExtra method.
But not working, sory for my bad english and thank you :)
Perhaps using explicit Intent and starting it could help you, hm? :)
Intent mIntent = new Intent(context, MainActivity.class);
mIntent.putExtra("sms", msj);
context.startActivity(mIntent);
Your mistake is that you construct your new Intent with SmsReceiver.class (but you need to launch MainActivity) and that you do not start any activity with such an intent.
Edit 1: Also, pay attention - you are trying to run a toast inside your worker thread. This is not possible. Remove your anonymous Thread and move your toast code to your onCreate(Bundle):
protected void onCreate(Bundle saveState){
....
String smsMsj = getIntent().getStringExtra("sms");
if(smsMsj != null){
Toast.makeText(getApplication(), smsMsj, 2).show();
}
....
}
Edit 2: Moreover, your duration parameter in Toast.makeText(..) is set to 2. This does not correspond to any magic constant in Toast class. You have to use one of the constants: Toast.LENGTH_LONG or Toast.LENGTH_SHORT. So, rewrite your code to:
Toast.makeText(getApplication(), smsMsj, Toast.LENGTH_SHORT);

What is the proper way to update activity based on Network responses?

I am implementing an application which is kind of VOIP application. So my application is kind of network application. Now I want to implement two part in my application, one is GUI part and one is network part. My GUI part will just contain activities and handling of user interaction. My Network part should handle all network related activities like handling incoming network data and sending data to network based on GUI interaction. Now whenever there is any incoming data, I want to update some activity whose reference is not there in Network module. So what could be the best way to update activity from some other class? In my case some other class is my Network class. So in short I would like to ask that what should be the architecture in such scenario? i.e. Network part should run in separate thread and from there it should update GUI?
Depending on the type/size of data you need to send to the activity, you can use one of a number of options.
Use one of the methods described here.
Use a BroadcastReceiver: register it in the Activity and then fire off matching Intents in the Service that handles the networking code.
Make your Activity bind to your Service and then pass in a Handler that you send Messages to.
I have written apps like this, and I prefer the Handler method. In fact I have written an Abstract Activity class to do all the hard work and simply extend it in any activity that want to be notified of a change.
To Use the following code, just get your Activity to extend UpdatableActivity and override the dataUpdated() method. This method is called when your Service notifies the handler that data has been updated. In the Service code put your code to do an update in the update() method (Or modify to call your existing code). This allows an activity to call this.updateService() to force an update. The service can call the sendMessageToUI() method to notify all interested activities that the data has been updated.
Here is what the abstract activity looks like:
public abstract class UpdatableActivity extends Activity {
public static final String TAG = "UpdatableActivity (Abstract)";
private final Messenger mMessenger = new Messenger(new IncomingHandler());
private Messenger mService = null;
private boolean mIsBound;
protected class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
if (Constants.LOG_DEBUG) Log.d(TAG, "Service has notified us of an update: ");
switch (msg.arg1) {
case UpdateService.MSG_DATA_UPDATED:
dataUpdated();
break;
default: super.handleMessage(msg);
}
}
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger(service);
try {
Message msg = Message.obtain(null, UpdateService.MSG_REGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
// In this case the service has crashed before we could even do anything with it
}
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been unexpectedly disconnected - process crashed.
mService = null;
}
};
/**Override this method in you acctivity to handle the update */
public abstract void dataUpdated();
void doBindService() {
if (Constants.LOG_DEBUG) Log.d(TAG, "Binding to service...");
bindService(new Intent(this, UpdateService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
void doUnbindService() {
if (mIsBound) {
// If we have received the service, and hence registered with it, then now is the time to unregister.
if (mService != null) {
try {
Message msg = Message.obtain(null, UpdateService.MSG_UNREGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
// There is nothing special we need to do if the service has crashed.
}
}
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
}
}
public void updateService() {
if (Constants.LOG_DEBUG) Log.d(TAG,"Updating Service...");
if (mIsBound) {
if (mService != null) {
try {
Message msg = Message.obtain(null, UpdateService.MSG_SET_INT_VALUE, UpdateService.MSG_DO_UPDATE, 0);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
if (Constants.LOG_ERROR) Log.e(TAG,Log.getStackTraceString(e));
}
}
} else {
if (Constants.LOG_DEBUG) Log.d(TAG, "Fail - service not bound!");
}
}
pu
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.doBindService();
}
#Override
protected void onDestroy() {
super.onDestroy();
try {
doUnbindService();
} catch (Throwable t) {
if (Constants.LOG_ERROR) Log.e(TAG, "Failed to unbind from the service", t);
}
}
}
And here is what the Service looks Like:
public class UpdateService extends Service {
public static final String TAG = "UpdateService";
public static final int MSG_DATA_UPDATED = 0;
public static final int MSG_REGISTER_CLIENT = 1;
public static final int MSG_UNREGISTER_CLIENT = 2;
public static final int MSG_DO_UPDATE = 3;
public static final int MSG_SET_INT_VALUE = 4;
private static boolean isRunning = false;
private Handler handler = new IncomingHandler();
private final Messenger mMessenger = new Messenger(handler);
private ArrayList<Messenger> mClients = new ArrayList<Messenger>(); // Keeps track of all current registered clients.
#Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
class IncomingHandler extends Handler { // Handler of incoming messages from clients.
#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;
case MSG_SET_INT_VALUE:
switch (msg.arg1) {
case MSG_DO_UPDATE:
if (Constants.LOG_DEBUG) Log.d(TAG,"UI has asked to update");
update();
break;
}
break;
default:
super.handleMessage(msg);
}
}
}
private void sendMessageToUI() {
if (Constants.LOG_DEBUG) Log.d(TAG, "Notifying "+mClients.size()+" UI clients that an update was completed");
for (int i=mClients.size()-1; i>=0; i--) {
try {
// Send data as an Integer
mClients.get(i).send(Message.obtain(null, MSG_SET_INT_VALUE, MSG_DATA_UPDATED, 0));
} catch (RemoteException e) {
// The client is dead. Remove it from the list; we are going through the list from back to front so this is safe to do inside the loop.
mClients.remove(i);
}
}
}
public static boolean isRunning()
{
return isRunning;
}
#Override
public void onCreate() {
super.onCreate();
isRunning = true;
if (Constants.LOG_DEBUG) Log.d(TAG, "Service Started");
update();
}
#Override
public void onDestroy() {
if (Constants.LOG_DEBUG) Log.d(TAG, "Service Destroyed");
isRunning = false;
}
private void update() {
/**Your code to do an update goes here */
}
}
Yes, personally i think that the network and UI should be in separate threads. The way I tend to communicate between the two, which is probably not the recommended proper way, but it works for me, is to create a global variable in your application class. hope this helps a little
I would directly post to the main UI thread,
Handler mHandler = new Handler(Looper.getMainLooper());
mHandler.post(new Runnable() {...});

Categories

Resources