0

i have a big problem that is driving me crazy. I have a ListView with all apps installed but the scroll is very slow, so i want to improve it. I tried to put a Thread but it doesn't solv the problem. This is the code

ApplicationAdapter

public class ApplicationAdapter extends ArrayAdapter<ApplicationInfo> {
    private List<ApplicationInfo> appsList = null;
    private Context context;
    private PackageManager packageManager;
    Holder holder;

    public ApplicationAdapter(Context context, int textViewResourceId,
            List<ApplicationInfo> appsList) {
        super(context, textViewResourceId, appsList);
        this.context = context;
        this.appsList = appsList;
        packageManager = context.getPackageManager();
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent){
        View view = convertView;
        final Holder holder;
        if (null == view) {
            LayoutInflater layoutInflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = layoutInflater.inflate(R.layout.snippet_list_row, null);
            holder = new Holder();
            holder.appName = (TextView) view.findViewById(R.id.app_name);
            holder.packageName = (TextView) view.findViewById(R.id.app_paackage);
            holder.iconview = (ImageView) view.findViewById(R.id.app_icon);


            view.setTag(holder);
        }
        else
        {
            holder = (Holder)view.getTag();
        }




        final ApplicationInfo data = appsList.get(position);
        if (null != data) {

            holder.appName.setText(data.loadLabel(packageManager));
            holder.packageName.setText(data.packageName);
            holder.iconview.setImageDrawable(data.loadIcon(packageManager));



        }







        return view;
    }

    static class Holder
    {
        TextView appName, packageName;
        ImageView iconview;
    }



}

Activity

public class Activity_Eclair extends ListActivity {

    public PackageManager packageManager = null;
    public List<ApplicationInfo> applist = null;
    public ApplicationAdapter listadaptor = null;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_eclair);

        ListView lv = getListView();
        lv.setFastScrollEnabled(true);
        lv.setScrollingCacheEnabled(false);
        registerForContextMenu(lv);

        packageManager = getPackageManager();


        new LoadApplications().execute();


    Button bottone1 = (Button)findViewById(R.id.button1);
    bottone1.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {

            new LoadApplications().execute();


        }
    });};



    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);

        ApplicationInfo app = applist.get(position);

        Uri packageUri = Uri.parse("package:"+app.packageName);
        Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageUri);
        startActivity(uninstallIntent);
    }


    public List<ApplicationInfo> checkForLaunchIntent(List<ApplicationInfo> list) {
        ArrayList<ApplicationInfo> applist = new ArrayList<ApplicationInfo>();
        for (ApplicationInfo info : list) {
            try {
                if (null != packageManager.getLaunchIntentForPackage(info.packageName)) {
                    applist.add(info);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return applist;
    }


    private class LoadApplications extends AsyncTask<Void, Void, Void> {        

        public ProgressDialog progress = null;

        @Override
        protected Void doInBackground(Void... params) {
            applist = checkForLaunchIntent(packageManager.getInstalledApplications(PackageManager.GET_META_DATA));
            listadaptor = new ApplicationAdapter(Activity_Eclair.this,
                    R.layout.snippet_list_row, applist);

            return null;
        }

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

        protected void onDestroy() {
            if(progress!=null)
                if(progress.isShowing()){
                progress.dismiss();
                }

        }

        @Override
        protected void onPostExecute(Void result) {
            setListAdapter(listadaptor);
            progress.dismiss();
            super.onPostExecute(result);
        }

        @Override
        protected void onPreExecute() {
            progress = ProgressDialog.show(Activity_Eclair.this, null,
                    "Loading...");
            super.onPreExecute();
        }

        @Override
        protected void onProgressUpdate(Void... values) {
            super.onProgressUpdate(values);
        }
    }

    private final static int UPDATE_MENU_OPTION = 1;
    private final static int DELETE_MENU_OPTION = 2;
    private final static int TRUNCATE_MENU_OPTION = 3;
    private final static int DELETE = 4;

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {

    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
            AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
            final long examId = info.id;
            ApplicationInfo app = applist.get((int) info.id);

            switch (item.getItemId()) {

            case UPDATE_MENU_OPTION:
                try {
                    Intent intent = packageManager
                            .getLaunchIntentForPackage(app.packageName);

                    if (null != intent) {
                        startActivity(intent);
                    }
                } catch (ActivityNotFoundException e) {
                    Toast.makeText(Activity_Eclair.this, e.getMessage(),
                            Toast.LENGTH_LONG).show();
                } catch (Exception e) {
                    Toast.makeText(Activity_Eclair.this, e.getMessage(),
                            Toast.LENGTH_LONG).show();
                }
                return true;

            case DELETE_MENU_OPTION:
                Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id="+app.packageName));
                startActivity(browserIntent);
                return true;

            case TRUNCATE_MENU_OPTION:
                try {
                    //Open the specific App Info page:
                    Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                    intent.setData(Uri.parse("package:" + app.packageName));
                    startActivity(intent);

                } catch ( ActivityNotFoundException e ) {
                    //e.printStackTrace();

                    //Open the generic Apps page:
                    Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS);
                    startActivity(intent);

                }
                return true;

            case DELETE:
            {
                 Uri packageUri = Uri.parse("package:"+app.packageName);
                 Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageUri);
                 startActivity(uninstallIntent);

            }
            return true;

            default:
                    return super.onContextItemSelected(item);
            }
    }

I state that I have already tried numerous snippets present on StackOverflow and on the Web but do not work. }

  • http://stackoverflow.com/questions/16789676/caching-images-and-displaying check this using universal imageloader if it helps uses lazy loading – Raghunandan Nov 03 '13 at 10:03

