Firebase: onDisconnect() in a service - android

I am making a project in which i have to
configure realtime internet connection status
of one client app even if app is in background.
I Have to display it on
ServerSide that weather specific device is connected to internet or
not
I am using Firebase to perform this scenerio but it's not working.
ConnectionService
public class ConnectionService extends Service implements ConnectivityReciever.ConnectivityRecieverListner {
public static final int notify = 5000;
private Handler mHandler=new Handler();
private Timer mTimer = null;
FirebaseDatabase db;
DatabaseReference dbRef;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
dbRef=FirebaseDatabase.getInstance().getReference(Common.DEVICE_NAME).child("online");
MyApplication.getInstance().setConnectivtyListner(ConnectionService.this);
boolean isConnected=ConnectivityReciever.isConnected();
checkConnection(isConnected);
if(mTimer!=null){
mTimer.cancel();
}else{
mTimer=new Timer();
mTimer.scheduleAtFixedRate(new TimeDisplay(),0,notify);
}
}
private void checkConnection(boolean isConnected) {
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(ConnectionService.this, "Service is destroyed", Toast.LENGTH_SHORT).show();
}
#Override
public void onNetworkConnectionChanged(boolean isConnected) {
if(isConnected){
dbRef.onDisconnect().setValue("true");
Toast.makeText(ConnectionService.this, "online", Toast.LENGTH_SHORT).show();
}
if(!isConnected){
dbRef.onDisconnect().setValue(ServerValue.TIMESTAMP);
Toast.makeText(ConnectionService.this, "offline", Toast.LENGTH_SHORT).show();
}
}
//class TimeDisplay for handling task
class TimeDisplay extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
MyApplication.getInstance().setConnectivtyListner(ConnectionService.this);
boolean isConnected=ConnectivityReciever.isConnected();
checkConnection(isConnected);
// display toast
Toast.makeText(ConnectionService.this, "Service is running", Toast.LENGTH_SHORT).show();
}
});
}
private void checkConnection(boolean isConnected) {
if(isConnected){
dbRef.setValue("true");
Toast.makeText(ConnectionService.this, "online", Toast.LENGTH_SHORT).show();
}
if(!isConnected){
dbRef.child("online").onDisconnect().setValue(ServerValue.TIMESTAMP);
Toast.makeText(ConnectionService.this, "offline", Toast.LENGTH_SHORT).show();
}
}
}
}
Applicaiton
public class MyApplication extends Application {
public static MyApplication mInstance;
DatabaseReference dbRef;
#Override
public void onCreate() {
super.onCreate();
mInstance=this;
Common.DEVICE_NAME = android.os.Build.MODEL;
FirebaseApp.initializeApp(this);
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
public static synchronized MyApplication getInstance(){
return mInstance;
}
public void setConnectivtyListner(ConnectivityReciever.ConnectivityRecieverListner listner){
ConnectivityReciever.connectivityReceiverListener = listner;
}
}
I have tried all of methods but nothing worked.
Help will be arreciated.
Thanks

if you have registered your service with menifest.xml & your returning start_sticky, it should work but there's an alternative way also, you can write an api to ping the server(call it in a service after a specific interval), and save the time stamp with TRUE(if isConnected), so now the timestamp is saved along with boolean value true, let's suppose now the connection is OFF or cell is dead, since no updation will be sent to server, right?
now it comes the magic of reciver/admin app(where you want to show this online status graphically), now write another API that will fetch that saved response with timestamp & also get the current time when this fetching API will be triggered, find the difference b/w these two time stamps & impose a condition here `
(here difference is in seconds cuz we are using timestamps)
if(timeDifference>60)`
{
echo "true";
}
else
echo "false";
in this way you can get real time online/offline status
on reciver app you ca set
if(response.equals("true"))
{
textView.setText("ONLINE")
}
else
{
textView.setText("OFFLINE")
}
further you can read this post answer too
Save Response to Server When Network Connection goes OFF

Have you registered your Service within your Manifest.xml?
And for your service to be "sticky" you should override your onStartCommand to return START_STICKY

Related

Infinite loop or idle code in IntentService class of Android

I'm asking this question because my Java knowledge is really low... I need
need to use this new API 27 USSD feature... Below if What I'm trying to do :
public class MyService extends IntentService {
// BEGIN of MyService Class properties ****
public static boolean jobInProgress = true;
private Handler myHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg); // I guess this will be on some message queue somewhere
}
};
TelephonyManager tm;
// END of properties *************************************
// BEGIN of MyService class abstract class methods implementation
class MyCallback extends TelephonyManager.UssdResponseCallback{
Context serviceContext;
MyCallback (Context serviceContext){
this.serviceContext = serviceContext;
}
public void onReceiveUssdResponse (TelephonyManager telephonyManager,
String request,
CharSequence response){
//Here since it's a System callback I guess my this.tm == telephonyManager parameter right ?
Toast.makeText(serviceContext, "Response from network is : " + response, Toast.LENGTH_LONG).show();
MyService.jobInProgress = false;
}
public void onReceiveUssdResponseFailed (TelephonyManager telephonyManager,
String request,
int failureCode){
Toast.makeText(serviceContext, "USSD request failed with code " + failureCode, Toast.LENGTH_LONG).show();
MyService.jobInProgress = false;
}
}
// END of abstract methods implementation******************
//BEGIN of MyService Class methods
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Service is created.", Toast.LENGTH_LONG).show();
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service is destroyed", Toast.LENGTH_LONG).show();
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
doJob();
while(jobInProgress){
//I hang here to not call onDestroy to quickly...
}
}
private void doJob(){
//Get the instance of TelephonyManager
this.tm =(TelephonyManager)getSystemService(this.TELEPHONY_SERVICE);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
return;
}
//Don't know How to use sendUssdRequest second and thrid arguments. Below is what I have tried with no success
this.tm.sendUssdRequest("#105*2#",new MyCallback(this),myHandler);
}
//END of class methods*****************************
}
The golad I'm trying to achieve is to runn the USSD request and print the result in a Toast. When I launch the service, it says service created as expected, it goes into the doJob() method as expected, but after that, nothing else happens... The app does not even crash... Just as if after enterring doJob() no instructions was written...
Can you help me make this code work ?
The reason its not working is beacuse you are using Handler and infinite loop together.
When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it. So when you do following:
while(jobInProgress){
//I hang here to not call onDestroy to quickly...
}
It will block the worker Thread and also the Handler. As a result nothing happens.
The solution would be to use normal Service and avoid any looping.
Remember from Android O you cannot endlessly run your service in background. This approach will work if your app is in Foreground. Use foreground Service if you want to make it work reliably.
Here is how I solved it following Sagar's answer :
Instead of :
#Override
protected void onHandleIntent(#Nullable Intent intent) {
doJob();
while(jobInProgress){
//I hang here to not call onDestroy to quickly...
}
}
I did this :
#Override
protected void onHandleIntent(#Nullable Intent intent) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
doJob();
}
});
t.start();
while(jobInProgress){
//I hang here to not call onDestroy to quickly...
}
}
and my Handler changed to this :
private Handler myHandler = new Handler(Looper.getMainLooper())
public void handleMessage(Message msg) {
super.handleMessage(msg); // I guess this will be on some message queue somewhere
}
};

