填充图像的GridView时慢滚动使用的AsyncTask [英] Slow scrolling when populating gridview of images with AsyncTask

查看:259
本文介绍了填充图像的GridView时慢滚动使用的AsyncTask的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

美好的一天,我在这里有一点小问题。我使用和异步任务显示来自外部或内部的图像storage.Now它的工作原理,但问题是,这是非常缓慢的,并在滚动略显生涩。我不知道为什么?请任何解决方案或一个想法如何做到这一点。

good day, i am having a bit of a problem here. i am using and async task to display images from external or internal storage.Now it works but the problem is, it is very slow and slightly jerky in scrolling. I have no idea why? please any solution or an idea how to do this.

import java.io.IOException;
import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Debug;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;

public class Wallpaper extends Activity implements OnItemClickListener{

/*Instance variables*/
 private GridView grid;
 private ImageAdapter imageAdapter;
 private Display display;
 Cursor cursor;
 boolean inInternalStorage = false;



 public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        setContentView(R.layout.wallpaper_images);

        display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

        setupViews();
        setProgressBarIndeterminateVisibility(true); 
        loadImages();
    }

 @Override
 protected void onStop(){
     super.onStop();
 }

 /*methods called from AsyncTask as appropriate when its querying and processing the images from the MediaStore*/

 private void loadImages() {
 final Object data = getLastNonConfigurationInstance();
 if(data == null){
     new LoadImagesFromSDCard().execute();
 }else {
     final LoadedImage[] photos = (LoadedImage[])data;
     if(photos.length == 0){

        new LoadImagesFromSDCard().execute();
     }
     for(LoadedImage photo:photos){
         addImage(photo);
    }
 }

}

private void addImage(LoadedImage... value) {

    for(LoadedImage photo: value){
        imageAdapter.addPhotos(photo);  
        imageAdapter.notifyDataSetChanged();
    }

}

private void setupViews() {

        grid = (GridView)findViewById(R.id.gridview);
        grid.setNumColumns(display.getWidth()/95);
        grid.setClipToPadding(false);
        imageAdapter = new ImageAdapter(getApplicationContext());
        grid.setAdapter(imageAdapter);
        grid.setOnItemClickListener(this);
}

protected void onDestroy() {
        super.onDestroy();
        final GridView gridview = grid;
        final int count = grid.getChildCount();
        ImageView v = null;
        for (int i = 0; i < count; i++) {
            v = (ImageView) grid.getChildAt(i);
            ((BitmapDrawable) v.getDrawable()).setCallback(null); 
        }

        unbindDrawables(findViewById(R.id.gridview));
        System.gc();
    }

/*public Object onRetainNonConfigurationInstance(){
    final GridView gridview = grid;
    final int count = grid.getChildCount();
    final LoadedImage[] list = new LoadedImage[count];

    for(int i = 0; i < count; i++){
        final ImageView v = (ImageView)grid.getChildAt(i);
        list[i] = new LoadedImage(((BitmapDrawable) v.getDrawable()).getBitmap());
    }
    return list;
}*/


/*utility method called that prevents screen from crashing when screen orientation changes*/
private void unbindDrawables(View view){
    if(view.getBackground() != null){
        view.getBackground().setCallback(null);
    }
    if(view instanceof ViewGroup){
        for(int i = 0; i < ((ViewGroup) view).getChildCount(); i++){
            unbindDrawables(((ViewGroup)view).getChildAt(i));
        }
        try{
            ((ViewGroup)view).removeAllViews();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

/*AsyncTask thats queries the MediaStore for images and creates thumbnail images from bitmaps*/
class LoadImagesFromSDCard extends AsyncTask<Object, LoadedImage, Object> {

    @Override
    protected Object doInBackground(Object... params) {

        Cursor cursor;
        Bitmap bitmap = null;
        Bitmap newbitmap = null;
        Uri uri = null;

        String [] img = {MediaStore.Images.Media._ID};

        String state = Environment.getExternalStorageState();

        if(Environment.MEDIA_MOUNTED.equals(state)){    

        cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, img, 
          MediaStore.Images.Media.DATA + " like ? " , new String[]{ "%dcim%"}, null);
        } else {
         cursor = getContentResolver().query(MediaStore.Images.Media.INTERNAL_CONTENT_URI, img, null, null, null);
         inInternalStorage = true;
        }

        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID);
        int size = cursor.getCount();

        if(size == 0){
            Toast.makeText(getApplicationContext(), "There are no Images on the sdcard", Toast.LENGTH_SHORT).show();

        }else {

        }

        for(int i = 0; i < size; i++){
            cursor.moveToPosition(i);
            int ImageId = cursor.getInt(column_index);

            if(inInternalStorage == true){
             uri = Uri.withAppendedPath(MediaStore.Images.Media.INTERNAL_CONTENT_URI, "" + ImageId);
         }else {
             uri = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "" + ImageId);
         }


         try {
             BitmapFactory.Options options = new BitmapFactory.Options();
             options.inSampleSize=4;


             bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);

             if(bitmap != null){
                 newbitmap = Bitmap.createScaledBitmap(bitmap, 100, 100, true);
                 bitmap.recycle();
             }
             if(newbitmap != null){
                 publishProgress(new LoadedImage(newbitmap));
             }
         }catch(IOException e){

         }
        }
        cursor.close();
        return null;    
    }

    @Override
    public void onProgressUpdate(LoadedImage... value){
        addImage(value);
    }

       @Override
        protected void onPostExecute(Object result) {
            setProgressBarIndeterminateVisibility(false);
        }
}

