So here is what I am trying to understand.
I have a service like this
public MyService extends Service {
public List<MyListener> listenersList = new ArrayList<>();
public void addListeners(MyListeners mylistener) {
listenersList.add(myListener);
}
public void eventAOccured(){
for ( MyListner mylistener : listeners ) {
mylistener.eventAOccured();
}
}
public void eventBOccured(){
for ( MyListner mylistener : listeners ) {
mylistener.eventBOccured();
}
}
}
And here is my MyListener Interface which activities
public Interface MyListener {
public eventAOccured();
public eventBOccured();
}
Now we have three activites
public Activity1 extends AppCompatActivity implements MyListener{
public static int myVariable = 1;
//starts service. For sake of brevity I am skipping this part.
MyService.add(this);
//on click of a button
startActivity( new Intent (Activity1.this, Activity2.class);
//Now I know this will put Activity1 in paused state
#Override
public void eventAOccured() {
//Call activity 3
}
#Override
public void eventBOccured() {
myVariable = 3;
}
}
This is the second activity which is called by clicking a button in activity 1. After Activity2 is launched, lets say eventB occurs. Now If I access myVariable from Activity1, will it be 1 or 3.
After some time let us say, eventA has occured. Now will Activity3 will be launched?
I know an activity being paused means it is no longer visible to the user, but will the communication with service continue?
yes, paused activity still will receive the event as it is in the back stack of system and is not destroyed.
Override the onStartCommand(Intent intent, int flags, int startId) and returen STRAT_STICKY. this will restart the service.
You can check following Example.
public class Test extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("Test Service ", "onStartCommand");
return START_STICKY; //It will restart Service in onPause/onDestroy
}
#Override
public void onCreate() {
super.onCreate();
//Do your operation
}
}
Related
From an Android Service, I would like to call an Activity method, but only if the Activity is in the foreground.
I would like nothing to happen in case the Activity is not in the foreground.
Which is the simplest way to achieve that?
From a Service always better to broadcast events if the activity is listening to that broadcast will respond. If the activity is not listening then nothing will happen it will ignore.
This is the better solution than the one which you have asked.
I found a very simple solution, adapted from this previous answer:
On the Service:
Intent intent = new Intent(MainActivity.RECEIVER_INTENT);
intent.putExtra(MainActivity.RECEIVER_MESSAGE, myMessage);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
On the Activity:
public static final String RECEIVER_INTENT = "RECEIVER_INTENT";
public static final String RECEIVER_MESSAGE = "RECEIVER_MESSAGE";
Create a listener on onCreate():
public void onCreate(Bundle savedInstanceState) {
...
mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra(RECEIVER_MESSAGE);
// call any method you want here
}
};
}
register it in onStart():
#Override
protected void onStart() {
super.onStart();
LocalBroadcastManager.getInstance(this).registerReceiver((mBroadcastReceiver),
new IntentFilter(RECEIVER_INTENT)
);
}
unregister it in onStop():
#Override
protected void onStop() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
super.onStop();
}
You can do this using a Interface just to check if the activity is in background or in foreground.
I am sharing some code to have some idea.
public interface CheckAppInForeground {
boolean isAppInForGround();
}
In your Activity
public class MainActivity extends AppCompatActivity implements CheckAppInForeground {
Boolean isAppInForeGround;
#Override
protected void onResume() {
super.onResume();
isAppInForeGround = true;
}
#Override
protected void onStop() {
super.onStop();
isAppInForeGround = false;
}
#Override
public boolean isAppInForGround() {
return isAppInForeGround;
}
}
And your service class
public class MyService extends Service {
Activity activity;
public MyService(Activity activity) {
this.activity = activity;
}
#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) {
MainActivity mainActivity = (MainActivity) activity;
if (activity != null) {
boolean isActivityInForGround = mainActivity.isAppInForGround();
if (isActivityInForGround) {
// Do what you want to do when activity is in foreground
} else {
// Activity is in background
}
} else {
// Activity is destroyed
}
return super.onStartCommand(intent, flags, startId);
}
}
I think i am clear with the code. If you find something missing or unclear please let me know
So I have code that I want called when my application is closed. Not just when it is sent to the background or the surface is destroyed. How do I do this? Is there a method that I can override in a SurfaceView or Activity class?
New Edit - current BackgroundService class:
public class BackgroundService extends Service {
private String savedString;
public void onCreate() {
System.out.println("Service created");
super.onCreate();
}
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("start command: ");
savedString = intent.getStringExtra("myString);
return super.onStartCommand(intent, flags, startId);
}
public IBinder onBind(Intent intent) {
return null;
}
public void onTaskRemoved(Intent rootIntent) {
System.out.println("the saved string was: " + savedString);
super.onTaskRemoved(rootIntent);
}
public void onDestroy() {
System.out.println("destroyed service");
super.onDestroy();
}
}
Where I then have this in my other class:
Intent serviceIntent = new Intent(activity.getApplicationContext(), BackgroundService.class);
serviceIntent.putExtra("myString", "this is my saved string");
activity.startService(serviceIntent);
you need to add a background service
public class BackgroundServices extends Service
{
#Override
public void onCreate() {
Toast.makeText(this, "start", Toast.LENGTH_SHORT).show();
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
then in your activity. where you want to trigger this service
use
startService(new Intent(getBaseContext(), BackgroundServices.class));
in your case it will be call on onDestory function of that activity
Yes when the process is terminated
That is not possible in general. Nothing in your app is called when the process is terminated.
For example when you open the running apps screen, and swipe away the app to stop it from running
That is a task removal. It may result in your process being terminated, and there are many ways in which your process can be terminated that has nothing to do with task removal.
To detect task removal, override onTaskRemoved() in a Service.
I have a function in a service as follows:
public class ServiceA extends Service {
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
private final IBinder mBinder = new LocalBinder();
public void readFunc() {
//I have a function in here
}
}
I want to call the readFunc() in the service B. Could I do it in Android? Thank all. This is my service B
public class serviceB extends Service {
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("A");
intentFilter.addAction("B");
registerReceiver(broadcastReceiver, intentFilter);
return START_STICKY;
}
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case "A":
Log.d(TAG,"A");
//Call the function here
break;
case "B":
Log.d(TAG,"B");
break;
}
}
};
}
Well, you COULD do it, just instancing a new ServiceA and calling the function, but you should not do it like that. Services are not meant to be instantiated just to call a function which is not even part of the Service functionality. You have different options:
You could make readFunc() static if it does not modify variables of the class and you think it should belong to ServiceA and not to ServiceB. I don't think this is a goog approach in your case.
You could create a class ServiceAB which has readFunc(), and the define both ServiceA and B as "extends ServiceAB". Then both classes would inherit this function and you could just call readFunc() in both of them. I think this would be the correct approach in your case: both classes need some common functionality.
You could have readFunc() in a different class, and the instantiate it to use it in each of your services.
The way I would do it:
public class ServiceAB extends Service {
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
}
public void readFunc() {
//I have a function in here
}
}
Then:
public class serviceB extends ServiceAB {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("A");
intentFilter.addAction("B");
registerReceiver(broadcastReceiver, intentFilter);
return START_STICKY;
}
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case "A":
Log.d(TAG,"A");
readFunc(); //Just call the function
break;
case "B":
Log.d(TAG,"B");
break;
}
}
};
}
And ServiceA:
public class ServiceA extends ServiceAB {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
private final IBinder mBinder = new LocalBinder();
}
Quoting #Kingfisher Phuoc here and #Mr Snowflake here
there are three obvious ways to communicate with services and EventBus:
Using Intents
Using AIDL
Using the service object itself (as singleton)
EventBus
In your case, I'd go with option 3. Make a static reference to the service it self and populate it in onCreate():
void onCreate(Intent i) {
sInstance = this;
}
Make a static function MyService getInstance(), which returns the static sInstance.
Then in Activity.onCreate() you start the service,
asynchronously wait until the service is actually started (you could have your service notify your app it's ready by sending an Intent to the activity.) and get its instance.
When you have the instance, register your service listener object to you service and you are set.
NOTE: when editing Views inside the Activity you should modify them in the UI thread, the service will probably run its own Thread, so you need to call Activity.runOnUiThread().
The last thing you need to do is to remove the reference to you listener object in Activity.onPause(), otherwise an instance of your activity context will leak, not good.
NOTE: This method is only useful when your application/Activity/task is the only process that will access your service. If this is not the case you have to use option 1. or 2.
I am new to Android development, and I try to get some practice with service and intentservice.
This is my service class:
public class MyBaseService extends Service {
private double[] returnData;
public MyBaseService() {
}
#Override
public void onCreate() {
returnData = new double[//dataSise];
}
/** The service is starting, due to a call to startService() */
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
for (Map.Entry<Integer, Double[]> mapEntry : dataMap.entrySet()) {
doXYZ(mapEntry.getValue());
Arrays.sort(returnData);
}
} catch (IOException e) {
e.printStackTrace();
}
Intent intents = new Intent();
intents.setAction(ACTION_SEND_TO_ACTIVITY);
sendBroadcast(intents);
return START_STICKY;
}
/** A client is binding to the service with bindService() */
#Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
public class MyBinder extends Binder {
public MyBaseService getService() {
return MyBaseService.this;
}
}
/** Called when a client is binding to the service with bindService()*/
#Override
public void onRebind(Intent intent) {
}
/** Called when The service is no longer used and is being destroyed */
#Override
public void onDestroy() {
super.onDestroy();
}
private void doXYZ(double[] data) {
int gallerySize = galleryFiles.length;
for (int i=0; i<data.length; ++i) {
Intent cfIntent = new Intent(this, MyIntentService.class);
compareFeatureIntent.putExtra(MyIntentService.COMPARING_INDEX, i);
startService(cfIntent);
}
}
BroadcastReceiver mReceiver;
// use this as an inner class like here or as a top-level class
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int index = intent.getIntExtra(MyIntentService.COMPARING_INDEX, 0);
double scores = intent.getDoubleArrayExtra(MyIntentService.COMPARING_SCORE);
data[index] = scores[0];
}
// constructor
public MyReceiver(){
}
}
}
And this is intentservice class:
public class MyIntentService extends IntentService {
protected static final String ACTION_COMPARE_FEATURES = "CompareFeatures";
protected static final String COMPARING_SCORE = "Score";
protected static final String COMPARING_INDEX = "Index";
public MyIntentService() {
super("MyIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
int index = (int)intent.getLongExtra(COMPARING_INDEX, 0);
// This is long operation
double[] scores = getScores(index);
Intent intents = new Intent();
intents.setAction(ACTION_COMPARE_FEATURES);
intent.putExtra(COMPARING_SCORE, scores);
intent.putExtra(COMPARING_INDEX, index);
sendBroadcast(intents);
}
}
The scenario is that I want to start MyBaseService class inside main activity. Inside MyBaseService, I need to do a long run operation and need to iterate that operation many times. So, I put that long operation in MyIntentService, and start MyIntentService in a loop.
MyIntentService will produce some data, and I want to get that data back in MyBaseService class to do some further operations.
The Problem I am facing with communication between MyBaseService and MyIntentService. Because MyBaseService will start MyIntentSerice many times, my initial solution is to sendBroadcast() from MyIntentService, and register receiver in MyBaseService.
So, my questions are:
Is my design with MyBaseService MyIntentService efficient? If not, how should I do to archive the result I want?
If sendBroadcast() is a right direction, how should I register in MyBaseService?
Your architecture is fine. There are several ways to do this but this approach is OK.
You can register the BroadcastReceiver in MyBaseSerice.onStartCommand() and unregister it in MyBaseService.onDestroy().
You will need to determine how to shutdown MyBaseService. Either the Activity can do it or MyBaseService will need to keep track of the number of replies it is waiting for from the IntentService and as soon as it gets the last one it can shut itself down by calling stopSelf().
This is my code for service class here previous_network_type is global static variable it is not initialized in oncreate() or onstartcommand() function also not from activity on create function why is that any help?? whenever i used it, it gives me 0 value it should give me 10 after starting of this service but returns 0. To be more clear
First MyService has previous_network_type variable i want to assign it a value in oncreate or oncommand function
which i'l use in another class which is broadcast receiver
and you know that broadcast receiver runs only when an event is occur so what m trying to do whenever a particular event occur i want to access this value
public class MyService extends Service {
static int previous_network_type=0;
public void onCreate() {
previous_network_type=10;
};
public int onStartCommand(Intent intent, int flags, int startId) {
previous_network_type=10;
return Service.START_STICKY;
}
}
and the code of other class(Broadcast receiver is given below)
public void onReceive(Context context, Intent intent)
{
MyService.current_network_type=MyService.previous_network_type;
}
public class MainActivity extends Activity {
Intent i;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
i=new Intent(this,MyService.class);
startService(i);
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();;
stopService(i);
}
}
public class MyService extends Service {
static int previous_network_type=0;
public void onCreate() {
previous_network_type=10;
};
public int onStartCommand(Intent intent, int flags, int startId) {
previous_network_type=10;
Log.e("check","Value"+previous_network_type);
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
check once if you have defined the Service in Android.manifest.xml
<service android:name="com.example.kuchbhi.MyService"
></service>
Just make sure that you are accessing the value after the service has been created/started.
Try to debug.