package org.jivesoftware.smack; import java.util.logging.Logger; import org.jivesoftware.smack.util.DNSUtil; import org.jivesoftware.smack.util.dns.dnsjava.DNSJavaResolver; import org.xbill.DNS.Lookup; import org.xbill.DNS.ResolverConfig; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; public class SmackAndroid { private static final Logger LOGGER = Logger.getLogger(SmackAndroid.class.getName()); private static SmackAndroid sSmackAndroid = null; private BroadcastReceiver mConnectivityChangedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { LOGGER.fine("ConnectivityChange received, calling ResolverConfig.refresh() and Lookup.refreshDefault() in new Thread"); // Lookup.refreshDefault may cause network I/O. So in order to prevent a NetworkOnMainThreadException, // we refresh dnsjava in a new thread. // Full stacktrace of the offending call: // Caused by: android.os.NetworkOnMainThreadException // at android.os.StrictMode.onNetwork(StrictMode.java:1128) // at java.net.InetAddress.lookupHostByName(InetAddress.java:385) // at java.net.InetAddress.getAllByNameImpl(InetAddress.java:236) // at java.net.InetAddress.getByName(InetAddress.java:289) // at org.xbill.DNS.SimpleResolver.<init>(SimpleResolver.java:56) // at org.xbill.DNS.SimpleResolver.<init>(SimpleResolver.java:68) // at org.xbill.DNS.ExtendedResolver.<init>(ExtendedResolver.java:266) // at org.xbill.DNS.Lookup.refreshDefault(Lookup.java:86) // at org.xbill.DNS.Lookup.<clinit>(Lookup.java:97) Thread thread = new Thread() { @Override public void run() { ResolverConfig.refresh(); Lookup.refreshDefault(); } }; thread.setDaemon(true); thread.start(); } }; private static boolean receiverRegistered = false; private Context mCtx; private SmackAndroid(Context ctx) { // Use the application context to prevent "receiver not registered" messages mCtx = ctx.getApplicationContext(); DNSUtil.setDNSResolver(DNSJavaResolver.getInstance()); } /** * Init Smack for Android. Make sure to call * SmackAndroid.onDestroy() in all the exit code paths of your * application. */ public static synchronized SmackAndroid init(Context ctx) { if (sSmackAndroid == null) { sSmackAndroid = new SmackAndroid(ctx); } sSmackAndroid.maybeRegisterReceiver(); return sSmackAndroid; } /** * Cleanup all components initialized by init(). Make sure to call * this method in all the exit code paths of your application. */ public synchronized void onDestroy() { LOGGER.fine("onDestroy: receiverRegistered=" + receiverRegistered); if (receiverRegistered) { mCtx.unregisterReceiver(mConnectivityChangedReceiver); receiverRegistered = false; } } private void maybeRegisterReceiver() { LOGGER.fine("maybeRegisterReceiver: receiverRegistered=" + receiverRegistered); if (!receiverRegistered) { mCtx.registerReceiver(mConnectivityChangedReceiver, new IntentFilter( ConnectivityManager.CONNECTIVITY_ACTION)); receiverRegistered = true; } } }