Очень медленный ListView с использованием CursorAdpter

Я заполняю ListView настраиваемым адаптером курсора, который получает набор результатов курсора из базы данных. Отображение всего 20 просмотров может занять до 10–12 секунд!

Вот класс CursorAdater, в котором курсор предоставляет строки и представление изображения base 64 для серии текстовых представлений и представления изображений для каждый вид:

    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 

А в классе List-view курсор получается в фоновом методе Async Class, а адаптер устанавливается в 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();
                        }
        }

Изучили выделение в сети и не смогли найти много информации об оптимизирующих адаптерах курсора, поэтому любой ввод будет очень признателен!

Изменить: включая метод, который я использую для изменения размера изображений:

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

Где h и w:

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

РЕДАКТИРОВАТЬ: напишите асинхронный класс для обработки преобразования базы 64 в растровое изображение, затем в представлении изображения после выполнения установлено растровое изображение. Этот внутренний класс вызывается из метода bindView класса cursoradpter. Проблема в том, что изображение заполняется только последним представлением !!

 //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

Этот внутренний класс вызывается в методе bindView класса CursorAdpter:

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

person dancingbush    schedule 22.02.2014    source источник
comment
Вы загружаете растровое изображение в поток пользовательского интерфейса, это снижает производительность вашего списка ... загрузите его в другом потоке.   -  person kalyan pvs    schedule 22.02.2014


Ответы (2)


  1. сначала поместите текст на экран. Возможно, загружаются чертежи по умолчанию, чтобы показать вещи.

  2. Загрузка 20 растровых изображений из файла займет как минимум несколько секунд. Вы должны загружать их асинхронно (из потока, заполняющего ваш список). Только ваш поток пользовательского интерфейса может установить изображение, но вы можете загружать растровые изображения в рабочий поток, что является большей частью работы.

  3. Вы также должны загружать растровые изображения с использованием выборки, чтобы вы не загружали их с более высоким разрешением, чем вы можете отобразить, иначе вы читаете больше данных, чем вам нужно.

См. руководство Android по эффективной загрузке больших растровых изображений.

person NameSpace    schedule 22.02.2014
comment
Что ж, не могу комментировать это, так как я не вижу кода, но я вижу ваше изменение, включающее вашу функцию изменения размера для битампер. Вы должны выполнять выборку при чтении файла, а не после его загрузки. Вы могли пропустить все эти байты при начальном чтении. - person NameSpace; 22.02.2014
comment
Привет, я написал внутренний класс синхронизации для обработки преобразования base 64 в Bitmap, который передается в onPOstExceute, где он установлен на imagvview. Теперь это примерно в 5 раз быстрее, НО единственный вид списка для обновления изображений - последний в списке !!!! Больной почтовый индекс, пожалуйста, проверьте? - person dancingbush; 22.02.2014
comment
не может видеть весь код, но, вероятно, все асинхронные задачи относятся к одному и тому же глобальному, и, поскольку загрузчик изображений занимает некоторое время, все они загружаются в последнее загруженное представление. Попробуйте передать ссылку на iv, которая не является глобальной, а затем установить ее в post execute. - person NameSpace; 22.02.2014
comment
Я думаю, что проблема в том, что мне нужно объявить и запустить представление изображения в асинхронном классе (предыдущее сделано в методе просмотра привязки), displayImage = (ImageView) v.findViewById (R.id.iv_list_image); v = Просмотр передан в bindView, не удается получить v (Просмотр) в асинхронном классе! Так близко, но так далеко .. - person dancingbush; 22.02.2014
comment
передать массив объектов ... один из объектов - это ваш iv, другой может быть вашим строковым путем. - person NameSpace; 22.02.2014
comment
Пытался передать View v в конструктор синхронизации, но он не распознает parent: public getBitmapImage (View v) {// TODO Заглушка автоматически сгенерированного конструктора, принимает ViewGroup в качестве аргумента ViewGroup parent; v = mLayoutInflater.inflate (R.layout.database_list_row2, родительский, ложь); - person dancingbush; 22.02.2014
comment
Извините, только что увидел сообщение о массиве объектов, как бы вы это сделали? Я не очень хорошо разбираюсь в асинхронных классах ... - person dancingbush; 22.02.2014
comment
давайте продолжим обсуждение в чате - person NameSpace; 22.02.2014
comment
Эй, да, наконец, получил представление, передав представление конструктору, так что спасибо. У меня действительно возникла ошибка нехватки памяти, и вы упомянули: «Вы должны выполнять выборку при чтении файла, а не после его загрузки». «Так что именно ты имеешь в виду? Спасибо - person dancingbush; 22.02.2014
comment
Понял, использовал объект параметров BitMapOptions с методами options.inJustDecodeBounds и options.inSampleSize, чтобы значительно уменьшить выделение памяти для больших изображений из базы данных до их загрузки в память ....... спасибо еще раз - person dancingbush; 23.02.2014

Используйте адаптер курсора с загрузчиком, это помогло мне быстро загрузиться, когда у меня база данных с более чем 8000 записей. Надеюсь, это поможет вам.
Ссылка: http://developer.android.com/guide/components/loaders.html

person Moses    schedule 22.02.2014