0

My app sends data to the server. It generally works fine until the user is in a bad signal area. If the user is in a good signal area the the following code works fine and the data is sent.

String[] params = new String[]{compID, tagId, tagClientId, carerID,
                formattedTagScanTime, formattedNowTime, statusForWbService, getDeviceName(), tagLatitude, tagLongitude}; 
        AsyncPostData apd = new AsyncPostData();

            apd.execute(params);

.

private class AsyncPostData extends AsyncTask<String, Void, String> {

        ProgressDialog progressDialog;
        String dateTimeScanned;

        @Override
        protected void onPreExecute()
        {


           // progressDialog= ProgressDialog.show(NfcscannerActivity.this, 
                //  "Connecting to Server"," Posting data...", true); 

            int buildVersionSdk = Build.VERSION.SDK_INT;
            int buildVersionCodes = Build.VERSION_CODES.GINGERBREAD;

            Log.e(TAG, "buildVersionSdk = " + buildVersionSdk 
                    + "buildVersionCodes = " + buildVersionCodes);

            int themeVersion;
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD) {

                 themeVersion = 2;

            }else{

                 themeVersion = 1;
            }

            progressDialog = new ProgressDialog(NfcscannerActivity.this, themeVersion);
            progressDialog.setTitle("Connecting to Server");
            progressDialog.setMessage(" Sending data to server...");
            progressDialog.setIndeterminate(true);

            try{
            progressDialog.show();
            }catch(Exception e){

                //ignore
            }
        };  


        @Override
        protected String doInBackground(String... params) {

            Log.e(TAG, "carerid in doinbackground = " + params[3] + " dateTimeScanned in AsyncPost for the duplecate TX = " + params[4]);

            dateTimeScanned = params[4];

            return nfcscannerapplication.loginWebservice.postData(params[0], params[1], params[2], params[3], params[4],
                    params[5], params[6], params[7] + getVersionName(), params[8], params[9]);

        }

         @Override
            protected void onPostExecute(String result)
            {
             super.onPostExecute(result);

                try{
                progressDialog.dismiss();
                }catch(Exception e){
                    //ignore
                }

                if( result != null && result.trim().equalsIgnoreCase("OK")  ){

                    Log.e(TAG, "about to update DB with servertime");
                    DateTime sentToServerAt = new DateTime();
                    nfcscannerapplication.loginValidate.updateTransactionWithServerTime(sentToServerAt,null);
                    nfcscannerapplication.loginValidate.insertIntoDuplicateTransactions(dateTimeScanned);

                    tagId = null;
                    tagType = null;
                    tagClientId = null;

                    //called to refresh the unsent transactions textview
                    onResume();

                }else if(result != null && result.trim().equalsIgnoreCase("Error: TX duplicated")){
                    Log.e(TAG, "response from server is Duplicate Transaction ");


                    //NB. the following time may not correspond exactly with the time on the server
                    //because this TX has already been processed but the 'OK' never reached the phone,
                    //so we are just going to update the phone's DB with the DupTX time so the phone doesn't keep 
                    //sending it.

                    DateTime sentToServerTimeWhenDupTX = new DateTime();
                    nfcscannerapplication.loginValidate.updateTransactionWithServerTime(sentToServerTimeWhenDupTX,null);

                    tagId = null;
                    tagType = null;
                    tagClientId = null;



                }else{

                    Toast.makeText(NfcscannerActivity.this,
                            "No phone signal or server problem",
                            Toast.LENGTH_LONG).show();
                }
            }

    }//end of AsyncPostData 

.

The app in bad signal areas tends to show the progress bar for a few minutes before showing a black screen for a while rendering the app unusable.

I thought a way around this would be to do the following.

