the_prole
the_prole

Reputation: 8945

How to bind data in an adapter on a seperate thread

I have inner classes ViewHolder and StringHolder in my custon adapter class

private class StringHolder {
    String awards; String countries; String directors; String fullPlot; String genres; String ID;
    String imdbRating; String imdbVotes; String lastUpdated; String languages; String metacritic;
    String posterUrl; String shortPlot; String rating; String releaseDate; String runtime; String writers;
    String title; String imdbId; String cast;
    public StringHolder(Cursor cursor){
        awards = cursor.getString(cursor.getColumnIndexOrThrow("Awards"));
        countries = cursor.getString(cursor.getColumnIndexOrThrow("Country"));
        directors = cursor.getString(cursor.getColumnIndexOrThrow("Director"));
        fullPlot = cursor.getString(cursor.getColumnIndexOrThrow("FullPlot"));
        genres = cursor.getString(cursor.getColumnIndexOrThrow("Genre"));
        ID = cursor.getString(cursor.getColumnIndexOrThrow("ID"));
        imdbRating = cursor.getString(cursor.getColumnIndexOrThrow("imdbRating"));
        imdbVotes = cursor.getString(cursor.getColumnIndexOrThrow("imdbVotes"));
        lastUpdated = cursor.getString(cursor.getColumnIndexOrThrow("lastUpdated"));
        languages = cursor.getString(cursor.getColumnIndexOrThrow("Language"));
        metacritic = cursor.getString(cursor.getColumnIndexOrThrow("Metacritic"));
        posterUrl = cursor.getString(cursor.getColumnIndexOrThrow("Poster"));
        shortPlot = cursor.getString(cursor.getColumnIndexOrThrow("Plot"));
        rating = cursor.getString(cursor.getColumnIndexOrThrow("Rating"));
        releaseDate = cursor.getString(cursor.getColumnIndexOrThrow("Released"));
        runtime = cursor.getString(cursor.getColumnIndexOrThrow("Runtime"));
        writers = cursor.getString(cursor.getColumnIndexOrThrow("Writer"));
        title = cursor.getString(cursor.getColumnIndexOrThrow("Title"));
        imdbId = cursor.getString(cursor.getColumnIndexOrThrow("imdbID"));
        cast = cursor.getString(cursor.getColumnIndexOrThrow("Actors"));

    }
}

private class ViewHolder {
    TextView cast; TextView title; TextView plot; TextView imdbratings; TextView votes;
    ImageView bookmark; ImageView share; ImageView IMDBProfile; FlowLayout flowLayout;
    TextView releaseDate; TextView directors; TextView countries; TextView genres;
    public ViewHolder(View view){
        genres = (TextView) view.findViewById(R.id.genres);
        countries = (TextView) view.findViewById(R.id.countries);
        directors = (TextView) view.findViewById(R.id.directors);
        releaseDate = (TextView) view.findViewById(R.id.releaseDate);
        title = (TextView) view.findViewById(R.id.Title);
        plot = (TextView) view.findViewById(R.id.plot);
        imdbratings = (TextView) view.findViewById(R.id.rating);
        votes = (TextView) view.findViewById(R.id.votes);
        flowLayout = (FlowLayout) view.findViewById(R.id.hash_tag_layout);
        bookmark = (ImageView)view.findViewById(R.id.bookmark);
        share = (ImageView)view.findViewById(R.id.share);
        IMDBProfile = (ImageView)view.findViewById(R.id.IMDBProfile);
        cast = (TextView) view.findViewById(R.id.cast);
    }
}

I set the strings from StringHolder (queried from my database) to the text views in ViewHolder in the bindView method of my cusotm adapter

public void bindView(final View view, final Context context, final Cursor cursor) {

    // Get recycled viewHolder
    final ViewHolder viewHolder  =   (ViewHolder) view.getTag();

    // Bind strings to views in viewHolder
    StringHolder stringHolder = new StringHolder(cursor);
    viewHolder.title.setText(stringHolder.title);
    viewHolder.plot.setText(parsePlot(stringHolder.shortPlot, stringHolder.fullPlot));
    viewHolder.imdbratings.setText(stringHolder.imdbRating + "/10");
    viewHolder.votes.setText(formatNumbers(stringHolder.imdbVotes));
    viewHolder.countries.setText(stringHolder.countries);
    viewHolder.directors.setText(stringHolder.directors);
    viewHolder.releaseDate.setText(parseDate(stringHolder.releaseDate));
    viewHolder.genres.setText(stringHolder.genres);
    viewHolder.cast.setText(stringHolder.cast);

}

The problem is my main thread is doing a huge amound of work and skipping frames. I tried binding the views in a new thread like so

public void bindView(final View view, final Context context, final Cursor cursor) {

    // Get recycled viewHolder
    final ViewHolder viewHolder  =   (ViewHolder) view.getTag();

    // Bind strings to views in viewHolder
    new Thread() {
        @Override
        public void run() {

            StringHolder stringHolder = new StringHolder(cursor);
            viewHolder.title.setText(stringHolder.title);
            viewHolder.plot.setText(parsePlot(stringHolder.shortPlot, stringHolder.fullPlot));
            viewHolder.imdbratings.setText(stringHolder.imdbRating + "/10");
            viewHolder.votes.setText(formatNumbers(stringHolder.imdbVotes));
            viewHolder.countries.setText(stringHolder.countries);
            viewHolder.directors.setText(stringHolder.directors);
            viewHolder.releaseDate.setText(parseDate(stringHolder.releaseDate));
            viewHolder.genres.setText(stringHolder.genres);
            viewHolder.cast.setText(stringHolder.cast);

        }
    }.start();

}

Now I get this error

Only the original thread that created a view hierarchy can touch its views.

Any idea how to fix the error while maintaing the extra work in a seperate thread?

edit:

Here is my newView method

// Apply recycling to a view container
public View newView(Context context, Cursor cursor, ViewGroup parent) {

    View view = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
    ViewHolder viewHolder = new ViewHolder(view);
    view.setTag(viewHolder);

    return view;
}

Upvotes: 0

Views: 915

Answers (2)

X3Btel
X3Btel

Reputation: 1428

Its not good idea to move the whole view binding on different thread. seting text to view is not expensive operation creating the StringHolder is. You can AsyncTask to read form the cursor in the doInBackground method, then onPostExecute, which is run on UI thread, you can set values to your views

Upvotes: 1

vareste
vareste

Reputation: 445

use runOnUiThread()

runOnUiThread(new Runnable() {

    @Override
    public void run() {
        StringHolder stringHolder = new StringHolder(cursor);
        viewHolder.title.setText(stringHolder.title);
        viewHolder.plot.setText(parsePlot(stringHolder.shortPlot,stringHolder.fullPlot));
        viewHolder.imdbratings.setText(stringHolder.imdbRating + "/10");
        viewHolder.votes.setText(formatNumbers(stringHolder.imdbVotes));
        viewHolder.countries.setText(stringHolder.countries);
        viewHolder.directors.setText(stringHolder.directors);
        viewHolder.releaseDate.setText(parseDate(stringHolder.releaseDate));
        viewHolder.genres.setText(stringHolder.genres);
        viewHolder.cast.setText(stringHolder.cast);               
    }
});

Upvotes: 0

Related Questions