0

I have an application that detects if internet is available or not. I have changed the behaviour of the back button to avoid closing the application when pressed. The issue I'm facing is that when I have 4G or WIFI running and I run the app, it detects that internet is available, however, when I press the back button, the app is put on the background and internet is no longer detected by it.

I noticed that if I remove the permissions in the manifest file, the application works fine, it detects internet both when it is running and when put on background, but I need those permissions for making http post requests later.

Any help on this please?

Thanks.

MainActivity.java

public class MainActivity extends AppCompatActivity {
    Timer timer;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        init();
    }

    @Override
    public void onBackPressed() {
        this.moveTaskToBack(true);
    }

    private void init() {
        timer = new Timer();
        Tasker task = new Tasker(MainActivity.this, timer);
        task.execute();
    }

}

Tasker .java

public class Tasker extends AsyncTask<Void,Void,String> {
    final Handler handler = new Handler();
    static Timer timer;
    Context context;
    Toast toast;
    private TimerTask doAsynchronousTask;

    public Tasker(MainActivity context, Timer timer) {
        this.timer = timer;
        this.context = context;
    }

    @Override
    protected void onPreExecute() {
    }

    @Override
    protected String doInBackground(Void... voids) {
        doTimerTask();
        return null;
    }

    @Override
    protected void onPostExecute(String response) {

    }

    private void showToast(String message){
        toast = Toast.makeText(context, message, Toast.LENGTH_LONG);
        toast.setGravity(Gravity.CENTER, 0, 0);
        if(!((Activity) context).isFinishing()){
            toast.show();
        }
    }

    private void doTimerTask() {
        doAsynchronousTask = new TimerTask() {
            @Override
            public void run() {
                handler.post(new Runnable() {
                    @SuppressWarnings("unchecked")
                    public void run() {
                        if(haveNetworkConnection()){
                            showToast("Online");
                        }else{
                            showToast("Offline");
                        }

                    }
                });
            }
        };
        timer.schedule(doAsynchronousTask, 0,  10000);
    }

    private boolean haveNetworkConnection() {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
        boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
        return isConnected;
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.e.myapplication">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

2 Answers2

0

Actually, it may not be your desirable answer, but I think there is a way simpler way to do what you really want to do using a Broadcast receiver. you don't need to check network state using the timer. here's the link

Emad Razavi
  • 1,903
  • 2
  • 17
  • 24
  • I need a timer because i need to do an http request every x minutes and i need to check internet state before that. – Oussama Kamal Mar 24 '19 at 20:55
  • Using **Network Broadcast receiver**, you can get the state of your network at any time. you can use the timer for your specific condition, but you don't need to check network state inside that loop. see this : [link](http://www.androhub.com/android-detect-internet-connection-using-broadcast-receiver) – Emad Razavi Mar 24 '19 at 21:02
  • Thanks i will check it. – Oussama Kamal Mar 24 '19 at 21:05
  • You're welcome. if it helped you, vote my answer as accepted, please. – Emad Razavi Mar 24 '19 at 21:08
  • I will when i check and change the code to service broadcasting – Oussama Kamal Mar 24 '19 at 21:09
  • If I understood the question correctly, I don't think this would be what OP wanted. OP is trying to periodically do something with the internet connection as a prerequisite instead of doing something whenever the internet state changes. My suggestion would be to use a [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager) or [AlarmManager](https://developer.android.com/reference/android/app/AlarmManager). – Jack Mar 25 '19 at 01:47
  • I may have missexplaned my issue. The async task is working fine, my problem is that this line this.moveTaskToBack(true); puts the application in the background and then the toast message show "offline" even though internet is available. The toast only says "online" when the app is in foreground. So i am trying to understand why. – Oussama Kamal Mar 25 '19 at 07:00
0

I would suggest you to use a WorkManager or AlarmManager, or even Services for background related periodic tasks.

Using the Timer-AsyncTask combination is not a feasible approach and it could lead to many problems, one of which being it could easily be terminated by Android once it's in background.

My top pick would be WorkManager as it handles the condition for the tasks for you nicely, for example, if you want to only launch your task if there's internet connection, then you simply add a Work Constraint to your work request like this

Constraint networkConstraint = new Constraints.Builder()
    .setRequiredNetworkType(NetworkType.CONNECTED)
    .build();

workRequest.setConstraints(constraints)

And your task will only be executed if the network is connected. BTW, they don't need to be manually re-set after reboot like AlarmManagers does.

However, there are downsides to it, one of them being the perodic requests can only occur every 15 minutes, which you can circumvent (though not recommended) by setting more one time work requests in each perodic request with smaller intervals of delayed start time.

Anyways, stop using the AsyncTask approach you are using now, and use one of the "legitimate" approaches Android approves to do background tasks, I recommend WorkManager, but based on your situation, you can choose whatever approach you like as long as it's meant to work in background.

Jack
  • 5,354
  • 2
  • 29
  • 54
  • I may have missexplaned my issue. The async task is working fine, my problem is that this line this.moveTaskToBack(true); puts the application in the background and then the toast message show "offline" even though internet is available. The toast only says "online" when the app is in foreground. So i am trying to understand why. – Oussama Kamal Mar 25 '19 at 09:32
  • As I said, your AsyncTask way is not the proper way to do background tasks (when your app is in the background), I suppose right now since your app is in the background without proper background mechanism, Android is treating the things you declared in the task as invalid (context, ConnectivityManager, and such), therefore you can't get the valid NetworkInfo, it's probably null if you test it. So, just use one of the proper background task mechanisms and it should work fine, until then, I think your task is currently running in a partially recycled state therefore all the problems occured. – Jack Mar 25 '19 at 22:07
  • I am not sure what you are saying is correct. I changed my asynctask to a broadcastreceiver on background but the issue is still the same. I opened a new question for it here BroadcastReceiver to detect internet on background https://stackoverflow.com/q/55342572/11159549 – Oussama Kamal Mar 25 '19 at 22:21
  • I have explained why that doesn't work either in your new question. I am confused now, what exactly is your goal here, do you want to do something whenever the internet state changes, or do you want to routinely do something but check the internet state beforehand? – Jack Mar 25 '19 at 22:50
  • Yes i do an http post request every 2 minutes and it is done using an async task in the background. I want before that check if internet is available that is why i tried the broadcast receiver that detects internet availibility on its state change and puts that on a variable that i can check before doing my http request. It is working but when i put the app in background via the backpress code i showed it does no longer work. – Oussama Kamal Mar 26 '19 at 06:49
  • I explained exactly why it doesn't work in my answer, because your current way is not how you do background tasks in Android. If your intention is to do routine tasks with prerequisites, then just try `WorkManager` like in my original answer, or something else if it doesn't work for you, but make sure it's a proper background mechanism for Android. I can't stress enough that your current way of doing this will not work properly because it's not a proper background mechanism of Android. – Jack Mar 26 '19 at 10:28