I'm hoping this is more of an issue with code than anything else and I'm hoping that someone out there can help track down the issue.
I have other code that starts the service with startService() and I can verify that the service is started as the debugger hits the onCreate() function of DecoderService.
However, the bindService never binds to the running service. Is this an asynchronous call and I have to wait for something to complete?
public class ResultsActivity extends Activity {
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
Intent decoderIntent = new Intent(this,DecoderService.class);
_isBound = bindService(decoderIntent,mConnection,Context.BIND_AUTO_CREATE);
_textView.start(_mBoundService);
}
private boolean _isBound = false;
private DecoderService _mBoundService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
_mBoundService = ((DecoderService.LocalBinder)service).getService();
}
public void onServiceDisconnected(ComponentName className)
_mBoundService = null;
}
};
}
public class DecoderService extends Service {
protected void onHandleIntent(Intent intent) {
// TODO Auto-generated method stub
_numCompleted = 5;
_numTotal = 100;
}
protected int _numCompleted = 0;
protected int _numTotal = 0;
public void onCreate() {
onHandleIntent(null);
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
// 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 {
DecoderService _ref = null;
public LocalBinder()
{
_ref = DecoderService.this;
}
DecoderService getService() {
return DecoderService.this;
}
}
}
Is this an asynchronous call and I
have to wait for something to
complete?
The binding is not ready until onServiceConnected() is called on your ServiceConnection object.
Related
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;
}
}
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
For a chat application i need service which manages the communication between the user and the web service. I decided to use the usual Android service component.
I now how to to start the service, also i know how to send messages from the service to the activity, but how do i control the service from the activity?
E.g. the user sends a message, so i have to make the service to send e.g. http requests containing the message. Or the user wants to end a chat session, so the activity have to make the service to send a request containing a command to end the chat session.
You can use AIDL
http://developer.android.com/guide/components/aidl.html
In AIDL, you can implement methods in service, and call those methods from activity through binder.
So in your case,1) Implement sendMessage(String msg) in service
2)Declare this method in aidl file and call from service
mService.sendMessage(msg);
EDIT without using AIDL:
Service class
public class LocalService extends Service {
private final IBinder mBinder = new LocalBinder();
private final Random mGenerator = new Random();
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return mBinder;
}
public class LocalBinder extends Binder{
LocalService getService(){
return LocalService.this;
}
}
public int getRandomNumber()
{
return mGenerator.nextInt(100);
}
}
Activity class
public class BindingActivity extends Activity {
LocalService mService;
boolean mbound = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_binding);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_binding, menu);
return true;
}
#Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
Intent intent = new Intent(this, LocalService.class);
bindService(intent,mConnection,Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
if(mbound)
{
unbindService(mConnection);
mbound = false;
}
}
private ServiceConnection mConnection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
LocalBinder binder = (LocalBinder)service;
mService = binder.getService();
mbound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
mbound = false;
}
};
public void onClick(View view)
{
if(mbound)
{
int num = mService.getRandomNumber();
Toast.makeText(this, "number: "+num, Toast.LENGTH_SHORT).show();
}
}
}
I have a service that is going to act as an internal clock as part of another app, and it contains a Timer which runs every one second to update the time.
Problem is, when I close and re-open the app, the Service binds itself and all the code runs again in the service and then there are two Timers per second, and so on.
I've tried following the Local Service example, but the same thing happens http://developer.android.com/reference/android/app/Service.html#LocalServiceSample
Is it something to do with the bind/unbind of the service?
I'd like for just one process to run, so I'm looking for a way really to see if the process is running already, and if not then start it.
LocalService
`public class LocalService extends Service {
// This is the object that receives interactions from clients.
private final IBinder mBinder = new LocalBinder();
private long dateOfLastSync;
private long timeNow;
private final Handler handler = new Handler();
private static Timer timer = new Timer();
private Context ctx;
/**
* 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 {
// The LocalBinder provides the getService() method for clients to retrieve the current instance of LocalService.
LocalService getService() {
Log.d("INTERNALCLOCK", "getService");
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
#Override
public void onCreate() {
Log.d("INTERNALCLOCK", "onCreate");
ctx = this;
startService();
}
#Override
public void onDestroy() {
Log.d("INTERNALCLOCK", "onDestroy");
Toast.makeText(this, "Service Stopped ...", Toast.LENGTH_SHORT).show();
}
private void startService()
{
timer.scheduleAtFixedRate(new mainTask(), 0, 1000);
}
private class mainTask extends TimerTask
{
public void run()
{
toastHandler.sendEmptyMessage(0);
}
}
public void getTimeFromServer() {
FetchServerTime fetchTime = new FetchServerTime();
fetchTime.execute();
}
#Override
public IBinder onBind(Intent intent) {
Log.d("INTERNALCLOCK", "onBind");
getTimeFromServer();
return mBinder;
}
/** method for clients */
public long getTimeNow() {
Log.d("INTERNALCLOCK", "getTimeNow");
return timeNow;
}
public void startTimeCounter() {
Log.d("INTERNALCLOCK", "startTimeCounter");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("INTERNALCLOCK", "onStartCommand");
return START_STICKY;
}
private final Handler toastHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
timeNow += 1000;
Log.d("INTERNALCLOCK", "time is " + timeNow);
Toast.makeText(getApplicationContext(), "test", Toast.LENGTH_SHORT).show();
}
};
class FetchServerTime extends AsyncTask<Integer, String, Long> {
private String mUrl;
private Date date;
private AlarmManager mAlarmManager;
public FetchServerTime() {
mUrl = "XXX";
}
#Override
protected Long doInBackground(Integer... params) {
(get server time code)
}
#Override
protected void onPostExecute(Long result) {
super.onPostExecute(result);
Log.d("INTERNALCLOCK", "Server time on post execute: " + result);
timeNow = result;
dateOfLastSync = result;
}
}
`
InternalClockActivity
public class InternalClockActivity extends Activity implements CanUpdateTime {
private TextView timeLabel;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d("INTERNALCLOCK", "onCreate - main");
timeLabel = (TextView) findViewById(R.id.time);
doBindService();
}
private LocalService mBoundService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. Because we have bound to a explicit
// service that we know is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
mBoundService = ((LocalService.LocalBinder)service).getService();
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
// Because it is running in our same process, we should never
// see this happen.
mBoundService = null;
}
};
private boolean mIsBound;
void doBindService() {
// Establish a connection with the service. We use an explicit
// class name because we want a specific service implementation that
// we know will be running in our own process (and thus won't be
// supporting component replacement by other applications).
bindService(new Intent(InternalClockActivity.this,
LocalService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
void doUnbindService() {
if (mIsBound) {
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
}
}
#Override
protected void onDestroy() {
super.onDestroy();
doUnbindService();
}
public void updateTime(String time){
timeLabel.setText(time);
}
}
I just created some static variables to see if the timer was running, i.e.
private static boolean isDownloadTaskRunning = false;
private void startService()
{
if (!isDownloadTaskRunning) {
// Timers are not running already
// start timer to download date at intervals
timerToDownloadNewData.scheduleAtFixedRate(new DownloadDateTask(), 0, TIMES.FIFTEEN_MINS.getSeconds());
// set running to true
isDownloadTaskRunning = true;
}
}
I have created a simple service which will increment a counter and log it.
public class AudioService extends Service {
int i=0;
private final IAudioInterface.Stub mBinder = new IAudioInterface.Stub() {
public int getI()
{
return i;
}
};
#Override
public IBinder onBind(Intent intent) {
Log.d("onBind from service","****");
return mBinder;
}
#Override
public void onCreate() {
super.onCreate();
Log.d("onCreate from service","***");
Log.d("i=","="+i);
i=i+1;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("OnDestroy Called from service","***");
}
public void onStartCommand(Intent intent, int startId) {
super.onStart(intent, startId);
Log.d("onStartCommand from service","***");
}
#Override
public boolean onUnbind(Intent intent) {
Log.d("onUnbind from service","***");
return super.onUnbind(intent);
}
i am incrementing the i value in the oncreate method of he service.
The Client Activity is as shown below
public class AidlInterfaceServiceActivity extends Activity implements OnClickListener {
/** Called when the activity is first created. */
private static final String TAG = "Audio:Service";
IAudioInterface mService = null;
boolean connected = false;
ServiceConnection mConnection = new ServiceConnection(){
public void onServiceConnected(ComponentName arg0, IBinder service) {
// TODO Auto-generated method stub
connected = true;
Log.d("Service connected","**");
mService = IAudioInterface.Stub.asInterface(service);
try {
Log.d("i from client","="+mService.getI());
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName arg0) {
// TODO Auto-generated method stub
Log.i(TAG, "Service disConnected");
connected = false;
mService= null;
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d("on created ","**********");
Intent music = new Intent();
music.setClass(this,AudioService.class);
startService(music);
bindService(music, mConnection, Context.BIND_AUTO_CREATE);
}
The AIDL file is as below
interface IAudioInterface
{
int getI();
}
The problem is when i run the client activity every time the value of i is "0".
i value is not getting incremented.
I have these queries.
1.what happens when the service is started multiple time.
2.what happens when the service is bounded multiple times.
3.what happens to the data members inside the service class when it is started multiple times.Does those data members get reinitialized.
I am really confused ..Any one please help.
Does it help if you declare your counter variable as static?