String[] params = new String[]{compID, tagId, tagClientId, carerID,
                formattedTagScanTime, formattedNowTime, statusForWbService, getDeviceName(), tagLatitude, tagLongitude}; 
        AsyncPostData apd = new AsyncPostData();
        try {
            apd.execute(params).get(10, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (TimeoutException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

This will cause the AsyncTask to cancel after 10 seconds, but as it is executing there is a black screen until the data is sent followed by the progressbar for a few millisecs.

Is there a way to show the progressbar whilst executing an AsyncTask.get()?

thanks in advance. matt.

Also are there any ideas why the black screen comes when the user is in bad signal area and therefor no response from the server. This senario seems to cause the app alot of problems where it's behavior is unusual afterwards like sending extra transactions at a later date.

[edit1]

public class SignalService extends Service{

    NfcScannerApplication nfcScannerApplication;
    TelephonyManager SignalManager;
    PhoneStateListener signalListener;
    private static final int LISTEN_NONE = 0;
    private static final String TAG = SignalService.class.getSimpleName();


    @Override
    public void onCreate() {
        super.onCreate();
        // TODO Auto-generated method stub
        Log.e(TAG, "SignalService created");
        nfcScannerApplication = (NfcScannerApplication) getApplication();
        signalListener = new PhoneStateListener() {
            public void onSignalStrengthChanged(int asu) {
                //Log.e("onSignalStrengthChanged: " , "Signal strength = "+ asu);
                nfcScannerApplication.setSignalStrength(asu);

            }
        };

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // TODO Auto-generated method stub
        Log.e(TAG, "SignalService destroyed");
        SignalManager.listen(signalListener, LISTEN_NONE);

    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        // TODO Auto-generated method stub
        Log.e(TAG, "SignalService in onStart");

         SignalManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
         SignalManager.listen(signalListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTH);

    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

}
turtleboy
  • 8,210
  • 27
  • 100
  • 199
  • Using `get()` will only make the UX worse: [Black screen while AsyncTask is running](http://stackoverflow.com/a/15259698/2558882). – Vikram Jul 18 '13 at 13:09
  • mmm yes i know that it blocks the UI thread but i don't know how i could set a timer on the asynctask to cancell without using .get(). – turtleboy Jul 18 '13 at 13:13
  • Is it possible to cancel asynctask using a handler? – turtleboy Jul 18 '13 at 13:13
  • Yes - it is you should be using a handler for time related functinos with an async task – Rarw Jul 18 '13 at 13:34
  • coding what @Rarw said: `new Handler().postDelayed(Runnable, delayInMilliseconds)`. Inside `run()` method of Runnable, put `myAsyncTask.cancel()`. You will need to dismiss the `ProgressDialog` inside `onCancelled()` of your AsyncTask. – Vikram Jul 18 '13 at 13:55
  • @vikram hi i've coded that up best i can, would you have a look at it please. The progress bar keeps spinning. http://stackoverflow.com/questions/17725767/cancelling-asynctask-and-its-progressbar-from-a-handler – turtleboy Jul 18 '13 at 14:08
  • @Rarw i've coded up an example if you have time to look. the link is in the above comment thanks. – turtleboy Jul 18 '13 at 14:09
  • Look at my answer see if this is what you're really trying to do – Rarw Jul 18 '13 at 14:14

1 Answers1

0

You do not need a timer at all to do what you're attempting (for some reason I thought you were trying to loop the AsyncTask based on your comments above which resulted in mine.). If I understand correctly you're issue is with the loss of service. You have an AsyncTask that you start which may or may not finish depending on certain conditions. Your approach was to use get and cancle the task after a fixed time in the event that it did not finish executing before then - the assumption being if the task didn't finish within the 10 second cut off, service was lost.

A better way to approach this problem is to use a boolean flag that indcates whether network connectivity is available and then stop the task from executing if service is lost. Here is an example I took from this post (I apologize for the formatting I'm on a crappy computer with - of all things - IE8 - so I can't see what the code looks like).

public class MyTask extends AsyncTask<Void, Void, Void> {

private volatile boolean running = true;
private final ProgressDialog progressDialog;

public MyTask(Context ctx) {
    progressDialog = gimmeOne(ctx);

    progressDialog.setCancelable(true);
    progressDialog.setOnCancelListener(new OnCancelListener() {
        @Override
        public void onCancel(DialogInterface dialog) {
            // actually could set running = false; right here, but I'll
            // stick to contract.
            cancel(true);
        }
    });

}

@Override
protected void onPreExecute() {
    progressDialog.show();
}

@Override
protected void onCancelled() {
    running = false;
}

@Override
protected Void doInBackground(Void... params) {

    while (running) {
        // does the hard work
    }
    return null;
}

// ...

} 

This example uses a progress dialog that allows the user to cancle the task by pressing a button. You're not going to do that but rather you're going to check for network connectivty and set the running boolean based on whether your task is connected to the internet. If connection is lost - running will bet set to false which will trip the while loop and stop the task.

As for the work after the task complete. You should NEVER use get. Either (1) put everything that needs to be done after the doInBackgroundCompletes in onPostExecute (assuming its not too much) or (2) if you need to get the data back to the starting activity use an interface. You can add an interface by either adding as an argument to your tasks constructor or using a seperate method that sets the interface up. For example

public void setInterface(OnTaskComplete listener){
    this.listener = listener;
}

Where OnTaskComplete listener is declared as an instance variable in your AsyncTask. Note the approach I am describing requires using a seperate AsyncTask class. Your's is private right now which means you need to change your project a little.

UPDATE

To check connectivity I would use something like this.

public boolean isNetworkOnline() {
boolean status=false;
try{
    ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo netInfo = cm.getNetworkInfo(0);
    if (netInfo != null && netInfo.getState()==NetworkInfo.State.CONNECTED) {
        status= true;
    }else {
        netInfo = cm.getNetworkInfo(1);
        if(netInfo!=null && netInfo.getState()==NetworkInfo.State.CONNECTED)
            status= true;
    }
}catch(Exception e){
    e.printStackTrace();  
    return false;
}
return status;

}  

You can check to see if there is an actual network connection over which your app can connect to ther server. This method doesn't have to be public and can be part of you're AsyncTask class. Personally, I use something similar to this in a network manager class that I use to check various network statistics (one of which is can I connect to the internet).

You would check connectivity before you started executing the loop in your doInBackground method and then you could periodicly update throughout the course of that method. If netowkr is available the task will continue. If not it will stop.

Calling the AsyncTask built in cancle method is not sufficient becuase it only prevent onPostExecute from running. It does not actually stop the code from execting.

Community
  • 1
  • 1
Rarw
  • 7,645
  • 3
  • 28
  • 46
  • Hi thanks for your input. I kind of understand what you mean but could you go into more detail regarding the check network connectivity. I've written code that checks signal strength but i've found it unreliable sometimes(always saying no signal when there is). I've posted an edit with the signal code, is that along the correct lines? thanks – turtleboy Jul 18 '13 at 15:14