Good day, I have a problem here. I use an asynchronous task to display images from external or internal storage. Now it works, but the problem is that it is very slow and slightly jerky in scrolling. I have no idea why? please any decision or 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{ 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(); } 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(); } 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(); } } } 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; } } 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); } }
I think I'm in favor of letting doBackground () run for a while before I call publishProgress (). just like the gallery app in android. Any ideas on why this might be slow or how to solve this problem would be much appreciated since I was already stuck on how to improve performance for a while.