使用CursorAdpter的ListView非常慢

时间:2014-02-22 11:02:39

标签: android performance listview simplecursoradapter

我使用自定义游标适配器填充ListView,该适配器从数据库接收游标结果集。显示20个视图最多可能需要10-12秒!

这是 CursorAdater 类,其中光标将字符串和基本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 

列表视图类中,光标是在异步类的背景化方法中获取的,并且适配器在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;

编辑:使用asynch类来处理base 64到bitmap的转换,然后在post执行图像视图中设置为位图。这个内部类被称为cursoradpter类的bindView方法。问题是现在只有最后一个视图用图像填充!!

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

这个内部类在CursorAdpter类的bindView方法中调用:

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

2 个答案:

答案 0 :(得分:2)

  1. 首先将文字放在屏幕上。也许是默认的drawables来显示正在加载的内容。

  2. 从文件加载20位图至少需要几秒钟。您应该异步加载这些(从填充列表视图的线程)。只有您的UI线程可以设置imageview,但您可以在工作线程中加载位图,这是最重要的工作。

  3. 您还应该使用采样加载位图,这样您就不会以高于可以显示的分辨率加载它们,否则您将读取的数据超出您的需要。

  4. 有效加载大型位图请参阅android tutorial

答案 1 :(得分:1)

将游标适配器与loader一起使用。当我拥有超过8000条记录的数据库时,它帮助我快速加载。我希望它会对你有所帮助 参考:http://developer.android.com/guide/components/loaders.html