Examples of how AsyncTask is used in PSLab Android App

In this blog, we will look at a very useful and important feature provided by Android – AsyncTask and more importantly how AsyncTasks have been put to use for various functionalities throughout the PSLab Android Project

What are Threads?

Threads are basically paths of sequential execution within a process. In a way, threads are lightweight processes. A process may contain more than one threads and all these threads are executed in parallel. Such a method is called “Multithreading”. Multithreading is very useful when some long tasks need to be executed in the background while other tasks continue to execute in the foreground.

Android has the main UI thread which works continuously and interacts with a user to display text, images, listen for click and touch, receive keyboard inputs and many more. This thread needs to run without any interruption to have a seamless user experience.

When AsyncTask comes into the picture?

AsyncTask enables proper and easy use of the UI thread. This class allows you to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.  

In PSLab Android application, we communicate with PSLab hardware through I/O(USB) interface. We connect the PSLab board with the mobile and request and wait for data such as voltage values and signal samples and once the data is received we display it as per requirements. Now clearly we can’t run this whole process on the main thread because it might take a long time to finish and because of that other UI tasks would be delayed which eventually degrade the user experience. So, to overcome this situation, we use AsyncTasks to handle communication with PSLab hardware.

Methods of AsyncTask  

AsyncTask is an Abstract class and must be subclassed to use. Following are the methods of the AsyncTask:

  • onPreExecute()
    • Used to set up the class before the actual execution
  • doInBackground(Params…)
    • This method must be overridden to use AsyncTask. This method contains the main part of the task to be executed. Like the network call etc.
    • The result from this method  is passed as a parameter to onPostExecute() method
  • onProgressUpdate(Progress…)
    • This method is used to display the progress of the AsyncTask
  • onPostExecute(Result)
    • Called when the task is finished and receives the results from the doInBackground() method

There are 3 generic types passed to the definition of the AsyncTask while inheriting. The three types in order are 

  1. Params: Used to pass some parameters to doInBackground(Params…) method of the Task 
  2. Progress: Defines the units in which the progress needs to be displayed/
  3. Result : Defines the data type to be returned from onInBackground() and receive as a parameter in the onPostExecute(Result) method

Example of the usage of the AsyncClass is as under : 

private class SampleTask extends AsyncTask<Params, Progress, Result> {
     @Override
     protected Result doInBackground(Params... params) {
          // The main code goes here
          return result;
     }
     @Override 
     protected void onProgressUpdate(Progress... progress) {
          // display the progress
     }
     @Override 
     protected void onPostExecute(Result result) {
         // display the result
     }
}

We can create an instance of this class as under and execute it.

SampleTask sampleTask = new SampleTask();
sampleTask.execute(params)

We can cancel a running class by calling the task.cancel() function

sampleTask.cancel()

AsyncTask in PSLab Android Application

As mentioned earlier some task which takes a lot of time, can’t be executed on the main thread. Hence in such cases AsyncTask is used. We will look into some examples where AsyncTask has been put to use in PSLab Android Application

Delete All Logs: 

In the DataLoggerActivity, user has an option to delete all the logs that have been saved on the local storage. Now there might be a lot number of log files that needs to be deleted. Hence it is better to use AsyncTask for these. The code snippet for this is below,

private class DeleteAllTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... voids) {
            Realm realm = Realm.getDefaultInstance();
            for (SensorDataBlock data : realm.where(SensorDataBlock.class)
                    .findAll()) {
                File logDirectory = new File(
                        Environment.getExternalStorageDirectory().getAbsolutePath() +
                                File.separator + CSVLogger.CSV_DIRECTORY +
                                File.separator + data.getSensorType() +
                                File.separator + CSVLogger.FILE_NAME_FORMAT.format(data.getBlock()) + ".csv");
                logDirectory.delete();
                realm.beginTransaction();
                realm.where(SensorDataBlock.class)
                        .equalTo("block", data.getBlock())
                        .findFirst().deleteFromRealm();
                realm.commitTransaction();
            }
            realm.close();
            return null;
        }
        @Override
        protected void onPostExecute(Void aVoid) {
            deleteAllProgressBar.setVisibility(View.GONE);
            if (LocalDataLog.with().getAllSensorBlocks().size() <= 0) {
                blankView.setVisibility(View.VISIBLE);
            }
        }
    }

As can be seen, we look for all the stored logs, and then delete each file one after another in doInBackground(). Once all the files are deleted, onPostExecute() is called, where we make the progress bar disappear. So, this how AsyncTask is used to implement deleteAllFiles feature.