Android Run Service inside a Service for every 30 seconds?

I followed this to Run a Service for Every 5 Min
Till now Its working fine.. But I have added a Intent for Next service in TimeDisplay But its working fine only for the First Time But the second Activity is not running for Every 30 seconds...Its only Working on First Run..
this is MyService
public class ServMain1 extends Service {
private static final String TAG = "ServMain1";
public static final int notify = 30000;
private Handler mHandler = new Handler();
private Timer mTimer = null;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onCreate() {
if (mTimer != null) // Cancel if already existed
mTimer.cancel();
else
mTimer = new Timer(); //recreate new
mTimer.scheduleAtFixedRate(new TimeDisplay(), 0, notify);
}
#Override
public void onDestroy() {
super.onDestroy();
mTimer.cancel(); //For Cancel Timer
Toast.makeText(this, "Service is Destroyed", Toast.LENGTH_SHORT).show();
}
//class TimeDisplay for handling task
class **TimeDisplay** extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
// display toast
Toast.makeText(ServMain1.this, "ServMain1 : Service is running", Toast.LENGTH_SHORT).show();
startService(new Intent(ServMain1.this, ServMain2.class));
}
});
}
}
}
Here at TimeDisplay I am using this to start second service startService(new Intent(ServMain1.this, ServMain2.class));
How ever I am getting Toast for Every 30 Seconds But Along with that toast I am using a intent is not working...
Its working only for the first time... but I am getting toast of every 30seconds
Can Any one suggest me How to using this kind of activity
A service will only run once even after you call startService multiple times.
If you want to keep restarting the service in your handler, you need to first check if it already running, kill it if it is already running and call startService post that.
You can check if the service is running using
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
And inside your handler make these changes
mHandler.post(new Runnable() {
#Override
public void run() {
// display toast
Toast.makeText(ServMain1.this, "ServMain1 : Service is running", Toast.LENGTH_SHORT).show();
if(!isMyServiceRunning(ServMain2.class)){
startService(new Intent(ServMain1.this, ServMain2.class));
} else{
stopService(ServMain2.class);
startService(new Intent(ServMain1.this, ServMain2.class));
}
}
});