2 Answers2

1

1 - edit Manifest file add to activity

android:hardwareAccelerated="true"

2- Cache and draw icons to ImageView oneByOne we need 4 classes witch is :

Utils.class

public class Utils {
    public static void CopyStream(InputStream is, OutputStream os)
    {
        final int buffer_size=1024;
        try
        {
            byte[] bytes=new byte[buffer_size];
            for(;;)
            {
              int count=is.read(bytes, 0, buffer_size);
              if(count==-1)
                  break;
              os.write(bytes, 0, count);
            }
        }
        catch(Exception ex){}
    }
}

MemoryCache.class

public class MemoryCache {

    private static final String TAG = "MemoryCache";
    private Map<String, Bitmap> cache=Collections.synchronizedMap(
            new LinkedHashMap<String, Bitmap>(10,1.5f,true));//Last argument true for LRU ordering
    private long size=0;//current allocated size
    private long limit=1000000;//max memory in bytes

    public MemoryCache(){
        //use 25% of available heap size
        setLimit(Runtime.getRuntime().maxMemory()/4);
    }

    public void setLimit(long new_limit){
        limit=new_limit;
        Log.i(TAG, "MemoryCache will use up to "+limit/1024./1024.+"MB");
    }

    public Bitmap get(String id){
        try{
            if(!cache.containsKey(id))
                return null;
            return cache.get(id);
        }catch(NullPointerException ex){
            ex.printStackTrace();
            return null;
        }
    }

    public void put(String id, Bitmap bitmap){
        try{
            if(cache.containsKey(id))
                size-=getSizeInBytes(cache.get(id));
            cache.put(id, bitmap);
            size+=getSizeInBytes(bitmap);
            checkSize();
        }catch(Throwable th){
            th.printStackTrace();
        }
    }

    private void checkSize() {
        Log.i(TAG, "cache size="+size+" length="+cache.size());
        if(size>limit){
            Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator(); 
            while(iter.hasNext()){
                Entry<String, Bitmap> entry=iter.next();
                size-=getSizeInBytes(entry.getValue());
                iter.remove();
                if(size<=limit)
                    break;
            }
            Log.i(TAG, "Clean cache. New size "+cache.size());
        }
    }

    public void clear() {
        try{
            cache.clear();
            size=0;
        }catch(NullPointerException ex){
            ex.printStackTrace();
        }
    }

