2012-06-26 24 views
5

Buradaki fikir, bir öğeyi tıkladıktan sonra bir ProgressBar öğesinin görev tamamlandığında yavaşça dolduğu öğelerin bir listesi olmalıdır. Örneğin, her birinin indir düğmesiyle dosyaların bir listesini yapın. İndirme düğmesine tıklandığında, dosya arka planda indirilir ve dosyanın ne kadar yakın olduğunu gösteren bir ilerleme çubuğu doldurulur.ListView/OnClick'e bir ProgressBar ekleme Tek bir saat olarak adlandırılan

Bunu yapmak için, zaman zaman yeniden biçimlendirmek üzere bağdaştırıcıda notifyDataSetChanged öğesini çağıran bir AsyncTask oluşturuyorum. Bu bir düğmeyi tıklatıldıktan sonra, AsyncTask tamamlanana kadar, ListView'deki diğer düğmeleri tıklayamıyorum. Birisi bana neyi yanlış yaptığımı söyler mi?

Bunu Ice Cream Sandwich üzerindeki emülatörde (x86) çalıştırıyorum.

: Sonra ListView DownloadItem listesini uyarlar bir ArrayAdapter sahip

class DownloadItem { 
    public String name;  // Name of the file being downloaded 
    public Integer progress; // How much is downloaded so far 
    public Integer length; // Size of the file 
} 

:

Ben İndirme ilerlemesini (aşağıdaki kod kısalık için basitleştirilmiş) temsil edecek bir DownloadItem var

class DownloadArrayAdapter extends ArrayAdapter<DownloadItem> { 
    List<DownloadItem> mItems; 
    public DownloadArrayAdapter(List<DownloadItem> items) { 
     mItems = items; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     View row = convertView; 
     if(row == null) { 
      // Inflate 
      Log.d(TAG, "Starting XML inflation"); 
      LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      row = inflater.inflate(R.layout.download_list_item, parent, false); 
      Log.d(TAG, "Finished XML inflation"); 
     } 

     DownloadItem item = mItems.get(position); 

     ProgressBar downloadProgressBar = (ProgressBar) row.findViewById(R.id.downloadProgressBar); 
     Button downloadButton = (Button) row.findViewById(R.id.downloadButton); 

     downloadButton.setTag(item); 
     downloadProgressBar.setMax(item.length); 
     downloadProgressBar.setProgress(item.progress); 

     return row; 
    } 
} 

Şimdiye kadar çok iyi - bu, listeyi düzgün bir şekilde işler. Ben de sadece yürütme olarak executeOnExecutor ile bu çalıştı, ama hiç şansım ettik

class DownloadActivity extends Activity { 
    //... 
    public void onDownloadButtonClick(View view) { 
     DownloadItem item = (DownloadInfo)view.getTag(); 
     DownloadArrayAdapter adapter = (DownloadArrayAdapter) view.getAdapter(); 
     new DownloadTask(adapter, item).execute(); 
     //new DownloadTask(adapter, item).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) 
    } 
} 

: Benim Aktivite, ben OnClickListener var. DownloadTask şudur:

class DownloadTask extends AsyncTask<Void, Integer, Void> { 
    ArrayAdapter<?> mAdapter; 
    DownloadItem mItem; 

    public DownloadTask(ArrayAdapter<?> adapter, DownloadItem item) { 
     mItem = item; 
    } 

    //Dummy implementation 
    @Override 
    public Void doInBackground(Void ... params) { 
     for(int i=0; i<mItem.length; ++i) { 
      Thread.sleep(10); publishProgress(i); 
     } 
     return null; 
    } 

    @Override 
    public void onProgressUpdate(Integer ... values) { 
     mItem.progress = values[0]; 
     mAdapter.notifyDataSetChanged(); 
    } 
} 

Bu çalışma - neredeyse. Bunu yaptığımda, bir düğmeyi tıklattıktan sonra, ProgressBar normal olarak güncelleştirir - ancak AsyncTask döndürene kadar ListView'deki diğer düğmeleri tıklayamıyorum. Diğer bir deyişle, onDownloadButtonClick hiçbir zaman aranmaz. MAdapter.notifyDataSetChanged() çağrısını onProgressUpdate işlevinden kaldırırsam, birden çok görev eşzamanlı olarak güncelleştirilir, ancak elbette, liste geçersiz sayılmaz ve bu nedenle değişiklikleri görmek için gezinmem gerekir.

Neyi yanlış yapıyorum ve bunu nasıl düzeltebilirim?

Düzenleme: Bunu biraz daha oynanır ve notifyDataSetChanged çağırarak sıklığı onClick çağrılan ya da sadece kaybolmasını olmadığını etkiler gibi görünüyor. Yukarıdaki kod ile, çılgınca tıklayarak, bazen başlatmak için ikinci bir indirme çubuğu alabilirsiniz. Thread.Sleep'ı 2000 gibi daha büyük bir şeye artırırsam, liste beklediğim gibi çalışır.

Yani yeni soru - denilmekten onClick engellemediğini iken nasıl güncellemek için ProgressBars sorunsuz alabilirim?

2.