private static class LoadedImage {
    Bitmap mBitmap;

    LoadedImage(Bitmap bitmap) {
        mBitmap = bitmap;
    }

    public Bitmap getBitmap() {
        return mBitmap;
    }
}

/*Image Adapter to populate grid view of images*/

public class ImageAdapter extends BaseAdapter {
    private Context mContext;
    private ArrayList<LoadedImage> photos = new ArrayList<LoadedImage>();


    public ImageAdapter(Context context){
        this.mContext = context;
    }

    public void addPhotos(LoadedImage photo){
        photos.add(photo);
    }

    @Override
    public int getCount() {
        return photos.size();
    }


    @Override
    public Object getItem(int position) {
        return position;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        System.gc();
        ImageView image;
        ViewHolder holder;

        if(convertView == null){
            LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.image_list,null);
            holder = new ViewHolder();
            holder.image = (ImageView)convertView.findViewById(R.id.image_list_id);
            convertView.setTag(holder); 
        } else{
            holder = (ViewHolder)convertView.getTag();
        }   
        holder.image.setLayoutParams(new GridView.LayoutParams(100, 100));
        holder.image.setImageBitmap(photos.get(position).getBitmap());
        return convertView;
    }
}

static class ViewHolder {
   ImageView image;
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    Cursor cursor = null;
    int image_column_index = 0;
    String[] proj = {MediaStore.Images.Media.DATA};

    String state = Environment.getExternalStorageState();

  if(Environment.MEDIA_MOUNTED.equals(state)){

    cursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,proj, MediaStore.Images.Media.DATA + " like ? ", new String[]{"%dcim%"},null);

  }else{
      cursor = managedQuery(MediaStore.Images.Media.INTERNAL_CONTENT_URI,proj,null, null,null);
  }
    cursor.moveToPosition(position);
    image_column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);


    String info = cursor.getString(image_column_index);
    Intent imageviewer  = new Intent(getApplicationContext(), ViewImage.class);
           imageviewer.putExtra("pic_name", info);
           startActivity(imageviewer);

}

}

我想我是后一种方法让doBackground()一段时间()运行之前,我打电话publishProgress。就像在Android上的应用程序库如何做。
为什么这可能是缓慢的任何想法或如何解决这个问题将大大AP preciated因为我一直停留在现在怎么提高了,而更流畅。

i think what i am after is a way to allow doBackground() to run for a while before i call publishProgress(). just like how the gallery app in android does. Any ideas on why this could be slow or how to solve this problem will be greatly appreciated as i have been stuck on how to improve the perfomance for a while now.

推荐答案

最大的瓶颈会从设备上访问图像(内部或外部)。因此,你想在内存中尽可能多的图像越好(当然,原因之内)。可以以许多方式来实现:

The biggest bottleneck will be accessing the images from the device (internal or external). Therefore, you'll want to have as many images in memory as possible (within reason of course). You can do this in a number of ways:


  • 加载或许18首图像(如你所说显示之前,$ P $的pbuffer)。检查以确保图像的数量不超过您选择的任何数量虽然。

  • 创建一个将存储位图的100x100像素缩略图的Thumbs.db文件类型。这将允许更快的阅读,因为你只需要在一个文件中读取然后提取每个位图。如果用户点击图像,然后从存储请求它。此方法需要更多的工作,但能够真正快速加载缩略图。你可能不得不设计自己的简单的文件头,如:

  • Load perhaps 18 images first (as you said, prebuffer before displaying). Check to make sure the number of images doesn't exceed whatever number you choose though.
  • Create a 'thumbs.db' type file which will store 100x100 px thumbnails of the bitmaps. This will allow much faster reading since you'd only need to read in one file then extract each bitmap. If the user clicks an image, then request it from the storage. This method requires more work, but will be able to load the thumbnails really fast. You'd probably have to design your own simple file headers, such as:

 <file header (size of file, number of images)>
 <image header (img id, size in bytes)>
 <image bitmap data>
 <image header (img id, size in bytes)>
 <image bitmap data>
 <image header (img id, size in bytes)>
 <image bitmap data>
 ...


这篇关于填充图像的GridView时慢滚动使用的AsyncTask的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