简体   繁体   中英

Checking if the internet connection is lost at runtime

Good day. I know how to check if there is an internet connection available, my problem is that I want to present the user an AlertDialog that prevents action except trying again whenever the connection is lost or deactivated. What I don't know is how to code it only one time, so I don't need to replicate it manually in all activities.

I tried using Observer Pattern, and initialize it in SplashActivity(Launcher Activity).


 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);

        ObservedObject observedObject = new ObservedObject();
        observedObject.addObserver(new ObserverInternetConnection());

}
 public class ObservedObject extends Observable {
        private boolean isConnected;

        public boolean isConnected() {
            return isConnected;
        }

        public void setConnected(boolean connected) {
            isConnected = connected;
            setChanged();
            notifyObservers();
        }

     public class ObserverInternetConnection implements Observer {

        @Override
        public void update(Observable observable, Object o) {
            if (observable instanceof ObservedObject) {
                if (observable.hasChanged())
//alert is a method to show toast message
                    alert("connection changed");
                if (((ObservedObject) observable).isConnected)
                    alert("connected");
                else
                    alert("disconnected");

            }

        }
    }

It worked when I manually set the observedObject connection. But I want to avoid doing so. Is there a way to do this automatically? I was thinking of using another thread, but how could I do so? another problem is that the way i check the internet connection is using ConnectivityManager but it need me to pass the context and the context can (and will) change throughout the application, how can I overcome so? Is there any other approach for the problem?

I would suggest to create BaseActivity where you are initializing connectivity change listener (Observer in your case) and extend this activity with Splash, Main and other activities that you are using.

This way you are going to avoid code duplication.

Also don't forget to unregister listeners when activity is destroyed.

Also you dont need to use different threads. Here is example how to listen connectivity changes in Activity:

Register receiver first:

   @Override
    public void register(Context context) {
        initReceiver();
        final IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        context.registerReceiver(receiver, intentFilter);
    }

receiver

receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (isOnline()) {
                    hideNoConnectionError();
                } else {
                    showNoConnectionError();
                }
            }
        };

and isOnline()

 val isOnline: Boolean
        get() {
            return try {
                val connectivityManager = context.getSystemService(
                        Context.CONNECTIVITY_SERVICE) as ConnectivityManager
                connectivityManager.activeNetworkInfo != null &&
                        connectivityManager.activeNetworkInfo.isConnected
            } catch (exception: Exception) {
                false
            }
        }

sorry, last method is written in Kotlin, but I think it is completely understandable

One additional approach if your minimal SDK version >= N(24) would be to subscribe to ConectivityManager in Application class. In order to prevent user from interaction start transparrent activity on top with some shadowed background stating that connection lost. This is not ideal approach but you will not need to stick to inheritance.

TestApplication.java

public class TestApplication extends android.app.Application {
    private static final String TAG = "TestApplication";
    @Override
    public void onCreate() {
        super.onCreate();

        ConnectivityManager m = (ConnectivityManager) getSystemService(Service.CONNECTIVITY_SERVICE);
        m.registerDefaultNetworkCallback(new ConnectivityManager.NetworkCallback() {
            @Override
            public void onAvailable(Network network) {
                Log.e(TAG, "onAvailable: ");
                startActivity(ConnectionLostScreen.createIntentHideSplashOnNetworkRecovery(TestApplication.this));
            }

            @Override
            public void onLost(Network network) {
                Log.e(TAG, "onLost: ");
                startActivity(ConnectionLostScreen.createShowSplashOnNetworkFailure(TestApplication.this));
            }

        });
    }
}

ConnectionLostScreen.java

public class ConnectionLostScreen extends AppCompatActivity {
    private final static int SHOW = 1;
    private final static int HIDE = 2;
    private final static String EXTRA_NAME = "ACTION";

    public static Intent createShowSplashOnNetworkFailure(Context app) {
        Intent intent = new Intent(app, ConnectionLostScreen.class);
        intent.putExtra(EXTRA_NAME, SHOW);
        intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT| Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NO_ANIMATION);
        return intent;
    }

    public static Intent createIntentHideSplashOnNetworkRecovery(Context app) {
        Intent intent = new Intent(app, ConnectionLostScreen.class);
        intent.putExtra(EXTRA_NAME, HIDE);
        intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
        return intent;
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash_screen);

        if (getIntent() != null) handleIntent(getIntent());
    }

    @Override
    public void onBackPressed() {
       //disabled so user would not be able to close this activity.
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);

        if (intent != null) handleIntent(intent);
    }

    void handleIntent(Intent intent) {
        int value = intent.getIntExtra(EXTRA_NAME, 0);

        if (value == 0 || value == HIDE) {
            finish();
            return;
        }
    }
}

Theme for ConnectionLostScreen would be.

<style name="Theme.Transparent" parent="AppTheme">
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:backgroundDimEnabled">false</item>
</style>

Pros:

  • No inheritance.
  • Independent and works across application
  • No activity lifetime tracking
  • No need for Activity context as entire Activity acts like dialog.
  • Custom layout, graphic, animation could be integrated
  • No user action needed because when connection restored ConnectionLostScreen will be closed.

Cons:

  • Activity flow management for ConnectionLostScreen (making it singleTop etc.)
  • Hard to make granular control if only certain screens should be covered
  • Animations for Activity transitions

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM