How to Download Data and Update User Interface Using AsyncTask


AsyncTask is a helper class that makes performing a background task and updating the user interface (UI) painless. The class takes care of the communication between the background thread and the main UI thread. All you have to do is override some methods in the AsyncTask class to perform the UI update(s).

 

In this post, we’ll be looking at a simple app that uses AsyncTask to download some data from an URL while enabling and disabling a progress bar. I am going to assume you have a general idea of what an AsyncTask is. If that is not the case, I recommend that you check out my post about AsyncTask before proceeding.


 

The Sample App

 

 

The app performs a simple functionality. It takes in an URL and tries to fetch the data at that URL. When the background task is fetching the data, the progress bar will be active. When the task is complete or is not fetching any data the progress bar will be inactive. After fetching the data successfully, it will be shown in the text view.

 

Using the Four Steps of AsyncTask

 

The sample app utilizes the four steps of an AsyncTask to perform the download and update the UI. The four steps are onPreExecute, doInBackground, onProgressUpdate, and onPostExecute. In each of the step, the following occurs:

 

  • onPreExecute: Enables the progress bar, which makes it visible to indicate downloading.

 

  • doInBackground: Performs a fetch for the data at the URL and store the data.

 

  • onProgressUpdate: Do nothing here since the progress bar is set to intermediate. It just keeps moving to indicate that the app is not frozen. This is where you would update the progress bar or other UI to reflect the percentage of the task complete if it is known in advance.

 

  • onPostExecute: Dismisses the progress bar by making it invisible and sets the text view to show the downloaded content. Note: in the example image, I used an URL to a webpage so what gets shown is the HTML version of the webpage.

 

The Code

 

public class MainActivity extends AppCompatActivity {

    private ProgressBar progressBar;
    private TextView webpageContentTextView;
    private EditText urlEditText;

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

        protected MainActivity mainActivity;

        public WebPageDownloader(MainActivity mainActivityRef) {
            mainActivity = mainActivityRef;
        }

        @Override
        protected String doInBackground(String... urls) {
            StringBuffer webPageContentStringBuffer = new StringBuffer();
            if (urls.length <= 0) {
                return "Invalid URL";
            }

            try {
                String url = urls[0];
                URL webUrl = new URL(url);
                InputStream webPageDataStream = webUrl.openStream();
                InputStreamReader webPageDataReader = new InputStreamReader(webPageDataStream);
                int maxBytesToRead = 1024;
                char[] buffer = new char[maxBytesToRead];
                int bytesRead =  webPageDataReader.read(buffer);

                while(bytesRead != -1) {
                    webPageContentStringBuffer.append(buffer, 0, bytesRead);
                    bytesRead = webPageDataReader.read(buffer);
                }

                return webPageContentStringBuffer.toString();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

            return "Failed to get webpage content";
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            if (mainActivity != null) {
                mainActivity.showProgressBar();
            }
        }

        @Override
        protected void onProgressUpdate(Void... progress) {
            super.onProgressUpdate();
        }

        @Override
        protected void onPostExecute(String webContent) {
            super.onPostExecute(webContent);
            if (mainActivity != null) {
                mainActivity.dismissProgressBar();
                mainActivity.setWebPageContent(webContent);
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        progressBar = findViewById(R.id.progressBar);
        webpageContentTextView = findViewById(R.id.webpageContentTextView);
        urlEditText = findViewById(R.id.urlEditText);
    }

    public void getWebPageContent(View view) {
        WebPageDownloader webPageDownloader = new WebPageDownloader(this);
        String url = urlEditText.getText().toString();
        try {
            // note: don't use get() if you want your UI thread to keep running
            // 'get' will pause the UI thread until the task finishes executing
            webPageDownloader.execute(url);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void log(String message) {
        Log.d("[Web Page Downloader] ", message);
    }

    private void showProgressBar() {
        progressBar.setVisibility(View.VISIBLE);
    }

    private void dismissProgressBar() {
        progressBar.setVisibility(View.INVISIBLE);
    }

    private void setWebPageContent(String webPageContent) {
        webpageContentTextView.setText(webPageContent);
    }
}

 

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="bddevlabs.com.webpagedownloader.MainActivity">

    <ScrollView android:layout_width="0dp" android:layout_height="0dp" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="16dp" android:fillViewport="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/progressBar">

        <TextView android:id="@+id/webpageContentTextView" android:layout_width="match_parent" android:layout_height="match_parent" android:text="Web Page Content Shows Here..." />

    </ScrollView>

    <EditText android:id="@+id/urlEditText" android:layout_width="306dp" android:layout_height="wrap_content" android:ems="10" android:hint="Enter URL" android:inputType="text" android:textColorLink="@android:color/darker_gray" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />

    <Button android:id="@+id/goButton" android:layout_width="73dp" android:layout_height="44dp" android:text="Go" app:layout_constraintStart_toEndOf="@+id/urlEditText" app:layout_constraintTop_toTopOf="parent" android:onClick="getWebPageContent"/>

    <ProgressBar android:id="@+id/progressBar" style="@style/Widget.AppCompat.ProgressBar.Horizontal" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="16dp" android:layout_marginStart="16dp" android:layout_marginTop="8dp" android:indeterminate="true" android:indeterminateTint="@android:color/holo_blue_light" android:visibility="invisible" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/urlEditText" tools:visibility="invisible" />
</android.support.constraint.ConstraintLayout>

 

Above is the code for the activity and the layout of that activity. The main activity is where the AsyncTask goes off and fetch the data from an URL. For the entire Android project of this sample app, you can visit the GitHub page.


 

I hope this post was helpful to you. If you found this post helpful, share it with others so they can benefit too.

 

To get in touch, you can follow me on Twitter, leave a comment, or send me an email at steven@brightdevelopers.com.


About Steven To

Steven To is a software developer that specializes in mobile development with a background in computer engineering. Beyond his passion for software development, he also has an interest in Virtual Reality, Augmented Reality, Artificial Intelligence, Personal Development, and Personal Finance. If he is not writing software, then he is out learning something new.