How can I stop async tasks that loops in background android after onPause() is called?

I'm using package com.hierynomus.smbj.share; to connect via smb2 to a network location in order to check it's connectivity however this only runs at the start of my activity (in background).

I've added a listener to return after the task has returned a string value (fail, success) once the the listener in the activity (i called the task from) is called, I then create a new instance of the Connection Status (this loops it)

This is how i check for the connection at onCreate() of an activity

//Global ConnectionStatus connectionStatus;

        connectionStatus = new ConnectionStatus();
        connectionStatus.setContext(this);
        connectionStatus.setListener(this);
        connectionStatus.setCon(databaseReadWrite.getMydbc());
        connectionStatus.execute("CheckDatabase", "nodelay");

This is how I'm trying to cancel task when another activity is opened

  protected void onPause() {
        delay.equals("cancel");
        super.onPause();
        MyApplication.activityPaused();
        if (connectionStatus != null) {
            connectionStatus.cancel(true);

        }
        hasRun = false;

    }

Then this runs in the same activity after the async task is completed so i've re-run a new instance of connectionStatus

@Override
    public void onTaskCompleted(String result) {
            ActionBar actionBar = this.getSupportActionBar();
            String title = getTitle().toString();
            String code = handlingFunctions.getResultCode(result);
            if (code.equals("1")) {
                Message.message(this, " Database connected to server!");
                setTitle(title + result);
            } else if (code.equals("2")) {
                actionBar.setBackgroundDrawable(new ColorDrawable(Color.RED));
                alertDialog.message(this, result);
            } else if (code.equals("0")) {
                actionBar.setBackgroundDrawable(new ColorDrawable(Color.RED));
                setTitle(title + " Database connected in offline mode");
                alertDialog.message(this, result);
            } else if (code.equals("3")) {
                //alertDialog.message(this, result);
                imageStatus.setText(result);
            } else if (code.equals("4")) {
                imageStatus.setText(result);
            }
            connectionStatus = new ConnectionStatus();
            connectionStatus.setContext(getApplicationContext());
            connectionStatus.setListener(AllParts.this);
            connectionStatus.setCon(databaseReadWrite.getMydbc());
            connectionStatus.execute("CheckDatabase", "delay");

        }
    }



  public class ConnectionStatus extends AsyncTask<String, Void, String> {

    private OnConnectionStatusComplete listener;
    private ArrayList<String> imageNames;
    private ArrayList<ImageDetails> currentImageDetails;
    private SQLiteConnection sqLiteConnection;
    private Context context;

    public void setListener(OnConnectionStatusComplete listen) {
        this.listener = listen;
    }

    public void setImageNames(ArrayList<String> ImageNames) {
        this.imageNames = ImageNames;
    }

    public void setCurrentDetails(ArrayList<ImageDetails> details) {
        this.currentImageDetails = details;
    }

    @Override
    protected void onPostExecute(String s) {
        listener.onTaskCompleted(s);
    }

    public void setContext(Context mContext) {
        context = mContext;
    }

    public void setCon(SQLiteConnection sqlite) {
        sqLiteConnection = sqlite;
    }

     @Override
    protected String doInBackground(String... strings) {
         if(this.isCancelled()){
        return "";
    }else{

                MyApplication myApplication = (MyApplication) context.getApplicationContext();
                String IPAddress = myApplication.getIpaddress();
                String domain = myApplication.getDomainname();
                String username = myApplication.getUsername();
                String password = myApplication.getPassword();
                String containingFolder = myApplication.getSharefolder();
                String temp = "";

                //return null;

                if (strings[1].equals("delay")) {
                    try {
                        Thread.sleep(6000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (strings[0].equals("CheckDatabase")) {
                    temp = checkDatabaseConnect();
                } else {
                    temp = checkImageConnection(IPAddress, domain, username, password, containingFolder);
                }
                return temp;
            }


    }

String checkDatabaseConnect() {
    String statement = "PRAGMA sync_status";
    JSONArray is_ready = new JSONArray();
    try {
        SQLiteStatement mystatement = null;

        try {
            mystatement = sqLiteConnection.prepareStatement(statement);
        } catch (SQLException ex) {
            try {

                java.io.File path = new java.io.File("/sdcard/exports/logs");
                SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
                String currentDateTime = dateFormat.format(new Date()) + " ";
                java.io.File myFile = new java.io.File(path, "DBCrashes.txt");
                FileOutputStream fOut = new FileOutputStream(myFile, true);
                OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
                myOutWriter.append("\n" +
                        "\r");
                myOutWriter.append(currentDateTime + "Get pragma results: (" + statement + ")" + ex);
                myOutWriter.close();
                fOut.close();
            } catch (java.io.IOException e) {
                //do something if an IOException occurs.
            }

        }
        mystatement.step();
        int ncols = mystatement.getColumnCount();

        if (ncols > 0) {
            String result = mystatement.getColumnTextNativeString(0);
            JSONObject jObject = new JSONObject(result);
            is_ready = jObject.getJSONArray("peers");
            if (is_ready.length() > 0) {
                return "Success, Database is connected! (1)";
            } else {
                return "The database is not connected to the server. In offline mode, check network and restart application to connect to server. (0)";

            }
        }
        mystatement.dispose();

    } catch (SQLException ex) {
        try {

            java.io.File path = new java.io.File("/sdcard/exports/logs");
            SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
            String currentDateTime = dateFormat.format(new Date()) + " ";
            java.io.File myFile = new java.io.File(path, "DBCrashes.txt");
            FileOutputStream fOut = new FileOutputStream(myFile, true);
            OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
            myOutWriter.append("\n" +
                    "\r");
            myOutWriter.append(currentDateTime + " (" + statement + ")" + ex);
            myOutWriter.close();
            fOut.close();
            return "No connection to a database, please try again (2)";
        } catch (java.io.IOException e) {

            //do something if an IOException occurs.

        }

    } catch (JSONException e) {
        e.printStackTrace();
    }

    return "Success (5)";

}
}

The problem I'm having is after I leave the activity, the task is still running and returns this error (I know this because it takes into account the delay)

2 answers

  • answered 2019-02-10 12:31 Rene Ferrari

    You do have implemented a handling for isCanceled but this implementation is only at the start.

    Your current flow is like this:

    1. task starts, immediately checks if it is cancelled or not (since it is the first line in doInBackground)
    2. onPause is called, cancel of the task is invoked
    3. since the cancel check has already been made your task continues to run freely

    How do you solve this?

    The easiest way would be to check if it is cancelled before checkDatabaseConnection or checkImageConnection is called. And even inside those methods check if it is cancelled or not.

    Even if that is done correctly, your Thread.sleep could cause your AsyncTask being cancelled 6s after onPause is called.

    For reasons like this, AsyncTask is not used anymore. There are other options for Threading which are much better.

    This or this will give you a starting point.

  • answered 2019-02-10 12:31 medyas

    try checking if the task is cancelled after the Thread.sleep(6000) , so even if the task was in sleep when cancel is called it will return when it is done.

    if (strings[1].equals("delay")) {
       try {
          Thread.sleep(6000);
          if(this.isCancelled()) {
              return "";
          }
       } catch (InterruptedException e) {
          e.printStackTrace();
       }
       /*if(this.isCancelled()) {
          return "";
       }*/
    }