In my app, I am getting my messages instantly from my server via pusher. I have created a service designated to handle connections and firing broadcast messages to other activities in my app.
The problem that I face now is to have this service run in a new thread to have it still run even when my app goes to the background. I've found from this that I should create and connect it to the "service thread", but I cannot find examples for it with pusher.
If anyone can, could you please provide an example to do so? If not, insights to writing code with these "service threads" would be helpful as well. Thanks in advance for the help :D
PusherService.java
public class PusherService extends Service {
private static final String TAG = "PusherService";
private Pusher pusher = new Pusher("myKey");
private Channel channel = pusher.subscribe("cafe_channel");
private JSONObject pusherJSONObj;
private Order order;
public PusherService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//this service will run until we stop it
setupPusher();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
}
private void setupPusher() {
Log.d(TAG, System.currentTimeMillis()+"");
channel.bind("customer_order", new SubscriptionEventListener() {
#Override
public void onEvent(String channelName, String eventName, final String data) {
Intent broadcastIntent = new Intent();
try {
pusherJSONObj = new JSONObject(data);
order = new Order(pusherJSONObj);
broadcastIntent.setAction("customer_order");
broadcastIntent.putExtra("message", "success");
broadcastIntent.putExtra("order", order);
} catch (JSONException e) {
e.printStackTrace();
Log.d("Pusher", "conversion failed");
broadcastIntent.setAction("customer_order");
broadcastIntent.putExtra("message", "JSON conversion error");
}
sendBroadcast(broadcastIntent);
}
});
pusher.connect();
}
}
OrdersActivity.java
private BroadcastReceiver pusherReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equalsIgnoreCase("customer_order")) {
adapter.newOrder((Order) intent.getParcelableExtra("order"));
}
}
};
It turns out that multithreading on one process does not solve my problem.
So instead, I split the service into a new process, which will keep the service running independent of the status of the main thread & process. Tested and found that service does not stall when my activities go background.
Related
Android will kill some service when memory is not enough.
Like this:
I know I can use foreground service to prohibit android to kill my service
public class MyService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
try {
Notification notification = new Notification(R.mipmap.ic_launcher,"this is service", System.currentTimeMillis());
Intent intent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,intent , 0);
notification.setLatestEventInfo(this, "myapp", "myservice", contentIntent);
notification.flags =Notification.FLAG_AUTO_CANCEL;
startForeground(123,notification);
}
catch(Exception e)
{
stopSelf();
}
}
#Override
public void onDestroy() {
super.onDestroy();
stopForeground(true);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
}
But this will display a notification on screen
I would rather kill service than display notification, but I also don't want to display stopped message.
I found some app, it can display no message when android kills it.
e.g. Screen Dimmer
How can I prohibit android to display app stopped message?
Check this: https://stackoverflow.com/a/32229266/2965799
According to that I have used the following code to handle the exception. I wanted to display another message so I added my own message however if you use his answer there will be no messages.
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
new Thread() {
#Override
public void run() {
Looper.prepare();
Toast.makeText(getActivity(),"Your message", Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
try
{
Thread.sleep(4000); // Let the Toast display before app will get shutdown
}
catch (InterruptedException e) { }
System.exit(2);
}
});
One way is to implement a UncaughtExceptionHandler with your own custom failure code. The API to install your handler is this:
public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh);
The class is documented here. As a very basic example:
import java.lang.Thread.UncaughtExceptionHandler;
public final class CrashHandler implements UncaughtExceptionHandler {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
android.util.Log.wtf("My app name", "Oops, caught it dying on me!");
}
}
A full working example is available here.
I want to check some web API and do something per x minutes. I think I should write a service on Android (is there any other solution?).
But how can do that?
I am thinking about writing a service class and in the manifest file I should add this line:
<service
android:name="com.xx.yy.noti_check"
android:enabled="true"
>
</service>
And in my noti_check class I check my web API like this on onStartCommand:
public class noti_check extends Service {
Context mcont;
private Handler myhandler ;
private long RETRY_TIME = 15000;
private long START_TIME = 2000;
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onStart(Intent intent, int startId) {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mcont=this;
myhandler= new Handler();
myhandler.postDelayed(myRunnable, START_TIME);
return Service.START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
try {
myhandler.removeCallbacks(myRunnable);
}
catch (Exception e) {
// TODO: handle exception
}
}
private Runnable myRunnable = new Runnable() {
public void run() {
try {
new get_notifyalert(mcont).execute("") ;
}
catch (Exception e) {
// TODO: handle exception
}
myhandler.postDelayed(myRunnable, RETRY_TIME);
}
};
}
Is this is the right way?
Is this the right way?
No. Only have a service running when it is actively delivering value to the user. Watching the clock tick is not actively delivering value to the user. Use AlarmManager for periodic work like this.
I have asked this question here but it was marked as duplicate -
however I didn't find any solution helpful mentioned in comments.
Here, I am asking again with more details ...
I am doing a sample app (PoC) on HCE and using HostApduService as per Android user guide. I have created two apps
1) ReaderApp - acting as card reader
2) HCEApp - emulating a card
In HCEApp, I have created a class 'MyService' extending HostApduService
public class MyService extends HostApduService {
private int messageCounter;
private final String TAG = "MyService";
Intent mIntent;
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate");
mIntent = new Intent(this, MyActivity.class);
mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(mIntent);
}
/**
* returned bytes will be sent as response. This method runs in Main thread
* so return ASAP.
*/
#Override
public byte[] processCommandApdu(byte[] apdu, Bundle extras) {
if (selectAidApdu(apdu)) {
Log.i(TAG, "Application selected");
return getWelcomeMessage();
} else {
Log.i(TAG, "Received: " + new String(apdu));
return getNextMessage();
}
}
private byte[] getWelcomeMessage() {
return "Hello Desktop!".getBytes();
}
private byte[] getNextMessage() {
return ("Message from android: " + messageCounter++).getBytes();
}
private boolean selectAidApdu(byte[] apdu) {
if (apdu != null) {
for (byte b : apdu) {
System.out.printf("0x%02X", b);
}
}
return apdu.length >= 2 && apdu[0] == (byte) 0
&& apdu[1] == (byte) 0xa4;
}
#Override
public void onDeactivated(int reason) {
Log.i(TAG, "Deactivated: " + reason);
}
#Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}
As you can see in onCreate(), I am launching MyActivity provides user to enter some information and needs to be sent back to MyService.
I think I can not use binding as 'onBind()' is declared final in HostApduService as below
#Override
public final IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
Please let me know if I am understading it correctly. Appreciate any help.
Thanks
iuq
Whether you can use onBind or not I do not know, but I recently worked with a BroadcastReceiver from which I had to start a Service. You cannot bind a Service from a BroadcastReceiver according to docs, you can only start it. I needed to send some data to the Service from my BroadcastReceiver at some later point, and since the binder techniques was not available to me, I had to find a different way to communicate with the Service, much like your case where you don't have a reference to it.
I did some research but could not find any solution, but then I remembered that you can pass intent data with the startService(intent) call. I start my Service work in onCreate instead, as onCreate is only called once when the Service is created.
In your Activity
public void sendDataToService(){
Intent intent = new Intent(context, MyService.class);
intent.putExtra("message", SOME_DATA);
context.startService(intent);
}
In your Service
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Check if intent has extras
if(intent.getExtras() != null){
// Get message
int message = intent.getExtras().getInt("message");
}
return START_NOT_STICKY;
}
This may be some sort what of a hack since "startService" does not sound like it should be used to send messages, and am not sure if this is exactly what you need, but it worked for me, so I hope it works for you. Cheers
Edit: BTW. I use it to tell a LocationService that a particular activity no longer want location updates.
I ended up taking a different approach to solving this same problem. When I bind to my HostApduService subclass, I grab a handle to the Messenger interface returned by the HostApduService onBind implementation.
Here's some sample code. This would all go in your activity implementation (calling it MyActivity here, communicating with MyHostApduServiceSubclass). Here's what MyActivity would need to include:
private Messenger mAPDUMessenger;
...
#Override
protected void onStart() {
super.onStart();
Context context = getApplicationContext();
Intent apduIntent = new Intent(montext, ContactlessApduService.class);
context.bindService(apduIntent, mAPDUConnection, Context.BIND_AUTO_CREATE);
}
...
private ServiceConnection mAPDUConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
// The HostApduService has a final override on the onBind() service method that returns
// an IMessageHandler interface that we can grab and use to send messages back to the
// terminal - would be better to get a handle to the running instance of the service so
// that we could make use of the HostApduService#sendResponseApdu public method
mAPDUMessenger = new Messenger(service);
registerAPDUMessengerIntentFilters();
// ^ This method sets up my handlers for local broadcast messages my BroadcastReceiver processes.
}
...
}
...
private void registerAPDUMessengerIntentFilters() {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(MyActivity.this);
IntentFilter intentFilter = new IntentFilter(MyHostApduServiceSubclass.ACTION_PPSE_APDU_SELECT);
lbm.registerReceiver(apduMessageBroadcastReceiver, intentFilter);
}
...
BroadcastReceiver apduMessageBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(MyHostApduServiceSubclass.ACTION_PPSE_APDU_SELECT)) {
sendResponseApdu(MyActivity.PPSE_APDU_SELECT_RESPONSE_BYTES);
}
}
};
...
public final void sendResponseApdu(byte[] responseApdu) {
Message responseMsg = Message.obtain(null, MyHostApduServiceSubclass.MSG_RESPONSE_APDU);
// ^ Note here that because MSG_RESPONSE_APDU is the message type
// defined in the abstract HostApduService class, I had to override
// the definition in my subclass to expose it for use from MyActivity.
// Same with the KEY_DATA constant value below.
Bundle dataBundle = new Bundle();
dataBundle.putByteArray(MyHostApduServiceSubclass.KEY_DATA, responseApdu);
responseMsg.setData(dataBundle);
try {
mAPDUMessenger.send(responseMsg);
} catch (RemoteException e) {
// Do something with the failed message
}
}
And then your HostApduService subclass would just need to send a broadcast to your activity indicating what APDU command was received. Here is what would need to be included in MyHostApduServiceSubclass:
public static final String ACTION_PPSE_APDU_SELECT = "ACTION_PPSE_APDU_SELECT";
// Abstract super class constant overrides
public static final String KEY_DATA = "data";
public static final int MSG_RESPONSE_APDU = 1;
#Override
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
Context context = getApplicationContext();
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
if (Arrays.equals(MyHostApduServiceSubclass.PPSE_APDU_SELECT_BYTES, commandApdu)) {
lbm.sendBroadcast(new Intent(ACTION_PPSE_APDU_SELECT));
}
return null;
// ^ Note the need to return null so that the other end waits for the
// activity to send the response via the Messenger handle
}
Is there any way to directly communicate with a WallpaperService from an Activity? It doesn't look like I can use the normal service communication classes because the onBind method is declared final in the WallpaperService class I'm extending. Worth noting that I'm referring to my WallpaperService not any.
Any workarounds if this isn't possible?
My solution was to use local sockets. I created an instance of a LocalServerSocket in the constructor of my wallpaper's Engine. Here's a quick implementation. Server runs on a separate thread and is directly tied to the lifecycle of MyEngine. The thread will stop when continueSocket is set to false. This happens onDestroy. Problem is that LocalServerSocket.accept() blocks until there's something to do. The workaround is to send a message to our own server so it will run through the loop again and check continueSocket (which is now false), closing the server. Check the closeSocketServer method. I have it running in onDestroy in the example but you might want to use it elsewhere like onSurfaceDestroyed and add your own sanity checks.
public class MyWallpaperService extends WallpaperService {
#Override
public Engine onCreateEngine() {
return new MyEngine();
}
private class MyEngine extends Engine {
private boolean continueSocket = true;
MyEngine() {
new Thread() {
#Override
public void run() {
try {
LocalServerSocket server = new LocalServerSocket("MyAddress");
Log.d("SERVER READY", "Server is ready.");
while(continueSocket) {
LocalSocket receiver = server.accept();
if(receiver != null) {
InputStream input = receiver.getInputStream();
byte[] data = IOUtils.toByteArray(input);
Log.d("GOT DATA", new String(data));
}
}
server.close();
} catch (IOException ex) {
Log.wtf("IOEXCEPTION", ex);
}
}
}.start();
}
#Override
public void onDestroy() {
closeSocketServer();
super.onDestroy();
}
private void closeSocketServer() {
continueSocket = false;
try {
LocalSocket socket = new LocalSocket();
socket.connect(new LocalSocketAddress("MyAddress"));
socket.getOutputStream().write(new byte[0]);
socket.getOutputStream().close();
socket.close();
} catch (IOException ex) {
//
}
}
}
}
And in my Activity it can be as simple as this...
try {
LocalSocket sender = new LocalSocket();
sender.connect(new LocalSocketAddress("MyAddress"));
String data = "Hello world!";
Log.d("SENT DATA", data);
sender.getOutputStream().write(data.getBytes());
sender.getOutputStream().close();
sender.close();
} catch (IOException ex) {
Log.wtf("IOEXCEPTION", ex);
}
Logcat ends up looking like this:
D/SERVER READY﹕ Server is ready. (when the wallpaper starts up)
D/SENT DATA﹕ Hello world! (when the activity sends data)
D/GOT DATA﹕ Hello world! (when the wallpaper gets the data)
In your WallpaperService onCreateEngine:
IntentFilter intentFilter = new IntentFilter("your.package.your.action");
MyBroadcastReceiver mReceiver = new MyBroadcastReceiver(mRenderer);
LocalBroadcastManager.getInstance(getApplicationContext())
.registerReceiver(mReceiver, intentFilter);
In mRenderer's class:
public void receiveCommand(int i) {
Log.d("got", String.valueOf(i));
}
Receiver class:
public class MyBroadcastReceiver extends BroadcastReceiver {
private final MyRenderer _mRenderer;
public MyBroadcastReceiver(MyRenderer mRenderer) {
_mRenderer = mRenderer;
}
#Override
public void onReceive(Context context, Intent intent) {
_mRenderer.receiveCommand(intent.getExtra("msg", -1));
}
}
Now call from activity:
Intent in = new Intent();
in.setAction("your.package.your.action");
in.setExtra("msg", 42);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(in);
I'm trying to download multiple files using IntentService. The IntentService donwloads them okey as expected one at a time, the only problem is that when the Internet is down the intent service will not stop the donwload rather it will get stuck on the current thread. If I manage to stop the current thread it will continue running the other threads stored in its queue even though the internet connection is down.
It was suggested in another post that I use LinkedBlockingQueue and create my own Worker thread that constantly checks this queue for new threads. Now I know there are some increased overheads and thus performance issues when creating and destroying threads but that's not a concern in my case.
At this point, All I want to do is understand how IntentService works which as of yet I don't (and I have looked at the code) and then come up with my own implementation for it using LinkedBlockingQueue controlled by a Worker thread. Has anyone done this before ? Could provide a working example, if you feel uncomfortable providing the source code, pseudo code is fine by me. Thanks!
UPDATE: I eventually implemented my own Intent Service using a thread that has a looper which checks the queue which in turn stores the intents passed from the startService(intent).
public class MyIntentService extends Service {
private BlockingQueue<Download> queue = new LinkedBlockingQueue<Download>();
public MyIntentService(){
super();
}
#Override
public void onCreate() {
super.onCreate();
new Thread(queueController).start();
Log.e("onCreate","onCreate is running again");
}
boolean killed = false;
Runnable queueController = new Runnable() {
public void run() {
while (true) {
try {
Download d =queue.take();
if (killed) {
break;
}
else {
d.downloadFile();
Log.e("QueueInfo","queue size: " + queue.size());
}
}
catch (InterruptedException e) {
break;
}
}
Log.e("queueController", "queueController has finished processing");
Log.e("QueueInfo","queue size: " + queue.toString());
}
};
class Download {
String name;
//Download files process
void downloadFile() {
//Download code here
}
Log.e("Download","Download being processed is: " + name);
}
public void setName(String n){
name = n;
}
public String getName(){
return name;
}
}
public void killService(){
killed = true;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Download d = new Download();
d.setName(intent.getStringExtra("VIDEOS"));
queue.add(d);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.e("stopSelf","stopSelf has been just called to stop the Service");
stopSelf();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
I'm not so sure about the START_NOT_STICKY in the onStartCommand() method. If it's the right flag to return or not. Any clarification on that would be appreciated!
UPDATE: I eventually implemented my own Intent Service using a thread that has a looper which checks the queue which in turn stores the intents passed from the startService(intent).
public class MyIntentService extends Service {
private BlockingQueue<Download> queue = new LinkedBlockingQueue<Download>();
public MyIntentService(){
super();
}
#Override
public void onCreate() {
super.onCreate();
new Thread(queueController).start();
Log.e("onCreate","onCreate is running again");
}
boolean killed = false;
Runnable queueController = new Runnable() {
public void run() {
while (true) {
try {
Download d =queue.take();
if (killed) {
break;
}
else {
d.downloadFile();
Log.e("QueueInfo","queue size: " + queue.size());
}
}
catch (InterruptedException e) {
break;
}
}
Log.e("queueController", "queueController has finished processing");
Log.e("QueueInfo","queue size: " + queue.toString());
}
};
class Download {
String name;
//Download files process
void downloadFile() {
//Download code here
}
Log.e("Download","Download being processed is: " + name);
}
public void setName(String n){
name = n;
}