アイデアはアイテムをクリックした後、ProgressBarがタスクが完了すると徐々に塗りつぶされるアイテムのリストを持つことです。たとえば、ファイルの一覧をそれぞれのダウンロードボタンで表示します。ダウンロードボタンをクリックすると、ファイルがバックグラウンドでダウンロードされ、ファイルがどれくらい近くに完了するかを示すプログレスバーが表示されます。ListView/OnClickにProgressBarを追加すると、一度だけ呼び出される
これを達成するために、アダプタでnotifyDataSetChangedを呼び出すことがあるAsyncTaskを作成して、再描画します。 AsyncTaskが完了するまで、このボタンがクリックされた後で動作しますが、ListViewの他のボタンをクリックすることはできません。誰かが私が間違っていることを教えてもらえますか?
アイスクリームサンドイッチのエミュレータ(x86)で実行しています。
:私は、リストビューのためDownloadItemのリストを適応させるArrayAdapterを有する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
}
:
Iは、ダウンロードの進行状況(以下のコードを簡潔にするために簡略化されている)を表すためにDownloadItemを有します
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;
}
}
これまでのところ、これはうまくいきました。これはリストを適切にレンダリングします。私もちょうど実行などexecuteOnExecutorでこれを試してみましたが、運とき
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)
}
}
:私の活動では、私がonClickListenerを持っています。ダウンロードタスクは:
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();
}
}
これはほとんど動作します。これを行うと、ボタンを1つクリックした後、ProgressBarが正常に更新されますが、AsyncTaskが返るまで、ListViewの他のボタンをクリックすることはできません。つまり、onDownloadButtonClickは呼び出されません。 onProgressUpdate関数からmAdapter.notifyDataSetChanged()呼び出しを削除すると、複数のタスクが同時に更新されますが、もちろんリストは無効化されていないため、スクロールして変更を確認する必要があります。
私は間違っていますが、どうすればこの問題を解決できますか?
編集:私はこれをもう少し試してみました。notifyDataSetChangedを呼び出す頻度は、onClickが呼び出されているのか失われているのかに影響しているようです。上記のコードでは、賢明にクリックすることで、時折2番目のダウンロードバーを起動することができます。私がThread.Sleepをもっと大きくすると、2000年のように、当初期待したとおりに動作します。
新しい質問 - どのようにしてonClickをブロックしないでProgressBarsをスムーズに更新するにはどうすればいいですか?
EDIT#2:私は私のGitHubのアカウントにこの問題でのサンプルプロジェクトをプッシュしている:あなたは、次のようにアダプタ自体でアイテムをダウンロードするには、クリックリスナーを設定https://github.com/mdkess/ProgressBarListView
をあなたがリストビューを使用しているようですか?もしそうなら、時間があれば、これを見る価値があると思う:[Google I/O 2010 - リストビュー](http://www.youtube.com/watch?v=wDBM6wVEO70)。あなたは 'Thread.sleep(800)'(例えば)を使うことができます。 '10'は必要ありません。 –
クリックリスナーはどこで設定しますか?あなたはダミーコードでこれを見逃します。 – reTs
@reTS:ボタンのアンドロイド:onClickパラメータを使用してXMLに設定しました。ハンドラは間違いなく呼び出されています。私の編集を質問にも見てください。 – mindvirus