    long getSizeInBytes(Bitmap bitmap) {
        if(bitmap==null)
            return 0;
        return bitmap.getRowBytes() * bitmap.getHeight();
    }
}

FileCache.class

public class FileCache {

    private File cacheDir;
    String cacheFile  = "cachefolder"; 

    public FileCache(Context context, String subfolder ){
        //Find the dir to save cached images
        if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
            cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),cacheFile+"/"+subfolder);
        else
            cacheDir=context.getCacheDir();
        if(!cacheDir.exists())
            cacheDir.mkdirs();
    }

    public FileCache(Context context){
        //Find the dir to save cached images
        if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
            cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),cacheFile);
        else
            cacheDir=context.getCacheDir();
        if(!cacheDir.exists())
            cacheDir.mkdirs();
    }
    public File getFile(String url){
        //I identify images by hashcode. Not a perfect solution, good for the demo.
        String filename = String.valueOf(url.hashCode());
        //Another possible solution (thanks to grantland)
        //String filename = URLEncoder.encode(url);
        File f = new File(cacheDir, filename);
        return f;
    }
    public void clear(){
        File[] files=cacheDir.listFiles();
        if(files==null)
            return;
        for(File f:files)
            f.delete();
    }

}

ImageLoader.class :

public class ImageLoader {

    public static int REQUIRED_SIZE=100;
    public MemoryCache memoryCache = new MemoryCache();
    FileCache fileCache;
    private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
    ExecutorService executorService; 
    int stub_id = R.drawable.drawing_image; 


    public ImageLoader(Context context){
        fileCache=new FileCache(context);
        executorService=Executors.newFixedThreadPool(5);
    }

    public void DisplayImage(String url, ImageView imageView)
    {

        imageViews.put( imageView, url );

        Bitmap bitmap = memoryCache.get(url);

        if( bitmap != null )
        {
            imageView.setImageBitmap(bitmap);
        }
        else
        {
            queuePhoto(url, imageView);
            imageView.setImageResource(stub_id);
        }
    }

    /*   private Bitmap bitmap_to_circel( Bitmap bitmap)
    {

        return bitmap;
        Bitmap circleBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);

        BitmapShader shader = new BitmapShader (bitmap,  TileMode.CLAMP, TileMode.CLAMP);
        Paint paint = new Paint();
              paint.setShader(shader); 
              paint.setAntiAlias(true);
              paint.setFilterBitmap(true);
              paint.setDither(true);      

       Canvas c = new Canvas(circleBitmap);
       c.drawCircle(bitmap.getWidth()/2, bitmap.getHeight()/2, bitmap.getWidth()/2, paint);

       return circleBitmap;
    }*/

    private void queuePhoto(String url, ImageView imageView)
    {
        PhotoToLoad p = new PhotoToLoad(url, imageView);
        executorService.submit(new PhotosLoader(p));
    }

    private Bitmap getBitmap(String url) 
    {
        File f=fileCache.getFile(url);

        //from SD cache
        Bitmap b = decodeFile(f);
        if(b!=null)
            return b;

        //from web
        try {
            Bitmap bitmap=null;
            URL imageUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
            conn.setConnectTimeout(30000);
            conn.setReadTimeout(30000);
            conn.setInstanceFollowRedirects(true);
            InputStream is=conn.getInputStream();
            OutputStream os = new FileOutputStream(f);
            Utils.CopyStream(is, os);
            os.close();
            bitmap = decodeFile(f);


            return bitmap;  

        } catch (Throwable ex){
           ex.printStackTrace();
           if(ex instanceof OutOfMemoryError)
               memoryCache.clear();
           return null;
        }
    }

    //decodes image and scales it to reduce memory consumption
    private Bitmap decodeFile(File f){
        try {
            //decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(new FileInputStream(f),null,o);

            //Find the correct scale value. It should be the power of 2.
            int width_tmp=o.outWidth, height_tmp=o.outHeight;
            int scale=1;
            while(true){
                if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
                    break;
                width_tmp/=2;
                height_tmp/=2;
                scale*=2;
            }

            //decode with inSampleSize
            BitmapFactory.Options o2 = new BitmapFactory.Options();
            o2.inSampleSize=scale;
            return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
        } catch (FileNotFoundException e) {}
        return null;
    }

