Pergunta

I am a bit confused about this so I would really appreciate somebody's help.

I have an activity - MainActivity, inside of the activity I have two classes - RetrieveThumbnailsTask (AsyncTask) and an adapter ImageAdapter (extends BaseAdapter). I am basically just retrieving the thumbnails of the images from the external storage and showing them in a gridview. Now this proved to be quite slow (for hundreds of images it takes quite a time) so I decided to create the thumbnails in an AsyncTask.

The code is /irrelevant parts left out/:

public class MainActivity extends Activity {

    private Cursor cursor;
    private Bitmap[] thumbnails;
    private ProgressDialog pd;

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

        init();
    }

    private void init() {
        createProgressDialog();
        new RetrieveThumbnailsTask(this).execute();
    }

    private void createProgressDialog() {
        //...
    }

    private void createThumbnails() {
        //...
    }

    private class ImageAdapter extends BaseAdapter {

        private Context mContext;

        public ImageAdapter(Context c) {
            mContext = c;
        }

        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return thumbnails.length;
        }

        @Override
        public Object getItem(int position) {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public long getItemId(int position) {
            // TODO Auto-generated method stub
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ImageView imageView;
            if (convertView == null) {  // if it's not recycled, initialize some attributes
                imageView = new ImageView(mContext);
                imageView.setLayoutParams(new GridView.LayoutParams(120, 120));
                imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
                imageView.setPadding(8, 8, 8, 8);
            }
            else {
                imageView = (ImageView) convertView;
            }

            imageView.setImageBitmap(thumbnails[position]);
            return imageView;   
        }
    }

    private class RetrieveThumbnailsTask extends AsyncTask<Void, Void, Boolean> {

        private MainActivity activity;

        public RetrieveThumbnailsTask(MainActivity a) {
            activity = a;
        }

        protected void onPreExecute() {
            pd.show();
        }

        protected Boolean doInBackground(Void... params) {
            activity.createThumbnails(); //This is the slow process that creates the thumbnails
            return true;
        }

        protected void onPostExecute(Boolean b) {
            pd.dismiss();
            GridView gridview = (GridView) findViewById(R.id.gridview);
            gridview.setAdapter(new ImageAdapter(activity));

            gridview.setOnItemClickListener(new OnItemClickListener() {
                public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
                    Toast.makeText(MainActivity.this, "" + position, Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
}

The part I don't understand is this:

GridView gridview = (GridView) findViewById(R.id.gridview);
gridview.setAdapter(new ImageAdapter(activity));

gridview.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
                Toast.makeText(MainActivity.this, "" + position, Toast.LENGTH_SHORT).show();
            }
});

Now when this code is inside of onPostExecute, everything works alright. But when it is inside doInBackground (right above the return true statement), the code hangs on gridview.setAdapter(new ImageAdapter(activity)); and the app force closes. So my question is - why does this happen? What is the explanation? I guess I must be missing something big time. Thank you!

Foi útil?

Solução

gridview is a UI element and you can't update the UI on a background Thread which is what you are doing with setAdapter() and is why it works in onPostExecute().

All methods of AsyncTask run on the UI Thread except for doInBackground() so that is the only one which you can't update UI elements. So if you have a problem with setting it in onPostExecute() then please explain what it is, although you said it works. If there is no problem then just set it there.

AsyncTask Docs

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top