Android ListView和适配器

Android ListView和适配器,android,listview,Android,Listview,我正在处理一个下载管理器项目,因此,为了显示所有下载/下载操作,我更喜欢使用ListView显示我的下载列表。假设我们有多达个下载任务,那么所有任务的进度条都必须更新。对于后台下载任务,我创建了一个新类,并将其命名为HttpDownloader。所以,我在这个类的对象上传递这些进度条。当一个新对象添加到我的任务列表中时,我调用HttpDownloader的构造函数,并将新项目进度条传递给它。让我困惑的是当我向tasklist添加一个新对象并调用adapter的notifyDataSetChang

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

1。调用notifyDataSetChanged后,对旧listview对象的引用是析构函数?

2。如果是,如何保留旧视图的引用?

3。如果否,请向我解释,当后台进程强制通过progressbar更改进度值时,为什么进度条重置为默认值而不更改?

HTTPDownloader类

适配器类

class MyAdapter扩展了ArrayAdapter{
ArrayList M_列表;
公共MyAdapter(ArrayList列表){
超级(MainActivity.this,R.layout.download_项目,列表);
此.M_列表=列表;
}
@凌驾
public int getCount(){
返回此.M_list.size();
}
公共视图getView(int位置、视图转换视图、视图组父视图){
LayoutFlater充气机=(LayoutFlater)getSystemService(布局充气机服务);
视图行视图=充气机。充气(R.layout.download_项,父项,false);
ProgressBar=(ProgressBar)rowView.findViewById(R.id.progrees);
新线程(新的HttpDownloader(this.M_list.get(position),bar)).start();
返回行视图;
}
}

当调用notifyDataSetChanged()或Activity resumes时,列表的每一行都会调用适配器的getView()方法

因此,当您向列表中添加新项并调用notifyDataSetChanged()时,getView()方法的执行次数与该时刻列表中的项的执行次数相同,另外还有一个原因导致您添加了新项

正如您所知,getView()方法构建行,因此构建一个新的ProgressBar,显然,这个ProgressBar从progress的位置0开始


因此,答案可以恢复为“是”,每次调用notifyDataSetChanged(),getView()方法都会被多次调用,每行调用一个(如果您将android:layout_height参数设置为0dip,android:layou weight设置为1.0,就像您可能知道的ListView),这就是为什么您会得到ProgressBars“初始化”的原因当您将新项目添加到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;
    }
}
这个类基本上是相同的,不同之处在于我在UI线程中使用了一个处理程序来更改进度条的进度,并且仅当对进度条的引用不为null时才更改这个进度

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

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


希望您能理解。

我想保留这些参考资料。调用
notifyDataSetChanged()
时,可以更改所有旧引用。我想保留这些参考资料,我怎么能保留这个?(我正在使用ListView编程下载管理器UI,我们应该更改所有progressbars的值)
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;
    }
}
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;
    }
}
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;
}
}