    //Task for the queue
    private class PhotoToLoad
    {
        public String url;
        public ImageView imageView;
        public PhotoToLoad(String u, ImageView i){
            url=u; 
            imageView=i;
        }
    }

    class PhotosLoader implements Runnable {
        PhotoToLoad photoToLoad;
        PhotosLoader(PhotoToLoad photoToLoad){
            this.photoToLoad=photoToLoad;
        }

        @Override
        public void run() {
            if(imageViewReused(photoToLoad))
                return;
            Bitmap bmp=getBitmap(photoToLoad.url);

            memoryCache.put(photoToLoad.url, bmp);

            if(imageViewReused(photoToLoad))
                return;
            BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad);
            Activity a=(Activity)photoToLoad.imageView.getContext();
            a.runOnUiThread(bd);
        }
    }

    boolean imageViewReused(PhotoToLoad photoToLoad){
        String tag=imageViews.get(photoToLoad.imageView);
        if(tag==null || !tag.equals(photoToLoad.url))
            return true;
        return false;
    }

    //Used to display bitmap in the UI thread
    class BitmapDisplayer implements Runnable
    {
        Bitmap bitmap;
        PhotoToLoad photoToLoad;
        public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;}
        public void run()
        {
            if(imageViewReused(photoToLoad))
                return;
            if(bitmap!=null)
                photoToLoad.imageView.setImageBitmap(bitmap);
            else
                photoToLoad.imageView.setImageResource(stub_id);
        }
    }

    public void clearCache() {
        memoryCache.clear();
        fileCache.clear();
    }

}

3 - Add ImageLoader to your ApplicationAdapter and Start display images

public class ApplicationAdapter extends ArrayAdapter<ApplicationInfo> {
    private List<ApplicationInfo> appsList = null;
    private Context context;
    private PackageManager packageManager;
    Holder holder;
//added imageloader here <<------------------
    ImageLoader imgLoader; 

    public ApplicationAdapter(Context context, int textViewResourceId,
            List<ApplicationInfo> appsList) {
        super(context, textViewResourceId, appsList);
        this.context = context;
        this.appsList = appsList;
        packageManager = context.getPackageManager();
//Register image loader class <<---------------------
imgLoader      = new ImageLoader(context);
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent){
        View view = convertView;
        final Holder holder;
        if (null == view) {
            LayoutInflater layoutInflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = layoutInflater.inflate(R.layout.snippet_list_row, null);
            holder = new Holder();
            holder.appName = (TextView) view.findViewById(R.id.app_name);
            holder.packageName = (TextView) view.findViewById(R.id.app_paackage);
            holder.iconview = (ImageView) view.findViewById(R.id.app_icon);


            view.setTag(holder);
        }
        else
        {
            holder = (Holder)view.getTag();
        }




        final ApplicationInfo data = appsList.get(position);
        if (null != data) {

            holder.appName.setText(data.loadLabel(packageManager));
            holder.packageName.setText(data.packageName);

//now load icon provide Url and ImageView only and keep the rest to the class
//provide fill link url to the icon the class will download it , cache it , display it
//next time when scroll again to this position the icon will be displayed from cache file 
imgLoader.DisplayImage(data.icon_link_url_with_http, holder.iconview);




        }







        return view;
    }

    static class Holder
    {
        TextView appName, packageName;
        ImageView iconview;
    }



}

now your list view will scroll quickly even if its has 1k ImageView

Noob
  • 2,857
  • 6
  • 33
  • 47
0

holder.iconview.setImageDrawable(data.loadIcon(packageManager)); You do that everytime you set an image, which is very very slow, hitting the disk and loading the image in full scale. Some apps have very big launcher icons, this can kill your ram quickly. Load all images into ram or the cache folder before creating the listview and it will run a lot quicker.

meredrica
  • 2,563
  • 1
  • 21
  • 24