Search code examples
javaandroidandroid-asynctaskprogress-barinputstream

Showing inputstream file read progress with AsyncTask


I would like to show the progress of a file being read, and placed into an array list. In doing so, before the application presents the array-list in a list view to the user, I would like to show how much of the file has been read via an AsyncTask. Currently a white screen is displayed briefly. The file being read consists of around 20000 lines.

The AsyncTask (MyTask) is executed in the the onCreate() method, and is as follows:

 private class MyAsync extends AsyncTask<Void, Integer, ArrayList<Movie>> {
    ProgressDialog mProgressDialog;
    ArrayList<Movie> movies;

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

        //Show progress to user
        mProgressDialog = new ProgressDialog(MovieRatingsActivity.this);
        mProgressDialog.setTitle("Reading file");
        mProgressDialog.setMessage("Reading file, Please Wait!");
        mProgressDialog.setIndeterminate(false);
        mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mProgressDialog.show();
    }

    @Override
    protected ArrayList<Movie> doInBackground(Void... voids) {

        try {
            InputStream inputStream = getResources().openRawResource(R.raw.ratings);
            int count = inputStream.available();

            // onProgressUpdate( (amount read by inputstream / size of file )* 100 );

            movies = Movie.loadFromFile(inputStream);
            return movies;

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

        return null;
    }

    @Override
    protected void onProgressUpdate(Integer... progress) {
        super.onProgressUpdate(progress);
        mProgressDialog.setProgress(progress[0]);
    }

    @Override
    protected void onPostExecute(ArrayList<Movie> movies) {
        super.onPostExecute(movies);
        mProgressDialog.dismiss();

        mInflater = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        setListAdapter(new RowIconAdapter(getApplicationContext(), R.layout.listrow, R.id.row_label, movies));
    }
}

The function Movie.loadFromFile(inputStream) - which is where the data is placed into the array-list

    /** Loads movie information from a raw resource file */
public static ArrayList<Movie> loadFromFile(InputStream inputStream) {
    ArrayList<Movie> movies = new ArrayList<Movie>(20000);
    BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
    String line;
    try {
        while ((line = br.readLine()) != null) {
            String lRatings = line.substring(0,3).trim();
            String lVotes = line.substring(4,12).trim();
            String lName = line.substring(13).trim();
            movies.add(new Movie(lName, lRatings, lVotes));
        }
    } catch (IOException iox) { } // pure evil at work
    return movies;
}

Solution

  • Inside doInBackground() call publishProgress(value) where value is an integer representing the percentage of the job done.
    This will trigger onProgressUpdate() and you get the previously passed value in progress[0] and then you can update the progress bar accordingly.
    Edit the calculation of the percentage of the job done can only be made in the while loop of loadFromFile(). So in this case it's easier to drop loadFromFile() and put all its code inside doInBackground(). Then modify the loop like this:

    int counter = 0;
    while ((line = br.readLine()) != null) {
        String lRatings = line.substring(0,3).trim();
        String lVotes = line.substring(4,12).trim();
        String lName = line.substring(13).trim();
        movies.add(new Movie(lName, lRatings, lVotes));
        counter++;
        if ((counter % 200) == 0)
            publishProgress(counter / 200)
    } 
    

    The value counter / 200 will be 1% of the job done but you can change it if it's time consuming