Update sample NSD app to work reliably with current Android

Change the management of NSD Listener objects to one which ensures
that each Listener will be used for only one NSD service request at
a time (as the APIs were intended to function).  Listeners are now
allocated in a "lazy" on-demand way, rather than having one Listener
of each type allocated at application startup time.  When the Register
or Discover button is clicked, any existing Listener request of that
type will be canceled and the Listener discarded (avoiding the need
to wait until the Listener callback has been completed), and a new
Listener will be allocated.

Moves code around in the application-lifecycle callbacks to reflect
the current Android lifecycle.  Doing important things like
unregistering NSD services should not be done in the onDestroy()
callback, as there is no guarantee that the app won't be killed
before this callback is invoked.  This can lead to "zombie"
NSD registrations in KitKat.

Adds additional lifecycle logging.

Pass 2 - fix typo, clean up trailing whitespace

Pass 3 - fix onStart/onRestart mismatch

Bug: 13512512
Change-Id: Ic164110759204b27d8a14376777b593ebe1865fa
This commit is contained in:
Dave Platt
2014-03-28 13:54:12 -07:00
parent 2a137224a6
commit 73f1ba806f
3 changed files with 75 additions and 28 deletions

View File

@@ -52,7 +52,9 @@ public class ChatConnection {
public void tearDown() {
mChatServer.tearDown();
mChatClient.tearDown();
if (mChatClient != null) {
mChatClient.tearDown();
}
}
public void connectToServer(InetAddress address, int port) {

View File

@@ -43,6 +43,7 @@ public class NsdChatActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "Creating chat activity");
setContentView(R.layout.main);
mStatusView = (TextView) findViewById(R.id.status);
@@ -54,11 +55,6 @@ public class NsdChatActivity extends Activity {
}
};
mConnection = new ChatConnection(mUpdateHandler);
mNsdHelper = new NsdHelper(this);
mNsdHelper.initializeNsd();
}
public void clickAdvertise(View v) {
@@ -100,8 +96,20 @@ public class NsdChatActivity extends Activity {
mStatusView.append("\n" + line);
}
@Override
protected void onStart() {
Log.d(TAG, "Starting.");
mConnection = new ChatConnection(mUpdateHandler);
mNsdHelper = new NsdHelper(this);
mNsdHelper.initializeNsd();
super.onStart();
}
@Override
protected void onPause() {
Log.d(TAG, "Pausing.");
if (mNsdHelper != null) {
mNsdHelper.stopDiscovery();
}
@@ -110,16 +118,37 @@ public class NsdChatActivity extends Activity {
@Override
protected void onResume() {
Log.d(TAG, "Resuming.");
super.onResume();
if (mNsdHelper != null) {
mNsdHelper.discoverServices();
}
}
// For KitKat and earlier releases, it is necessary to remove the
// service registration when the application is stopped. There's
// no guarantee that the onDestroy() method will be called (we're
// killable after onStop() returns) and the NSD service won't remove
// the registration for us if we're killed.
// In L and later, NsdService will automatically unregister us when
// our connection goes away when we're killed, so this step is
// optional (but recommended).
@Override
protected void onDestroy() {
protected void onStop() {
Log.d(TAG, "Being stopped.");
mNsdHelper.tearDown();
mConnection.tearDown();
mNsdHelper = null;
mConnection = null;
super.onStop();
}
@Override
protected void onDestroy() {
Log.d(TAG, "Being destroyed.");
super.onDestroy();
}
}

View File

@@ -44,8 +44,6 @@ public class NsdHelper {
public void initializeNsd() {
initializeResolveListener();
initializeDiscoveryListener();
initializeRegistrationListener();
//mNsdManager.init(mContext.getMainLooper(), this);
@@ -87,13 +85,11 @@ public class NsdHelper {
@Override
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
@Override
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
};
}
@@ -125,24 +121,30 @@ public class NsdHelper {
@Override
public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) {
mServiceName = NsdServiceInfo.getServiceName();
Log.d(TAG, "Service registered: " + mServiceName);
}
@Override
public void onRegistrationFailed(NsdServiceInfo arg0, int arg1) {
Log.d(TAG, "Service registration failed: " + arg1);
}
@Override
public void onServiceUnregistered(NsdServiceInfo arg0) {
Log.d(TAG, "Service unregistered: " + arg0.getServiceName());
}
@Override
public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
Log.d(TAG, "Service unregistration failed: " + errorCode);
}
};
}
public void registerService(int port) {
tearDown(); // Cancel any previous registration request
initializeRegistrationListener();
NsdServiceInfo serviceInfo = new NsdServiceInfo();
serviceInfo.setPort(port);
serviceInfo.setServiceName(mServiceName);
@@ -154,12 +156,20 @@ public class NsdHelper {
}
public void discoverServices() {
stopDiscovery(); // Cancel any existing discovery request
initializeDiscoveryListener();
mNsdManager.discoverServices(
SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
}
public void stopDiscovery() {
mNsdManager.stopServiceDiscovery(mDiscoveryListener);
if (mDiscoveryListener != null) {
try {
mNsdManager.stopServiceDiscovery(mDiscoveryListener);
} finally {
}
mDiscoveryListener = null;
}
}
public NsdServiceInfo getChosenServiceInfo() {
@@ -167,6 +177,12 @@ public class NsdHelper {
}
public void tearDown() {
mNsdManager.unregisterService(mRegistrationListener);
if (mRegistrationListener != null) {
try {
mNsdManager.unregisterService(mRegistrationListener);
} finally {
}
mRegistrationListener = null;
}
}
}