W/ActivityManager( 61): Binding with unknown activity: android.os.BinderProxy@43f4a2d0
A quick googling turned up two bug reports on this problem:
http://code.google.com/p/android/issues/detail?id=2665
http://code.google.com/p/android/issues/detail?id=2483
Apparently, bindService() can not be performed from inside an embedded activity such as a Tab. There are three workarounds:
- Call getParent().bindService()
- Call getApplicationContext().bindService()
- Call bindService() in the TabHost activity and then passes the binder to other tabs.
Updated on November 6, 2010:
Because a service connection is context specific, the workaround #1 and #2 can have unintended threading consequences when you use TabActivity and TabHost to manage embedded tabs. For example, when getApplicationContext().bindService() is used, the ServiceConnection.onServiceConnected() will be called from a thread different from the thread running the current tab. Therefore, access to the service object must be synchronized. This is demonstrated below:
public class MyTab extends Activity { private static final TAG = MyTab.this.getName(); private RemoteService remoteService = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getApplicationContext().bindService()) { // Unsynchronized access!! Log.v(TAG, "Service bound ? " + remoteService != null ? "true" : "false"; } } private class MyServiceConnection implements ServiceConnection { @Override public void onServiceConnected (final ComponentName name, final IBinder service) { // Unsynchronized access!! remoteService = RemoteService.stub.asInterface(service); } @Override public void onServiceDisconnected (final ComponentName name) { // Unsynchronized access!! remoteService = null; } } }A straight-forward way to fix the synchronization problem is to introduce a lock variable:
public class MyTab extends Activity { private static final TAG = MyTab.this.getName(); private RemoteService remoteService = null; private final Object() lock = new Object(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getApplicationContext().bindService()) { // Synchronized access synchroized (lock) { try { while (remoteService == null) { lock.wait(); } } catch (InterruptedException e) { // Recheck condition } } Log.v(TAG, "Service bound ? " + remoteService != null ? "true" : "false"; } } private class MyServiceConnection implements ServiceConnection { @Override public void onServiceConnected (final ComponentName name, final IBinder service) { // Synchronized access synchronized (lock) { remoteService = RemoteService.stub.asInterface(service); lock.notifyAll(); } } @Override public void onServiceDisconnected (final ComponentName name) { // Synchronized access synchronized (lock) { remoteService = null; lock.notifyAll(); } } } }But we are not all done yet. We must use the same lock variable to pretect EVERY read/write access to the remoteService variable in this class. Why? Because the ServiceConnection.onServiceDisconnected() may be called from the main looper thread when the process hosting the background service has terminated or stopped unexpectedly. This can happen even though a service would normally be kept alive as long as there is a binding to it. Therefore, we need to surround every access to the remoteService variable with a lock to pretect ourself from reading stale object reference.
Locksmith Uxbridge
ReplyDeleteLocksmiths are called to unlock doors of our cars or homes. Have you ever wondered how they do their magic? If you’ve ever had to call one, you may probably have seen the locksmith tools that they use to save the day.