gpt4 book ai didi

Android ListView 和 Adapter

转载 作者:行者123 更新时间:2023-11-29 22:00:00 26 4
gpt4 key购买 nike

我正在开发一个下载管理器项目,因此,为了显示所有已下载/正在下载的操作,我更喜欢使用 ListView 来显示我的下载列表。假设,我们有多少个下载任务,那么,所有任务的进度条都要更新。对于后台下载任务,我创建了一个新类并将其命名为 HttpDownloader。因此,我将这些进度条传递给此类的对象。当一个新对象添加到我的任务列表时,我调用 HttpDownloader 的构造函数并将新项目进度条传递给它。令我困惑的是 当我将一个新对象添加到任务列表并调用适配器的 notifyDataSetChanged 时,我的列表被刷新,因此所有进度条重置为默认布局值但 HTTPDownloader 线程在后台成功运行。 所以,我的问题是,

<强>1。调用 notifyDataSetChanged 后,对旧 ListView 对象的引用是析构的?

<强>2。如果是,我如何保留旧 View 的引用?

<强>3。如果不是,请解释一下,为什么当后台进程强制传递进度条以更改进度值时,进度条会重置为默认值并且不会更改?

HTTPDownloader 类

class HttpDownloader implements Runnable {
public class HttpDownloader (String url, ProgressBar progressBar)
{
this.M_url = url;
this.M_progressBar = progressBar;
}

@Override
public void run()
{
DefaultHttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(this.M_url);
HttpResponse response;

try{
response = client.execute(get);
InputStream is = response.getEntity().getContent();
long contentLength = response().getEntity().getContentLength();
long downloadedLen = 0;
int readBytes = 0;

byte [] buffer = new byte [1024];


while ((readBytes = in.read(buffer, 0, buffer.length)) != -1) {
downloadedLen += readBytes;

//Some storing to file codes

runOnUiThread(new Runnable() {
@Override
public void run() {
M_progressBar.setProgress((100f * downloadedLen) / contentLength);
}
});
}

is.close();
} catch (ClientProtocolException e) {
Log.e("HttpDownloader", "Error while getting response");
} catch (IOException e) {
Log.e("HttpDownloader", "Error while reading stream");
}
}
}

适配器类

class MyAdapter extends ArrayAdapter<String> {
ArrayList<String> M_list;
public MyAdapter(ArrayList<String> list) {
super(MainActivity.this, R.layout.download_item, list);
this.M_list = list;
}

@Override
public int getCount() {
return this.M_list.size();
}

public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.download_item, parent, false);
ProgressBar bar = (ProgressBar) rowView.findViewById(R.id.progrees);

new Thread (new HttpDownloader(this.M_list.get(position), bar)).start();

return rowView;
}
}

最佳答案

好吧,如果你想保留引用以展示一个好的下载管理器,让我们看看如何做,分部分进行。

这个概念很容易理解,我们有线程下载项目,我们将调用每个工作任务。每个任务都与 ListView 中的一行相关联,因为您要显示每个项目下载的下载进度。

因此,如果每个任务与每一行相关联,我们将保存实际正在执行的任务,这样,我们随时了解正在运行的任务及其状态。这很重要,因为正如我之前所说,getView() 方法会被多次调用,我们需要知道每个正在进行的下载及其状态。

让我们看一下适配器的一些代码:

class MyAdapter extends ArrayAdapter<Uri> {
ArrayList<Uri> M_list;
Map<Uri, HttpDownloader> taskMap;

public MyAdapter(ArrayList<Uri> list) {
super(MainActivity.this, R.layout.download_item, list);
this.M_list = list;

taskMap = new HashMap<Uri, HttpDownloader>();
}

@Override
public int getCount() {
return this.M_list.size();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.download_item, parent, false);

ProgressBar progressBar = (ProgressBar) rowView.findViewById(R.id.progressBar);

configureRowWithTask(position, progressBar);

return rowView;
}