Custom service class with a ThreadPoolExecutor killed when app is off

I need to execute multipe tasks in parallel inside a custom service to get these working :
- Location service and activity recognition API.
- Geofence API and REST API calls.
I'm new to threads in java and android, and i found that the best way to implement this is to use a ThreadPoolExecutor instead of making my own thread classes and dealing with all the Handler Looper stuff.
When i execute my app, the service starts, Location updates and activity updates works fine inside a thread. but, when i close the app, the service restarts (when return START_STICKY;) and the thread is not working anymore.When (return START_NOT_STICKY;), the service disappears.
(In my case, i can't use startforeground())
I'm using this library(smart-location-lib) for location and activity updates.
- Here's my custom service code :
public class LocationService extends Service {
private ThreadPoolExecutor mDecodeThreadPool;
private BlockingQueue<Runnable> mDecodeWorkQueue;
private int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
private final int KEEP_ALIVE_TIME = 1;
private final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
public LocationService () {
}
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Location services created", Toast.LENGTH_SHORT).show();
mDecodeWorkQueue = new LinkedBlockingQueue<Runnable>();
mDecodeThreadPool = new ThreadPoolExecutor(
NUMBER_OF_CORES * 2, // Initial pool size
NUMBER_OF_CORES * 2, // Max pool size
KEEP_ALIVE_TIME,
KEEP_ALIVE_TIME_UNIT,
mDecodeWorkQueue);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "Location services started", Toast.LENGTH_SHORT).show();
mDecodeThreadPool.execute(new LocationRunnable(getApplicationContext()));
return START_STICKY;
}
#Override
public void onLowMemory() {
super.onLowMemory();
Log.v("LOW MEMORY", "|||||||||||||||||||||||||||||||||||||");
}
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onDestroy() {
Toast.makeText(this, "Location services stopped", Toast.LENGTH_LONG).show();
mDecodeThreadPool.shutdown();
mDecodeThreadPool.shutdownNow();
super.onDestroy();
}
}
- Here's my Runnable class code :
public class LocationRunnable implements Runnable, OnLocationUpdatedListener, OnActivityUpdatedListener {
SmartLocation smartLocation;
public LocationRunnable(Context ctx) {
smartLocation = new SmartLocation.Builder(ctx).logging(true).build();
}
#Override
public void run() {
Log.v("THREAD", "THREAD STARTED");
startLocation();
}
private void startLocation() {
smartLocation.location().start(this);
smartLocation.activity().start(this);
}
#Override
public void onActivityUpdated(DetectedActivity detectedActivity) {
if (detectedActivity != null) {
Log.v("ACTIVITY", "ACTIVITY UPDATED");
} else {
Log.v("ACTIVITY", "NULL");
}
}
int i = 0;
#Override
public void onLocationUpdated(Location location) {
Log.v("LOCATION", "LOCATION UPDATED" + i++);
}
private String getNameFromType(DetectedActivity activityType) {
switch (activityType.getType()) {
case DetectedActivity.IN_VEHICLE:
return "in_vehicle";
case DetectedActivity.ON_BICYCLE:
return "on_bicycle";
case DetectedActivity.ON_FOOT:
return "on_foot";
case DetectedActivity.STILL:
return "still";
case DetectedActivity.TILTING:
return "tilting";
default:
return "unknown";
}
}
}
I'm not really sure if this is the right or the best way to get what i need.
Any help is greatly appreciated !
I realize the question is old, but it might be of help to others.
I think it is due to the fact that the code from Runnable.run() exits immediately, thereby ending the parent thread, so that the changes in location no longer have an object to be posted to.
smartLocation.location().start(this); // this <-- is the Runnable
And the reason you get update until restart might be due to garbage collection not clearing up the no longer used Runnable object or some existing reference to it within your code.

