Search code examples
androidandroid-asynctaskpolling

How to poll server using Service and ASyncTask and update UI


I am currently using ZXing Barcode reader to scan a QR code. Using the API, the ZXing code has a "onActivityResult()" method to handle success or failure scans.

If it is successful, I call the checkQR class, which consists of a ASyncTask. Currently it returns the results once, as it is only called after scanning.

How do I keep calling/polling at an interval of 30 seconds, Update the textView and stop it (kill the service) after it detects a certain text (for example "it is done")?

Note: CheckQR constructor takes in a Context and TextView. orderstatus is the TextView which i wish to update the response from the server.

Partial code for onActivityResult()

public void onActivityResult(int requestCode, int resultCode, Intent intent) {
    IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
    if (scanResult != null) {
        String contents = scanResult.getContents();
        if (contents != null) {             
            orderNum.setText("Order Number: " + contents);
            new CheckQR(this,orderStatus).execute(contents);
        } else {
        //failed
        }
    }

Solution

  • There are too many caveats with your question. Do you want this scheduler to keep running outside Activity ? Do you want to rigidly call CheckQR every 30s even if the previous one has not completed ?

    I am assuming you want to call CheckQR for as long as your Activity lives because it updates a TextView. So if you want to make a chain call which starts after CheckQR completes then you can simply do it recursively with Handler in onPostExexute.

    private CheckQR cqr;
    
    class CheckQR extends AsyncTask<Void, Void, String>{
    
        @Override
        protected String doInBackground(Void... voids) {
            if (isCancelled()){
                return null;
            }
            String res = httpCall();
            return res;
        }
    
        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            if (result == null || isCancelled() || result.equals("it is done")){
                return;
            }
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    cqr = new CheckQR();
                    cqr.execute();
                }
            }, 30000);
        }
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        cqr.cancel(true);
    }
    

    If you want to start CheckQR every 30s no matter if the previous one has completed or not then use ScheduledExecutorService

            ScheduledExecutorService scheduler =
                Executors.newSingleThreadScheduledExecutor();
    
            ScheduledFuture scheduledFuture = scheduler.scheduleAtFixedRate
                (new Thread(){
    
                    @Override
                    public void run() {
                        //do blocking http call
    
                        if(stopCondition)//when stop condition is met
                            scheduledFuture.cancel(false);
    
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                if (!flagActivityOnDestroyedRaised){
                                    // you need this flag to prevent 
                                    // updating UI when Activity is already 
                                    // destroyed
                                    textView.setText("aaaa");
                                }
    
                            }
                        });
                    }
                }, 0, 30, TimeUnit.SECONDS);
    

    Clean up in onDestroy

    @Override
    protected void onDestroy() {
        super.onDestroy();
        scheduledFuture.cancel(false);
        flagActivityOnDestroyedRaised = true; 
    }
    

    This code is just a pseudo code. You need to declare some of the references here as instance variables and use the right methods. If you use ScheduledExecutorService then you need to unwrap your AsyncTask into Thread with runOnUiThread.