private void configureRowWithTask(int position,final ProgressBar bar) {
Uri url = M_list.get(position);
HttpDownloader task;

if (!(taskMapHasTaskWithUrl(url))) {
task = new HttpDownloader(url, bar);
Thread thread = new Thread(task);
thread.start();
taskMap.put(url, task);
} else {
task = taskMap.get(url);
bar.setProgress(task.getProgress());
task.setProgressBar(bar);
}
}

private boolean taskMapHasTaskWithUrl(Uri url) {
if (url != null) {
Iterator taskMapIterator = taskMap.entrySet().iterator();

while(taskMapIterator.hasNext()) {
Map.Entry<Uri, HttpDownloader> entry = (Map.Entry<Uri, HttpDownloader>) taskMapIterator.next();
if (entry.getKey().toString().equalsIgnoreCase(url.toString())) {
return true;
}
}
}

return false;
}
}

一些解释:

  • 我已将您的适配器类型更改为 Uris 的 ArrayAdapter,以便更好地处理链接。
  • 我添加了一个具有键值对的映射,键是 Uris,值是 HttpDownloader。此 map 将保存每个正在使用的任务。
  • 我添加了两个重要的方法,一个是 configureRowWithTask(),就像它自己的名字所说的那样,用任务配置行,将它们关联起来,但前提是任务是新的,否则是正在使用的任务。另一种方法是 taskMapHasTaskWithUrl(),只需检查给定任务(通过其 url)当前是否在 taskMap 中。
  • 可能,最重要的方法是 configureRowWithTask(),我将深入解释它。

configureRowWithTask() 方法检查是否有一个任务正在使用,这个方法是必需的,因为 getView() 被多次调用,但我们不希望同一个下载任务被执行多次,所以这个方法检查,如果任务是新的(不存在于 taskMap 中)然后创建 HttpDownloader 的新实例并将新任务放入映射中。

如果请求的任务存在于 taskMap 中,则意味着之前已请求过该任务,但列表中的行已消失,并且已重新调用 getView() 方法。所以任务已经存在,我们不必再次创建它,可能任务正在下载项目,我们唯一要做的就是查看其下载进度并将其设置为行的进度条。最后设置对进度条的引用,可能是 HttpDownloader 丢失了这个引用。

清楚这部分后,我们开始第二部分,HttpDownloader 类,让我们看一些代码:

public class HttpDownloader implements Runnable {

private Uri url;

private ProgressBar progressBar;
private int progress = 0;

private Handler handler;

public HttpDownloader (Uri url, ProgressBar progressBar) {
this.url = url;
this.progressBar = progressBar;
progressBar.setProgress(progress);

handler = new Handler();
}

@Override
public void run() {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(url.toString());
HttpResponse response;


try {
response = client.execute(get);
InputStream is = response.getEntity().getContent();
long contentLength = response.getEntity().getContentLength();
int downloadedLen = 0;
int readBytes = 0;

byte [] buffer = new byte [1024];


while ((readBytes = is.read(buffer, 0, buffer.length)) != -1) {
downloadedLen += readBytes;

//Some storing to file codes

progress = (int) ((100f * downloadedLen) / contentLength);

handler.post(new Runnable() {
@Override
public void run() {
if (progressBar != null) {
progressBar.setProgress(progress);
}
}
});
}

} catch (ClientProtocolException e) {
Log.e("HttpDownloader", "Error while getting response");
} catch (IOException e) {
e.printStackTrace();
Log.e("HttpDownloader", "Error while reading stream");
}
}

public int getProgress() {
return progress;
}

public void setProgressBar(ProgressBar progressBar) {
this.progressBar = progressBar;
}
}

这个类基本上是一样的,不同的是我在UI线程中使用了一个Handler来改变进度条的进度,只有当进度条的引用不为null时才改变这个进度。

重要的是每次下载字节时,下载进度的值都会刷新。

我已经检查了测试应用程序中的代码,似乎一切运行正常,如果您有任何问题,请告诉我,我会尽力帮助您; )

希望你能理解。

关于Android ListView 和 Adapter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12185009/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com