Checking status of a service failing because classloader

I have an Activity that starts a service which isn't local. Sometimes I check if is alive to perform actions.
My attempt at the moment was to use a static boolean variable. Reading some posts on SO I found out this not works because each process has it's own classloader.
Iterating over all running services is expensive to do a simple task like this.
Other solutions points out to use AIDL. In a very near future in my service, I'll store a WeakReference for the current running activity to execute it again in case of crash. Assuming for now I just want to check the service' state, is this an expensive solution too?
P.S.: I know it's an ugly solution to not handle exception properly. It's just a try.
EDIT: To clarify what I'm doing I post some code. This is the Service classs:
public class CrashRecover extends Service {
private volatile boolean stop = false;
private Thread backgroundThread;
private Messenger serviceMessenger = null;
private static boolean running = false;
...
#Override
public int onStartCommand(Intent intent, int flags, int startID){
serviceMessenger = new Messenger(new ServiceHandler(serviceLooper));
return START_STICKY;
}
#Override
public void onCreate(){
super.onCreate();
HandlerThread handlerThread = new HandlerThread("CrashRecoverThread", Process.THREAD_PRIORITY_BACKGROUND);
handlerThread.start();
serviceLooper = handlerThread.getLooper();
backgroundThread = new Thread(){
#Override
public void run(){
synchronized(this){
try {
while(!stop){
sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
running = true;
}
#Override
public void onDestroy(){
super.onDestroy();
try {
Message destroyMessage = Message.obtain();
destroyMessage.arg1 = CrashRecover.DESTROY_SERVICE;
serviceMessenger.send(destroyMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
running = false;
}
#Override
public IBinder onBind(Intent arg0) {
return serviceMessenger.getBinder();
}
public static boolean isRunning(){
return CrashRecover.running;
}
...
private class ServiceHandler extends Handler{
public ServiceHandler(Looper looper){
super(looper);
}
#Override
public void handleMessage(Message message){
switch(message.what){
case REGISTER_CLIENT:
//addActivityToRespawn(null);
//respawnActivity();
Log.i("INFO", "Service is registered");
break;
case UNREGISTER_CLIENT:
activityParams = message.getData();
//respawnActivity();
if(backgroundThread.isAlive()){
stop = true;
}
Log.i("INFO", "Service is unregistered");
break;
case DESTROY_SERVICE:
Log.i("INFO", "Service is destroyed");
break;
default:
super.handleMessage(message);
}
}
}
}
And this is my class when I verify if service is running:
public class Main extends Activity {
private Button serviceButton, crashButton;
private Intent serviceIntent;
private ClientMessageHandler clientHandler;
#Override
public void onCreate(Bundle savedInstanceState) {
...
clientHandler = new ClientMessageHandler();
serviceIntent = new Intent(Main.this, CrashRecover.class);
startService(serviceIntent);
}
...
#Override
public void onBackPressed(){
if(CrashRecover.isRunning()){
Log.i("INFO", "Service is running");
//Execute some actions
}
}
...
}
If you aren't doing this very often then I'd suggest using the "iterate over running services" method. There shouldn't be that many services running on your phone and iterating over them just accesses some internal data structures that Android keeps. Should work just fine.

Sticky Service Management

I've got a Sticky Service (returns START_STICKY from onStartCommand) which executes some code in an AsyncTask, but I'm having some problems with how and when to start, bind, stop, unbind. I only want the service around whilst the parent activity is alive, I don't want it hanging around in the background when the app has been closed, but I need the service to survive an orientation change. I currently don't need the service to be active for the entire duration of the activity being active, so I call stopSelf() after the main work is done in my AsyncTask in the Service and then start the Service again when needed. Sometimes I'll need to interrupt the work the service is doing, cancel the AsyncTask and start again with different data. The problem is that no matter what I do - I can't seem to get it solid throughout all the different possible scenarios. Can anyone have a look through and tell me what I'm doing wrong?
My Service is :
public class ChordCalculatorService extends Service {
private final IBinder mBinder = new LocalBinder();
private AsyncTask<SearchData, SearchStatusData, List<Item>> currentTask;
#Override
public void onCreate() {}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
/**
* Class for clients to access. Because we know this service always runs in
* the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
public ChordCalculatorService getService() {
return ChordCalculatorService.this;
}
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public SearchData getSearchData() {
return searchData;
}
public void startWork() {
if (currentTask != null && currentTask.getStatus() == Status.RUNNING) {
currentTask.cancel(true);
}
if(searchData != null) {
Worker task = new Worker();
currentTask = task.execute(new SearchData[] { searchData });
} else {
Message msg = handler.obtainMessage(ERROR, "No search data set");
handler.sendMessage(msg);
}
}
class Worker extends AsyncTask<SearchData, SearchStatusData, List<Item>> {
// ... code ...
#Override
protected void onPostExecute(List<Item> result) {
Message msg = handler.obtainMessage(COMPLETE, new StatusData(Status.STATUS_FINISHED, result));
handler.sendMessage(msg);
stopSelf();
}
}
}
Currently I have the Service being started when my custom View is created:
public class MyCustomView extends BasicFretBoardView {
private ServiceConnection conn;
private MyService myService;
private boolean isServiceStarted;
private boolean isServiceBound;
public MyCustomView(Context context, AttributeSet attr) {
super(context, attr);
startService();
}
public void startService() {
Intent serviceIntent = new Intent(getContext(), MyService.class);
conn = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
myService = ((LocalBinder) service).getService();
myService.registerHandler(serviceHandler);
}
#Override
public void onServiceDisconnected(ComponentName name) {
myService = null;
}
};
// Explicitly start the service. Don't use BIND_AUTO_CREATE, since it
// causes an implicit service stop when the last binder is removed.
getContext().startService(serviceIntent);
getContext().bindService(serviceIntent, conn, 0);
isServiceStarted = true;
isServiceBound = true;
}
public void stopService() {
if (isServiceStarted) {
Intent serviceIntent = new Intent(getContext(), MyService.class);
getContext().stopService(serviceIntent);
isServiceStarted = false;
}
unBindService();
}
public void unBindService() {
if(isServiceBound) {
getContext().unbindService(conn);
isServiceBound = false;
}
}
// gets called based on some user interaction
private void startServiceWork() {
if(!isServiceStarted) {
startService();
} else {
myService.cancelCalcalation();
}
myService.setData(data);
myService.startWork();
}
}
and stopping the service is handled in the Activity:
public class CustomChordActivity extends Activity {
// ... code ...
#Override
public void onBackPressed() {
super.onBackPressed();
}
#Override
protected void onPause() {
if(isFinishing()) {
chordsView.stopService();
}
super.onPause();
}
#Override
protected void onStop() {
super.onStop();
}
#Override
protected void onDestroy() {
chordsView.unBindService();
super.onDestroy();
}
#Override
protected void finalize() throws Throwable {
super.finalize();
}
}
It seems that you want your task to run on demand, maybe an IntentService would be a more suitable option. When you need work to be done, (startServiceWork()), you just start the service and that kicks off your AsyncTask. The service will then finish after the task has finished.
Now, regarding orientation changes, you would have to implement a Broadcast Receiver whose intent filter is "android.intent.action.CONFIGURATION_CHANGED". (I assume that you want the service to do work when the orientation changes) Place the Broadcast Receiver, within your activity/main ui thread. This will in effect make the hosting process of your Broadcast Receiver to be the main application process making it safer to start the service from within the Broadcast Receiver.

Categories

Resources