Question

I am populating a ListView with a customized cursor adapter that receives a cursor result set from a database. It can take up to a 10-12 seconds to display just 20 views!

Here is the CursorAdater class where the cursor supplies Strings and a base 64 Image representation to a series of Text-views and a Image-view for each view:

    public void bindView(View v, Context context, Cursor c) {
            String diveSite = c.getString(c.getColumnIndexOrThrow(diveDataBase.KEY_DIVESITE));
            String date = c.getString(c.getColumnIndexOrThrow(diveDataBase.KEY__DIVEDATE));
            String diveNumber= c.getString(c.getColumnIndexOrThrow(diveDataBase.KEY__DIVENUMBER));
            String diveImagePath = c.getString(c.getColumnIndex(diveDataBase.KEY_DIVEPICTURE));
            String rating = c.getString(c.getColumnIndexOrThrow(diveDataBase.KEY_DIVERATING));

            c.moveToLast();
            noOfRows = Integer.parseInt(c.getString(c.getColumnIndex(diveDataBase.KEY__DIVENUMBER)));


            /**
             * Next set the dive site name
             */

            TextView title_text = (TextView) v.findViewById(R.id.tv_DiveSiteListView);
            if (title_text!= null) {
                title_text.setText(diveSite);
            }

            /**
             * Set Date of dive in smaller textView font
             */

            TextView date_text = (TextView) v.findViewById(R.id.tv_diveDateList);
            if (date_text!= null) {
                date_text.setText(date);
            }       

            /**
             * Display the dive number in larger red font
             */

            TextView dive_no = (TextView) v.findViewById(R.id.tv_diveNumberListView);
            if (diveNumber!= null  ) {
                dive_no.setText(diveNumber+"/"+noOfRows);//+1 as rows start at zero
            }


            /*
             * Display the rating of the dive
             */
            RatingBar  bar = (RatingBar) v.findViewById(R.id.ratingBarListView);
            bar.setNumStars(5);

            bar.setRating( Float.parseFloat(rating));
            /**
             * Display the image only of image not null
             * First get image from Strimg pathname as a file, then convert to Bitmap and resize
             * 
             */

            ImageView displayImage = (ImageView) v.findViewById(R.id.iv_list_image);

 //set image here once taken form external string path, and resized bitmap conversion

            imagePathFile = new File(diveImagePath); 
            try {
                FileInputStream streamIn = new FileInputStream(imagePathFile);
                Bitmap bitmap = BitmapFactory.decodeStream(streamIn);//retrun null if can't convert

                if(bitmap!=null){
                    displayImage.setBackground(null);
                    resizedImage = reSizeImage(bitmap);

                    displayImage.setImageBitmap(resizedImage);


                }else{

                    displayImage.setBackgroundResource(R.drawable.logdive3);
                }

            } 

            catch (FileNotFoundException e) {
                e.printStackTrace();


            }//end try catch

            }//end newView 

And in a List-view class the cursor is obtained in a do-in-background method of a Async Class and the adapter is set in the on-post-execute:

@Override
        protected Cursor doInBackground(Void... params) {
            // get the cursor from database

                        ViewListOfDives.data = new diveDataBase(ViewListOfDives.this);
                        ViewListOfDives.data.open();
                        // get cursor object holding all data, use a asynch inner class to load 
                        cursor = data.getCursorData();


                        //ViewListOfDives.data.close();
            return cursor;
        }

//set the adapter to list view

@Override
        protected void onPostExecute(Cursor cursor) {

                        //check if data available
                        if(cursor!=null && cursor.getCount()>0){
                        // get customised array adoater list
                        adapter = new ItemAdapter(ViewListOfDives.this, cursor);
                        }else{

                                //display o dives in data base message and finish this activity
                                displayDialog();

                        }
                        ViewListOfDives.this.setListAdapter(adapter);
                        ViewListOfDives.data.close();
            super.onPostExecute(cursor);
            // dispose dialog
                        if(pd.isShowing()){
                                    pd.dismiss();
                        }
        }

Have been researching allot on line an can't find much on performance optimizing cursor adapters so Any input would be much appreciated!!

Edit: including method I use to resize the images:

public Bitmap reSizeImage(Bitmap bitmapImage) {
            // resize bitmap image passed and rerun new one
            Bitmap resizedImage = null;
            float factorH = h / (float) bitmapImage.getHeight();
            float factorW = w / (float) bitmapImage.getWidth();
            float factorToUse = (factorH> factorW)? factorW : factorH;
            try {
                resizedImage = Bitmap.createScaledBitmap(bitmapImage,
                        (int) (bitmapImage.getWidth() * factorToUse),
                        (int) (bitmapImage.getHeight() * factorToUse), false);
            } catch (IllegalArgumentException e) {
                Log.d(TAG, "Problem resizing Image @Line 510+");
                e.printStackTrace();
            }
            Log.d(TAG,
                    "in resixed, value of resized image: "
                            + resizedImage.toString());
            return resizedImage;
        }// end reSize

Where h and w :

 // for image resizing
        static int w = 250;
        static int h = 280;

EDIT: Have wriiten a asynch class to handle conversion of base 64 to to bitmap, then in post execute image view is set to the bitmap. This inner class is called form the bindView method of cursoradpter class. Issue is now only the last view is populated wit an image!!

 //asynch class to load nase 64 image and convert to bitmap and set imageview 

            private class getBitmapImage extends AsyncTask<String, Void, Bitmap>{

                @Override
                protected Bitmap doInBackground(String... imagePath) {

                    // get image path and decode to bitmap
                    String diveImagePath = imagePath[0];
                    //String diveImagePath = c.getString(c.getColumnIndex(diveDataBase.KEY_DIVEPICTURE));
                     File imagePathFile = new File(diveImagePath); 
                     try {
                            FileInputStream streamIn = new FileInputStream(imagePathFile);
                             bitmap = BitmapFactory.decodeStream(streamIn);//retrun null if cant convert
                }catch (FileNotFoundException e) {

                    e.printStackTrace();
                    //Toast.makeText(context, "No Image Found!! Usimng default", Toast.LENGTH_LONG).show();

                }//end try catch

                    return bitmap;

                }//end do in background


                @Override
                protected void onPostExecute(Bitmap bitmap) {

                    if(bitmap!=null){
                        displayImage.setBackground(null);
                        resizedImage = reSizeImage(bitmap);

                        displayImage.setImageBitmap(resizedImage);


                    }else{
                        //Toast.makeText(context, "No Image Found!! Usimng default", Toast.LENGTH_LONG).show();
                        displayImage.setBackgroundResource(R.drawable.logdive3);
                    }

                }//end onPOstExecute
            }//end getBitmap asynch

This inner class is called in the bindView method of CursorAdpter class:

//get bitmap image from base 64 string, and set to image view using asynch class thread
             new getBitmapImage().execute(diveImagePath);
Was it helpful?

Solution

  1. put the text on screen first. Maybe default drawables to show things are loading.

  2. Loading 20 bitmaps from file is going to a take a few seconds at least. You should load these asynchronously (from the thread populating your listview). Only your UI thread can set the imageview, but you can load the bitmaps in a worker thread, which is most the work.

  3. You should also be loading the bitmaps using sampling so you aren't loading them at a higher resolution than you can display, otherwise you're reading more data than you need to.

See android tutorial on loading large bitmaps efficiently.

OTHER TIPS

Use cursor adapter with loader.It helped me to load fast when I have database with more than 8000 records. I hope it will help you.
Reference:http://developer.android.com/guide/components/loaders.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top