DÜZENLEME:

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    View row = convertView; 
    if(row == null) { 
     // Inflate 
     Log.d(TAG, "Starting XML inflation"); 
     LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     row = inflater.inflate(R.layout.download_list_item, parent, false); 
     Log.d(TAG, "Finished XML inflation"); 
    } 

    final DownloadItem item = mItems.get(position); 

    ProgressBar downloadProgressBar = (ProgressBar) row.findViewById(R.id.downloadProgressBar); 
    Button downloadButton = (Button) row.findViewById(R.id.downloadButton); 

    downloadButton.setTag(item); 
    downloadProgressBar.setMax(item.length); 
    downloadProgressBar.setProgress(item.progress); 

    downloadButton.setOnClickListener(new View.OnClickListener() { 

     @Override 
     public void onClick(View v) { 
      new DownloadTask(DownloadArrayAdapter.this, item).execute(); 
     } 
    }); 

    return row; 
} 
+1

liste görünümünü kullanmak görünüyor? Eğer öyleyse, ve zamanınız varsa, bunu izlemeyi düşünüyorum: [Google I/O 2010 - Liste Görünümü] (http://www.youtube.com/watch?v=wDBM6wVEO70). Bir öneri: 'Thread.sleep (800)' kullanabilirsiniz (örneğin), '10' gerekli değildir. –

+1

Tıklama dinleyicisini nerede belirlersiniz? Bunu kukla kodda özlüyorsun. – reTs

+0

@reTS: XML için bu düğmeyi, android: onClick parametresiyle ayarlayın. İşleyici kesinlikle çağrılıyor - bir kere, bir kere. Bununla birlikte benim de sorguma bak. – mindvirus

cevap

5
+0

+1. şerefe !!!! – skygeek

+0

Merhaba .... Kodun bana çok yardımcı oldu ... Ama benim bir sorunum var. Kodunuzu bir etkinlikte çalıştırdığımda, çok iyi çalışıyor. Kodunuzu bir parçada çalıştırdığımda, ilerleme çubuğu nesnesini boş alırım. Neden böyle? –

+0

Bir ya da iki tanesi daha devam ederken bir öğeyi kaldırırsanız (ex için dowload) ne olur? çünkü deniyorum, ama bir öğeyi sildiğimde, progressBars hatası. – Cocorico

1

aşağıdaki gibi adaptör kendisinde öğeyi indirmek için tıklayın dinleyici ayarı denedin mi: Ben GitHub hesabına bu sorunla bir örnek proje itmiş bunu anladım. Bunun yerine notifyDataSetChanged() çağrı

ben DownloadItem nesnedeki her ProgressBar başvuru saklanır. Sonra, eski nesneler convertView olarak geçirildiğinde, ListView'de gezinirken, ProgressBar'ı eski DownloadInfo'dan kaldırdım ve yenisine ekledim.o boş değilse

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    View row = convertView; 
    final DownloadInfo info = getItem(position); 
    // We need to set the convertView's progressBar to null. 

    ViewHolder holder = null; 

    if(null == row) { 
     LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     row = inflater.inflate(R.layout.file_download_row, parent, false); 

     holder = new ViewHolder(); 
     holder.textView = (TextView) row.findViewById(R.id.downloadFileName); 
     holder.progressBar = (ProgressBar) row.findViewById(R.id.downloadProgressBar); 
     holder.button = (Button)row.findViewById(R.id.downloadButton); 
     holder.info = info; 

     row.setTag(holder); 
    } else { 
     holder = (ViewHolder) row.getTag(); 

     holder.info.setProgressBar(null); 
     holder.info = info; 
     holder.info.setProgressBar(holder.progressBar); 
    } 

    holder.textView.setText(info.getFilename()); 
    holder.progressBar.setProgress(info.getProgress()); 
    holder.progressBar.setMax(info.getFileSize()); 
    info.setProgressBar(holder.progressBar); 

    holder.button.setEnabled(info.getDownloadState() == DownloadState.NOT_STARTED); 
    final Button button = holder.button; 
    holder.button.setOnClickListener(new OnClickListener() { 
     @Override 
     public void onClick(View v) { 
     info.setDownloadState(DownloadState.QUEUED); 
     button.setEnabled(false); 
     button.invalidate(); 
     FileDownloadTask task = new FileDownloadTask(info); 
     task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 
     } 
    }); 
    return row; 
    } 

indirme AsyncTask sonra, ProgressBar ilerleme teşkil edeceği ve beklendiği gibi bu çalıştı:

Böylece benim dizi adaptörü için GetView sonra oldu.

Ben GitHub'dan için düzeltilmiş kod yüklenen, buradan görebilirsiniz: https://github.com/mdkess/ProgressBarListView

+0

Ne yazık ki, bu iyi bir şey yapmadı - onClick'e bile ulaşmıyor. Ben çok notifyDataSetChanged çağırma ile ilgisi olduğunu düşünüyorum, bu yüzden şimdiki ilerleme çubuğu için bir referans tutmayı deniyorum. Yine de iyi düşünce. (Bu arada, seni reddetmedim). – mindvirus

+0

Teşekkürler. Kimin beni seçtiğine aldırmayın. Aslında, sorunuzu doğru bir şekilde okumadım. Ben, sen RowView etiket ayarlama .. Ama sen Düğme indirmek için etiket ayarlayın .. Bu yüzden size bu çözüm verdi .. Evet, ilerleme çubuğu referans ilerleme ve ilerleme çubuğu doğrudan çalışması gerekir .. BTW soruyu çok sordu güzel bir şekilde ve ben de senin uygulama gibi :-) harika performans için – Veer

İlgili konular