Capture Task and Fourier Transform Output of Signals in Oscilloscope.

To display the generated signal in the oscilloscope, we call captureTraces() and fetchTraces functions from the ScienceLab class. Now, both these functions communicate with the PSLab Board, request for data, receives the data, manipulates it into the desired format and then display the signal on the Oscilloscope screen. Now clearly we can’t afford to run such a process on the main thread. So we use AsyncTask to handle it. 

In the Oscilloscope, there is a feature to see the fourier transform output of the signal generated by the oscilloscope. Now to generate the Fourier Transform Output of the signal, we use the Fast Fourier Transform method. The time complexity of  FFT (Fast Fourier Transform) is O(Nlog(N)), where N is the number of samples of the input signal. Now even if FFT is fast, we can risk to run this function on the main Thread. So once again we get help from AsyncTask.
Both of these functionalities are included in same AsyncTask Class called captureTask  A snippet for this task can be seen below,

public class CaptureTask extends AsyncTask<String, Void, Void> {
        private ArrayList<ArrayList<Entry>> entries = new ArrayList<>();
        private ArrayList<ArrayList<Entry>> curveFitEntries = new ArrayList<>();
        private Integer noOfChannels;
        private String[] paramsChannels;
        private String channel;
        @Override
        protected Void doInBackground(String... channels) {
            paramsChannels = channels;
            noOfChannels = channels.length;
            try {
                double[] xData;
                double[] yData;
                ArrayList<String[]> yDataString = new ArrayList<>();
                String[] xDataString = null;
                maxAmp = 0;
                for (int i = 0; i < noOfChannels; i++) {
                    entries.add(new ArrayList<>());
                    channel = channels[i];
                    HashMap<String, double[]> data;
                    if (triggerChannel.equals(channel))
                        scienceLab.configureTrigger(channelIndexMap.get(channel), channel, trigger, null, null);
                    scienceLab.captureTraces(1, samples, timeGap, channel, isTriggerSelected, null);
                    data = scienceLab.fetchTrace(1);

In this part of the capture Task class, we use the captureTrace() and fetchTrace() function to get the signal samples and then store them into the data variable. Below is the part where we use call the fft() for the input signal.

if (isFourierTransformSelected) {
     Complex[] yComplex = new Complex[yData.length];
     for (int j = 0; j < yData.length; j++) {
              yComplex[j] = Complex.valueOf(yData[j]);
     }
     fftOut = fft(yComplex);
}

This is a very simple part where we just call the Fast Fourier Transfer function is the user has selected to see the fourier transform output. The implementation of the Fourier function can be seen below,

 public Complex[] fft(Complex[] input) {
        Complex[] x = input;
        int n = x.length;
        if (n == 1) return new Complex[]{x[0]}; // if only single element, return as it is
        if (n % 2 != 0) {
            x = Arrays.copyOfRange(x, 0, x.length - 1);
        //No of samples should be even for this function to run, so i case of odd samples we remove the last element. This doesn’t affect the output significantly
        }
        Complex[] halfArray = new Complex[n / 2];
        for (int k = 0; k < n / 2; k++) {
            halfArray[k] = x[2 * k]; // Array of input terms at even places
        }
        Complex[] q = fft(halfArray); // recursive call for even terms
        for (int k = 0; k < n / 2; k++) {
            halfArray[k] = x[2 * k + 1]; // Array of terms at odd places
        }
        Complex[] r = fft(halfArray); // recursive call for odd terms
        Complex[] y = new Complex[n]; // Array of final output
        for (int k = 0; k < n / 2; k++) {
            double kth = -2 * k * Math.PI / n;
            Complex wk = new Complex(Math.cos(kth), Math.sin(kth)); // “kernel” for kth term is the output (based on nth root of unity)
            if (r[k] == null) {
                r[k] = new Complex(1); // exception handling
            }
            if (q[k] == null) {
                q[k] = new Complex(1); // exception handling
            }
            y[k] = q[k].add(wk.multiply(r[k])); // kth term will be addition of odd and even terms
            y[k + n / 2] = q[k].subtract(wk.multiply(r[k])); // (k + n/2)th term will be subtraction of odd and even terms
        }
        return y; // rsultant array
    }

This is a classic implementation of Fast Fourier Transform. We divide the samples of input into odd and even placed terms and call the same function recursively until there is only one term left. After that we use nth (n being the number of samples) complex root of  unity, we combine the results of odd termed fft() and even termed fft() to get the final output. Since at each iteration we are breaking the input into half it will run for O(logN) time and to merge the odd and even termed output we run a loop in each iteration on the O(N). So the total complexity would be O(NlogN), and since it might take longer to compute the fourier transform for large input we require it to be inside the AsyncTask and not on the main thread.

There are many other functionalities throughout the app, where AsyncTask has been used. In a nutshell, AsyncTask is a very useful method to handle longer tasks off the main thread. 

Resources

Tags: PSLab, Android, GSoC 19, AsyncTask, Threading

Continue ReadingExamples of how AsyncTask is used in PSLab Android App

Implement Sensor Data Fetching Using AsyncTask

In PSLab android app we have implemented sensor data fetching of various sensors inbuilt in the mobile device like light sensor, accelerometer, gyrometer. We can use PSLab to log the data and show in the form of the graph or maybe export the data in the form of CSV format for future use.

But recording data from the phone sensor imposes a serious problem in the performance of the Android app as it is a costly to process in terms of memory, resources and time. In CS terms there is too much work that has to be done on the single main thread which sometimes leads to lag and compromises the UX.

So as a solution we applied a concept of the Multithreading provided by Java in which we can shift the heavy process to a separate background thread so that the main thread never gets interrupted during fetching the sensor data and the background thread handles all the fetching and updates the UI as soon as it gets the data, till then the Main thread continues to serves the user so to user the application remains always responsive.

For implementing this we used a special class provided by Android Framework called AsyncTask. Which provides below methods:-

  • doInBackground() : This method contains the code which needs to be executed in the background. In this method, we can send results multiple times to the UI thread by publishProgress() method.

  • onPreExecute() : This method contains the code which is executed before the background processing starts.

  • onPostExecute() : This method is called after doInBackground method completes processing. Result from doInBackground is passed to this method.

  • onProgressUpdate() : This method receives progress updates from doInBackground() method, which is published via publishProgress() method, and this method can use this progress update to update the UI thread.

  • onCancelled(): This method is called when the background task has been canceled. Here we can free up resources or write some cleanup code to avoid memory leaks.

We created a class SensorDataFetch and extended this AsyncTask class and override its methods according to our needs.

private class SensorDataFetch extends AsyncTask<Void, Void, Void> implements SensorEventListener {

   private float data;
   private long timeElapsed;

   @Override
   protected Void doInBackground(Void... params) {
      
       sensorManager.registerListener(this, sensor, updatePeriod);
       return null;
   }

   protected void onPostExecute(Void aVoid) {
       super.onPostExecute(aVoid);
       visualizeData();
   }

   @Override
   protected void onPreExecute() {
 super.onPreExecute();
   //do nothing
   }

   @Override
   protected void onProgressUpdate(Void... values) {
       super.onProgressUpdate(values);
          //do nothing
   }

   @Override
   protected void onCancelled() {
       super.onCancelled();
          //do nothing
   }

In doInBackground() method we implemented the fetching raw data from the sensor by registering the listener and in onPostExecute() method we updated that data on the UI to be viewed by the user.

When this process is being run in the background thread the Main UI thread is free and remains responsive to the user. We can see in Figure 1 below that the UI is responsive to the user swipe action even when the sensor data is updating continuously on the screen.

Figure 1 shows Lux Meter responding to user swipe while fetching sensor data flawlessly.

 

Resources

https://developer.android.com/reference/android/os/AsyncTask – Android Developer documentation for Async Task class.

Continue ReadingImplement Sensor Data Fetching Using AsyncTask

Sensor Data Logging in the PSLab Android App

The PSLab Android App allows users to log data from sensors connected to the PSLab hardware device. The Connected sensors should support I2C, SPI communication protocols to communicate with the PSLab device successfully. The only prerequisite is the additional support for the particular sensor plugin in Android App. The user can log data from various sensors and measure parameters like temperature, humidity, acceleration, magnetic field, etc. These parameters are useful in predicting and monitoring the environment and in performing many experiments.

The support for the sensor plugins was added during the porting python communication library code to Java. In this post,  we will discuss how we logged real time sensor data from the PSLab Hardware Device. We used Realm database to store the sensor data locally. We have taken the MPU6050 sensor as an example to understand the complete process of logging sensor data.

Creating Realm Object for MPU6050 Sensor Data

The MPU6050 sensor gives the acceleration and gyroscope readings along the three axes X, Y and Z. So the data object storing the readings of the mpu sensor have variables to store the acceleration and gyroscope readings along all three axes.

public class DataMPU6050 extends RealmObject {

   private double ax, ay, az;
   private double gx, gy, gz;
   private double temperature;

   public DataMPU6050() {  }

   public DataMPU6050(double ax, double ay, double az, double gx, double gy, double gz, double temperature) {
       this.ax = ax;
       this.ay = ay;
       this.az = az;
       this.gx = gx;
       this.gy = gy;
       this.gz = gz;
       this.temperature = temperature;
   }

  // getter and setter for all variables
}

Creating Runnable to Start/Stop Data Logging

To sample the sensor data at 500ms interval, we created a runnable object and passed it to another thread which would prevent lagging of the UI thread. We can start/stop logging by changing the value of the boolean loggingThreadRunning on button click. TaskMPU6050 is an AsyncTask which reads each sample of sensor data from the PSLab device, it gets executed inside a while loop which is controlled by boolean loggingThreadRunning. Thread.sleep(500) pauses the thread for 500ms, this is also one of the reason to transfer the logging to another thread instead of logging the sensor data in UI thread. If such 500ms delays are incorporated in UI thread, app experience won’t be smooth for the users.

Runnable loggingRunnable = new Runnable() {
   @Override
   public void run() {
       try {
           MPU6050 sensorMPU6050 = new MPU6050(i2c);
           while (loggingThreadRunning) {
               TaskMPU6050 taskMPU6050 = new TaskMPU6050(sensorMPU6050);
               taskMPU6050.execute();
              // use lock object to synchronize threads
               Thread.sleep(500);
           }
       } catch (IOException   InterruptedException e) {
           e.printStackTrace();
       }
   }
};

Sampling of Sensor Data

We created an AsyncTask to read each sample of the sensor data from the PSLab device in the background thread. The getRaw() method read raw values from the sensor and returned an ArrayList containing the acceleration and gyro values. After the values were read successfully, they were updated in the data card in the foreground which was visible to the user. This data card acts as a real-time screen for the user. All the samples read are appended to ArrayList mpu6050DataList, when the user clicks on button Save Data, the collected samples are saved to the local realm database.

private ArrayList<DataMPU6050> mpu6050DataList = new ArrayList<>();

private class TaskMPU6050 extends AsyncTask<Void, Void, Void> {

   private MPU6050 sensorMPU6050;
   private ArrayList<Double> dataMPU6050 = new ArrayList<>();

   TaskMPU6050(MPU6050 mpu6050) {
       this.sensorMPU6050 = mpu6050;
   }

   @Override
   protected Void doInBackground(Void... params) {
       try {
           dataMPU6050 = sensorMPU6050.getRaw();
       } catch (IOException e) {
           e.printStackTrace();
       }
       return null;
   }

   @Override
   protected void onPostExecute(Void aVoid) {
       super.onPostExecute(aVoid);
       // update data card TextViews with data read.
       DataMPU6050 tempObject = new DataMPU6050(dataMPU6050.get(0), dataMPU6050.get(1), dataMPU6050.get(2),
               dataMPU6050.get(4), dataMPU6050.get(5), dataMPU6050.get(6), dataMPU6050.get(3));
       mpu6050DataList.add(tempObject);
       synchronized (lock) {
           lock.notify();
       }
   }
}

Source: PSLab Android App

There is an option for Start/Stop Logging, clicking on which will change the value of boolean loggingThreadRunning which stops starts/stops the logging thread.

When the Save Data button is clicked, all the samples of sensor data collected from the  PSLab device till that point are saved to the local realm database.

realm.beginTransaction();
for (DataMPU6050 tempObject : mpu6050DataList) {
   realm.copyToRealm(tempObject);
}
realm.commitTransaction();

Data can also be written asynchronously to the local realm database. For other methods to write to a real database refer write section of Realm docs.

Resources

Continue ReadingSensor Data Logging in the PSLab Android App

Receiving Data From the Network Asynchronously

We often need to receive information from networks in Android apps. Although it is a simple process but the problem arises when it is done through the main user interaction thread. To understand this problem better consider using an app which shows some text downloaded from the online database. As the user clicks a button to display a text it may take some time to get the HTTP response. So what does an activity do in that time? It creates a lag in the user interface and makes the app to stop responding. Recently I implemented this in Connfa App to download data in Open Event Format.

To solve that problem we use concurrent thread to download the data and send the result back to be processed separating it from main user interaction thread. AsyncTask allows you to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.

AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most). If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.

An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called onPreExecute, doInBackground, onProgressUpdate and onPostExecute.

In this blog, I describe how to download data in an android app with AsyncTask using OkHttp library.

First, you need to add dependency for OkHttp Library,

compile 'com.squareup.okhttp:okhttp:2.4.0' 


Extend AsyncTask class and implement all the functions in the class by overriding them to modify them accordingly. Here I declare a class named AsyncDownloader extending AsyncTask. We took the string parameter, integer type progress and string type result to return instead which will be our JSON data and param is our URL. Instead of using get the function of AsyncTask we implement an interface to receive data so the main user interaction thread does not have to wait for the return of the result.

public class AsyncDownloader extends AsyncTask<String, Integer, String> {
    private String jsonData = null;

    public interface JsonDataSetter {
        void setJsonData(String str);
    }


    JsonDataSetter jsonDataSetterListener;

    public AsyncDownloader(JsonDataSetter context) {

        this.jsonDataSetterListener = context;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

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

        String url = params[0];

        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .build();
        Call call = client.newCall(request);

        Response response = null;

        try {
            response = call.execute();

            if (response.isSuccessful()) {
                jsonData = response.body().string();

            } else {
                jsonData = null;
            }

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


        return jsonData;
    }

    @Override
    protected void onPostExecute(String jsonData) {
        super.onPostExecute(jsonData);
        jsonDataSetterListener.setJsonData(jsonData);
    }
}


We download the data in doInBackground making a request using OkHttp library and send the result back in onPostExecute method using our interface method. See above to check out the complete class implementation.

You can make an instance to AsyncDownloader in an activity. Implement interface to receive that data.

Tip: Always close AsyncTask after using to avoid many concurrent tasks at one time.

Find the complete code here.

References:

Continue ReadingReceiving Data From the Network Asynchronously

Developing Control Panel for Sensor Activity in PSLab Android

Once we are able to capture data from the sensor using the PSLab device and stimulate it on PSLab Android App, we now require to provide the user various control options. These control options help the user to customize the data captures from the sensors. These options are available for all the sensors.

  • Number of samples: This allows the user to enter the number of samples he/she wants to capture.
  • Indefinite mode: This allows the user to capture indefinite samples from the sensors.
  • Play/Pause: This allows the user to start or pause the capture anytime.
  • Time-gap: User can set the time-gap between each sample capture.

Let’s discuss how to implement these control options in PSLab Android.

Creating layout for Control Panel

Initially, a control panel is created. A separate layout is created for the same in the sensor activity. Inside the layout, we added

  • An Image-Button which works as a play and pause button
  • An Edit-Text in which the user can enter the number of samples to be captured.
  • A Check-Box which enables indefinite sample capture.
  • A Seek-Bar which sets the time-gap between each sample capture.

Adding functionality to widgets.

Image-Button on-click listener has two roles to play. One role is to change the play image to pause image or vice versa and another is to set boolean variable true or false. This variable is used to stop or start the thread which is involved in fetching data from the sensor.

playPauseButton.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
       if (play) {
           playPauseButton.setImageResource(R.drawable.play);
           play = false;
       } else {
           playPauseButton.setImageResource(R.drawable.pause);
           play = true;
       }
   }
});

The play variable can be accessed by the different fragment to pause or resume the capture of the data from the sensors.

if (scienceLab.isConnected() && ((SensorActivity) getActivity()).play) {
//rest of the code
}

The number entered in the Edit-Box work as the maximum limit of samples to be captured. For this, a simple counter function is implemented. If the count value reaches the value in Edit-Box the thread is AsyncTask for fetching sensor data is not called any further. Enabling the Check-Box, disables the Edit-Box and hence eliminate the role of counter function resulting in AsyncTask (for fetching sensor data) being called indefinitely.

Time gap Seek-Bar sets the delay between each time AsyncTask for fetching sensor data is called. The thread sleeps for  the time selected in the Seek-Bar before AsyncTask is called again. Here is the code snippet for it.

try {
   Thread.sleep(((SensorActivity) getActivity()).timegap);
} catch (InterruptedException e) {
   e.printStackTrace();
}

This implements control panel for sensor activity in PSLab Android. To follow the entire code, click here.

Resources

Stack Overflow solution on how to change Imagebutton’s image onClick.

Continue ReadingDeveloping Control Panel for Sensor Activity in PSLab Android