MainActivity starts my TestService in onCreate and bind in onStart method. AsyncThread is started in TestService onStartCommand. bind and unbind methods are called in correct sequences. All things work perfectly, absolutely no issue :).
Issue starts from here: If MainActivity is terminated then running Async thread is also stopped w/o any interrupt exception but TestService is still running which I can check at Running Application Setting.
Please help me to find out why thread stops working.
PS: I cross checked with Thread/Handler but same result.
MainActivity and Service code are here:
public class MainActivity extends Activity implements IServiceInterface {
boolean mBound = false;
TestService mTestService = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
Intent serviceIntent = new Intent(this, TestService.class);
startService(serviceIntent);
}
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService
NSLogger.i("service binding....");
Intent intent = new Intent(this, TestService.class);
bindService(intent, mBindConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
if (mBound) {
NSLogger.i("service unbinding....");
unbindService(mBindConnection);
mBound = false;
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mBindConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
NSLogger.i("UI is connected to service");
LocalBinder binder = (LocalBinder) service;
mTestService = binder.getTestService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
NSLogger.i("UI is disconnected from service");
mBound = false;
mTestService = null;
}
};
}
public class TestService extends Service implements Runnable, Handler.Callback{
// Binder given to inproc clients
private final IBinder mBinder = new LocalBinder();
#Override
public IBinder onBind(Intent intent) {
mUIIsBound = true;
return mBinder;
}
public boolean onUnbind (Intent intent) {
mUIIsBound = false;
NSLogger.i("unbind service");
return true;
}
public class LocalBinder extends Binder {
TestService getTestService() {
return TestService.this;
}
}
public void onDestroy() {
//NEVER CALLED.
}
public int onStartCommand(Intent intent2, int flags, int startId) {
NSLogger.i("TestService start!");
new DownloadConfiguration().execute();
return START_STICKY;
}
private class DownloadConfiguration extends AsyncTask<Void, Integer, Boolean> {
#Override
protected Boolean doInBackground(Void... params) {
try {
NSLogger.i("before sleep");
Thread.sleep(5000);
NSLogger.i("After sleep");
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
}
Related
I have a code like this, which run, when click the button
if (isMyServiceRunning(PlayerService.class)) {
stopService(mIntent);
unbindService(serviceConnection);
} else {
startService(mIntent);
bindService(mIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
When I click button and my service do not running, service start to work( all good here)
When I click button and my service running, service stop and destroy( all good here)
but when I click, to service start to work, service do not working
My Service
public class PlayerService extends Service {
private final IBinder binder = new LocalBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
doAnything();
return START_STICKY;
}
public class LocalBinder extends Binder {
PlayerService getService() {
return PlayerService.this;
}
}
}
Service Connection
private ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
PlayerService.LocalBinder binder = (PlayerService.LocalBinder) service;
myService = binder.getService();
Log.d("TEST", "MainActivity onServiceConnected");
bound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
Log.d("TEST", "MainActivity onServiceDisconnected");
bound = false;
}
};
I'm developing an application, which plays music in the background by using service.
Music stops when we hit back app will be paused and but, music is not resuming when I get back to the application.
public class backService extends Service implements ComponentCallbacks2 {
private MediaPlayer mp;
SharedPreferences sharedpreferences;
public Boolean musicSwitch;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
if (mp != null){
mp.stop();
mp.release();
}
}
#Override
public void onCreate() {
super.onCreate();
sharedpreferences = getSharedPreferences(mypreference,
Context.MODE_PRIVATE);
musicSwitch = sharedpreferences.getBoolean("music", true);
if(musicSwitch){
mp = MediaPlayer.create(this, R.raw.all);
mp.setLooping(true);
mp.start();
}
}
#Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
if(mp != null){
mp.pause();
}
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
I want the application to resume music when we get back to the application, I have tried using onResume method, but there is no onResume method in services.
TIA
1) You need to create foreground service to prevent it from killing by OS
How can we prevent a Service from being killed by OS?
2) You can bind service (bindService(serviceIntent)) and use Binder interface
https://developer.android.com/guide/components/bound-services.html#Binder
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. 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 {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
Activity:
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
unbindService(mConnection);
mBound = false;
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
}
}
3) Then, in your activity onResume you can call method from your Binder to control music
I got the problem that I don't know how can I fetch return value from services. Why I want return value from services is I want to show this return value in Activity page. Following is my services file and return value is retvalue.
public class SyncService extends Service{
private String forSync, lastrecordfromlocal, userdefined;
DatabaseUtil dbUtil = new DatabaseUtil(this);
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#SuppressWarnings("deprecation")
#Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
forSync = common.getInfoForSync(this);
String[] getlist = forSync.split(":");
lastrecordfromlocal = getlist[0].toString();
userdefined = getlist[1].toString();
if (common.isNetAvailable(this) == true) {
SyncServiceTask InstallData = new SyncServiceTask(this);
try {
String (((retvalue))) = InstallData.execute(lastrecordfromlocal, userdefined).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
this.stopSelf();
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
As far as I know, the common way for service to communicate with activity is by BROADCAST.
You can send a broadcast at the position you want to "return retvalue" by something like:
Intent retIntent = new Intent(ServiceReturnIntent);
retIntent.putExtra("retvalue", retvalue);
sendBroadcast(retIntent);
which ServiceReturnIntent and "retvalue" are all self-defined strings to identify the broadcast and value name.
And in your activity which wishes to catch the return value, you should have a broadcast receiver, with something like:
public class myActivity extends Activity implements BroadcastReceiver {
TextView myTextView;
#Override
OnCreate(Bundle savedInstanceState) {
setContentView(R.layout.simple_layout);
myTextView = (TextView) findViewByID(R.id.simple_textview);
}
#Override
public void onReceive(Context context, Intent intent) {
int action = jumpTable.get(intent.getAction());
switch (action) {
case ServiceReturnIntent:
String valueFromService = intent.getStringExtra("retvalue");
myTextView.setText(valueFromService);
break;
// handle other action
......
}
}
You can read this tutorial for more about broadcast in android.
EDIT
modify sample code with setting it to a textview
You can bind service to the Activity:link
Your Service:
public class SyncService extends Service {
private final IBinder mBinder = new MyBinder();
private String;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
forSync = common.getInfoForSync(this);
String[] getlist = forSync.split(":");
lastrecordfromlocal = getlist[0].toString();
userdefined = getlist[1].toString();
if (common.isNetAvailable(this) == true) {
SyncServiceTask InstallData = new SyncServiceTask(this);
try {
String (((retvalue))) = InstallData.execute(lastrecordfromlocal, userdefined).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
return Service.START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
public class MyBinder extends Binder {
SyncService getService() {
return SyncService .this;
}
}
public String getRetValue() {
return retvalue;
}
}
And in Activity check the value:
SyncService mService;
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, SyncService .class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
if you want service to communicate with activity.we have two method.
1, you can use BROADCAST. you can send BROADCAST in service and use BroadcastReceiver in activity.
2, you also can use bindService to communicate activity.
public class LocalService extends Service {
// This is the object that receives interactions from clients. See
// RemoteService for a more complete example.
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
LocalService getService() {
return LocalService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
you can use iBinder to communicate with service
I'm implementing Service that establishes TCP connection with server and then allows clients to pass messages through this connection. Clients connect to service with bindService call. As a result onServiceConnected called in clients ServiceConnection object. The problem is that onServiceConnected called right after return from bindService, but my Service was not established connection with server at this moment. Can I somehow delay onServiceConnected call while connection was not established? If it is not possible please suggest some good pattern for my case. Thank you.
You should do it as follows:
Service code:
class MyService implements Service {
private boolean mIsConnectionEstablished = false;
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
public MyService getService() {
// Return this instance of LocalService so clients can call public
// methods
return MyService.this;
}
}
public interface OnConnectionEstablishedListener {
public void onConnectionEstablished();
}
private OnConnectionEstablishedListener mListener;
#Override
public void onCreate() {
super.onCreate();
new Thread( new Runnable() {
#Override
void run() {
//Connect to the server here
notifyConnectionEstablished();
}
}).start();
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private void notifyConnectionEstablished() {
mIsConnectionEstablished = true;
if(mListener != null) {
mListener.onConnectionEstablished();
}
}
public void setOnConnectionEstablishedListener(
OnConnectionEstablishedListener listener) {
mListener = listener
// Already connected to server. Notify immediately.
if(mIsConnectionEstablished) {
mListener.onConnectionEstablished();
}
}
}
Activity code:
class MyActivity extends Activity implements ServiceConnection,
OnConnectionEstablishedListener {
private MyService mService;
private boolean mBound;
#Override
public void onCreate() {
super.onCreate();
//bind the service here
Intent intent = new Intent(this, MyService.class);
bindService(intent, this, BIND_AUTO_CREATE);
}
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
mService.setOnConnectionEstablishedListener(this);
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
#Override
public void onConnectionEstablished() {
// At this point the service has been bound and connected to the server
// Do stuff here
// Note: This method is called from a non-UI thread.
}
}
I need to implement such a procedure:
Start a background service
Update the service with parameters (from UI - user input)
After activity ended the service should keep on running and preform requests to HTTP server every minute. in this stage i still need the parameters I updated in the second stage - I send them to the server.
The service should store the server last response and compere each with the last. if there is a change, notify the user.
Finally, when the activity starts again, the service should update UI with latest the server response.
What I tried:
BroadcastReciver - The problem is after onRecive ended all the arguments which aren't declared as final will wipe out, as well as I didn't found a way to update the Intent being sent automatically every minute.
Service - Using startService() - The problem is when the activity ended the service like stops and starts , flushing all it's arguments. and once again I didn't figured out how to update the arguments after the service is already started.
So how to handle such a situation?
Thanks.
It sounds like what you need to do is to be able to "bind" to your service. What I have posted below is a simple template of how to do that. For your purposes you will need to store variables in your Service class and create getters so that when you re-launch your activity you can get the most up to date variables. Also - please note that I start and stop the Service example below in onResume and onPause. You will no doubt want to do this differently.
//Activity
//Bind to Service Example
public class ExampleActivity extends Activity implements OnClickListener {
// UI
private Button binderButton;
// service
private MyService myService;
private Intent serviceIntent;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
// binder button
binderButton = (Button) findViewById(R.id.button1);
binderButton.setOnClickListener(this);
binderButton.setText("start");
serviceIntent = new Intent(this, MyService.class);
}
private ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
myService = ((MyService.MyBinder) service).getService();
}
#Override
public void onServiceDisconnected(ComponentName name) {
myService = null;
}
};
#Override
protected void onResume() {
super.onResume();
// start the service
startService(serviceIntent);
// bind to the service
bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
// call method within the service
myService.doServiceStuff();
break;
}
}
#Override
protected void onPause() {
super.onPause();
stopService(serviceIntent);
unbindService(serviceConnection);
}
}
//Service
public class MyService extends Service {
private final IBinder binder = new MyBinder();
#Override
public IBinder onBind(Intent arg0) {
return binder;
}
public void doServiceStuff() {
task.execute();
}
// create an inner Binder class
public class MyBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
Log.d("yourTag", "long running service task");
return null;
}
};
}
Thanks javaJoe, although your answer didn't solved my problem it gave me some a good ideas.
What I did:
in the Activity onCreate, check if my service is running, if so bind it else, create new one and bind it.
Transferring arguments between the Service and the Activity using setters and getters.
in the Activity onDestroy (the problem was that the service calls self Destory) the Activity sends the final arguments through Intent to a Broadcastreciver. The Broadcastreciver than starts the Service again, initiating it with the correct arguments.
I don't know if this architecture is ideal, i'd like to get some feedback.
Here is the code:
Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Set Service Intent
serviceIntent = new Intent(this, UpdateService.class);
if (isMyServiceRunning()) {
//Bind to the service
bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}else{
updateService=new UpdateService();
//Start the service
startService(serviceIntent);
//Bind to the service
bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
}
private boolean isMyServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (UpdateService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
private ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
updateService = ((UpdateService.MyBinder) service).getService();
//Set Initial Args
updateService.setParams(int arg0);
}
#Override
public void onServiceDisconnected(ComponentName name) {
updateService = null;
}
};
#Override
protected void onDestroy() {
//UnBind from service
unbindService(serviceConnection);
//Stop Service
stopService(serviceIntent);
//Prepare intent to broadcast reciver
Intent intent = new Intent(MainActivity.this,ServiceRunnerBCR.class);
intent.setAction(ServiceRunnerBCR.ACTION_SET_UpdateService);
intent.putExtra(ServiceRunnerBCR.keyVal_arg0, arg0);
intent.putExtra(ServiceRunnerBCR.keyVal_arg1, arg1);
//Send broadcast to start UpdateService after the activity ended
sendBroadcast(intent);
super.onStop();
}
Broadcastreciver:
public class ServiceRunnerBCR extends BroadcastReceiver {
public static final String ACTION_SET_UpdateService = "ACTION_ALARM";
public static final String keyVal_arg0="ARG0";
public static final String keyVal_arg1="ARG1";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_SET_UpdateService)){
updateIntent(context, intent.getDoubleExtra(keyVal_arg0, 0.02), intent.getStringExtra(keyVal_arg1));
}
}
private void updateIntent(Context context, double arg0, String arg1){
Intent intent = new Intent(context,UpdateService.class);
intent.setAction(ACTION_SET_UpdateService);
intent.putExtra(keyVal_arg0, arg0);
intent.putExtra(keyVal_arg1, arg1);
synchronized (this){
try {
this.wait(6000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
context.startService(intent);
Log.d("OREN","ServiceRunner");
}
}
Service:
public class UpdateService extends Service {
private final IBinder binder = new MyBinder();
public static final String keyVal_arg0="ARG0";
public static final String keyVal_arg1="ARG1";
private Timer timer;
private HTTPHandler http = new HTTPHandler();
private int test=0;
double arg0=0;
String arg1= "";
private TimerTask updateTask = new TimerTask() {
#Override
public void run() {
test++;
Log.d("OREN", "Timer task doing work " + test + " arg0: " + arg0);
//Do some work here
}
};
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent!=null){
arg0=intent.getDoubleExtra(keyVal_arg0, 0.002);
arg1=intent.getStringExtra(keyVal_arg1);
timer = new Timer("UpdateTimer");
timer.schedule(updateTask, 1000L, 10 * 1000L);
Log.d("OREN", "ServiceStarted" + test);
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public IBinder onBind(Intent intent) {
Log.d("OREN", "OnBind" + test);
return binder;
}
public void setArg0(double d){
arg0=d;
}
// create an inner Binder class
public class MyBinder extends Binder {
public UpdateService getService() {
return UpdateService.this;
}
}
#Override
public void onDestroy() {
Log.d("OREN", "OnDestroy" + test);
super.onDestroy();
}
#Override
public boolean onUnbind(Intent intent) {
Log.d("OREN", "OnUnBind" + test);
return super.onUnbind(intent);
}
}