【问题标题】:Populate adapter item on completion asynctask在完成异步任务时填充适配器项
【发布时间】:2016-08-14 16:20:38
【问题描述】:

我一直在环顾四周,但运气不佳,所以我想听听您对此的看法,尤其是想知道我是否走错了方向。

我有一个片段实例化一个适配器,将一个对象数组列表传递给它。对象列表引用必须从服务器检索才能显示的其他资源。因此,对于数组列表的每个对象,在适配器内部,我调用一个异步任务来检索这些信息并填充适配器项。

不幸的是,这仅导致数组的最后一个元素包含所有信息,而另一个(在我的示例中,列表中只有两个元素)为空。我的感觉是我覆盖了两次相同的适配器项,因此我只看到最后检索到的对象。

我的适配器使用 ViewHolder 设计模式,因此,在 getView 函数中,我实例化了 ViewHolderItem 私有类的对象,其中包含对所有布局元素的引用。然后我在我的所有 onPostExecute 中使用这个 viewHolderItem 来填充适配器项。

这是我的 ViewHolder 项的代码:

private static class ViewHolderItem{
    protected Button leaveFeedback, accept, reject;
    protected LinearLayout userInfo, rideInfo, pickupLayout, buttons;
    protected TextView pickupTimeText;
    protected PickupTime pickupTime;
}

这是我的 getView,它收集视图引用、设置 viewholderitem 并启动 asynctasks(评论后的行检索乘客信息):

@Override
public View getView(int i, View view, ViewGroup viewGroup) {

    // First let's verify the view is not null
    if (view == null) {
        // This a new view we inflate the new layout
        LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(R.layout.ride_passenger_item, viewGroup, false);
        viewHolderItem = new ViewHolderItem();

        viewHolderItem.userInfo = (LinearLayout) view.findViewById(R.id.user_info);
        viewHolderItem.rideInfo = (LinearLayout) view.findViewById(R.id.ride_info);
        viewHolderItem.buttons = (LinearLayout) view.findViewById(R.id.btns);
        viewHolderItem.leaveFeedback = (Button) view.findViewById(R.id.leave_feedback);
        viewHolderItem.pickupLayout = (LinearLayout) view.findViewById(R.id.pickup_layout);
        viewHolderItem.pickupTimeText = (TextView) view.findViewById(R.id.pickup_time);
        viewHolderItem.accept = (Button) view.findViewById(R.id.accept);
        viewHolderItem.reject = (Button) view.findViewById(R.id.reject);

        // store the holder with the view.
        view.setTag(viewHolderItem);
    }
    else{
        // we've just avoided calling findViewById() on resource everytime
        // just use the viewHolder
        viewHolderItem = (ViewHolderItem) view.getTag();
    }

    final Passengership passengership = passengerships.get(i);

    /** retrieve passenger info **/
    new GetDemand().execute(demandAPI.getDemand());
    new GetPassenger().execute(userAPI.getUser(passengership.getPassenger()));
    new GetRide().execute(rideAPI.getRide());

    /**
     * if we are displaying pending passenger request, proposed by the driver
     * we need to enable the accept reject button
     **/
    if(type.equals(Status.PENDING) && !passengership.isProposedByDriver())
        buildAcceptRejectButtons(passengership);

    this.passengershipID = passengership.getId();
    return view;
}

这是我的 AsyncTask 类之一:

/**
 * Download the JSON of the demand
 */
private class GetDemand extends GetRequest {

    @Override
    protected void onPostExecute(ServerResponseObject serverResponseObject){
        Demand demand = GsonCustomBuilder.getGson().fromJson(
                serverResponseObject.getJSONObject().toString(), Demand.class);
        demand.populateView(viewHolderItem.rideInfo);
    }
}

demand.populateView() 基本上是一个函数,我将包含视图引用的 viewHolderItem 传递给它,以便我可以在其中填充信息。

【问题讨论】:

  • 每个项目三个 AsyncTasks?你的电池使用一定不要太高兴……你能不重构API吗?
  • I call an asynctask to retrieve these information and populate the adapter item.。适配器项目是什么意思?在你说你有一个包含对象的数组列表之前。您应该填充另一个具有相同大小的数组列表并将结果放在那里。然后调用之后的 notifyDatasetChanged。您将结果保存在一个数组中,否则滚动时会丢失它们。
  • 你应该给异步任务一个额外的参数i,因为现在他们不知道他们从哪个项目开始以及完成后将结果放在哪里。
  • viewHolderItem。你把它作为你的活动变量?错误的。使其成为 getView() 的局部变量。这将阻止您在其他地方使用它。
  • @greenapps 感谢您的回答并为您的困惑感到抱歉。我这句话的意思是异步任务是在适配器内启动的,我现在明白他们不知道数据属于哪个项目。所以我理解你的意思。我要试试你说的。对于 viewHolderItem 而言,它在适配器中,而不是在活动中。

标签: java android listview android-asynctask adapter


【解决方案1】:

原来我没有正确使用适配器,但感谢@greenapps 输入,我设法解决了我的问题。

基本上,我在 getView 函数中移动了变量 viewHolderItem,现在我通过构造函数将它传递给我的所有 AsyncTasks,这样他们就可以在从服务器获得结果后使用它来填充适配器项。

作为一个例子,这是我经过上述修改后的 AsyncTask 类之一:

/**
 * Download the JSON of the demand
 */
private class GetDemand extends GetRequest {

    private int passengershipID;
    private ViewHolderItem viewHolderItem;

    public GetDemand(int passengershipID, ViewHolderItem viewHolderItem){
        this.passengershipID = passengershipID;
        this.viewHolderItem = viewHolderItem;
    }

    @Override
    protected void onPostExecute(ServerResponseObject serverResponseObject){
        Demand demand = GsonCustomBuilder.getGson().fromJson(
                serverResponseObject.getJSONObject().toString(), Demand.class);
        Passengership passengership = passengershipsHashMap.get(passengershipID);
        passengership.setDemand(demand);
        demand.populateView(viewHolderItem.rideInfo);
    }
}

正如您在代码中看到的,我有一个构造函数,用于将 viewHolderItem 传递给 AsyncTask。最后,在 onPostExecute 中,我使用 viewHolderItem 来填充检索到的信息。

【讨论】:

  • 如果您有更多的项目然后可以看到,这将不会做。目前你只有两个你说的项目,所以它们总是可见的。但是对于测试添加更多的项目,所以用户必须滚动。你会发现你的方法出错了。你应该怎么做,我已经在我的第一条评论中告诉过你。
猜你喜欢
  • 2015-03-26
  • 2015-08-12
  • 1970-01-01
  • 2016-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-07
  • 2023-03-16
相关资源
最近更新 更多