2013-11-03 99 views
0

我有一個讓我發瘋的大問題。我有一個安裝了所有應用程序的ListView,但滾動速度非常慢,所以我想改進它。我試圖把一個線程,但它不解決問題。這是代碼ListView and Images:我要瘋了

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; 
    } 



} 

活動

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); 
      } 
    } 

我聲明,我已經嘗試目前在計算器上,並在網絡上無數的片段,但不起作用。 }

+0

http://stackoverflow.com/questions/16789676/caching-imag es-and-displays如果它有助於使用延遲加載,請使用通用圖像加載器進行檢查 – Raghunandan

回答

0

holder.iconview.setImageDrawable(data.loadIcon(packageManager)); 每當你設置一個非常非常慢的圖像時,你都會這樣做,點擊磁盤並全面加載圖像。有些應用程序有非常大的啓動器圖標,這可以很快地殺死你的公羊。在創建列表視圖之前將所有圖像加載到內存或緩存文件夾中,並且運行速度會更快。

1

1 - 編輯清單文件添加到活動

android:hardwareAccelerated="true" 

2-緩存並繪製圖標的ImageView oneByOne我們需要4類女巫:

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 - 添加ImageLoader的你ApplicationAdapter並開始顯示圖像

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; 
    } 



} 

現在你的列表視圖將快速滾動即使它有1k ImageView