【问题标题】:android issues updating Listview due to filtering, with a custom base adapter由于过滤,android 使用自定义基础适配器更新 Listview 问题
【发布时间】:2014-10-14 09:19:06
【问题描述】:

我在 Android 中对 ListView 实施搜索机制时遇到了问题。

  • 我目前在ListView 中显示公司列表
  • ListView 链接到引用数据模型的自定义 BaseAdapter
  • 数据模型通过HTTP requests处理数据收集。

我成功部分过滤:已识别的公司在listview 中被识别,但其余公司(与搜索约束不匹配的公司仍然存在),即使我删除了它们

代码如下:

package org.x.activites;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.x.R;
import org.x.activites.utils.Analytics;
import org.x.adapters.listview.AbstractDynamicModel;
import org.x.adapters.listview.AbstractExtendedDynamicViewAdapter;
import org.x.adapters.listview.ViewHolder;
import org.x.application.Application;
import org.x.http.HTTPRequest;
import org.x.list.adapters.PartnerViewHolder;
import org.x.model.Partner;

import android.app.AlertDialog;
import android.app.SearchManager;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ListView;

import com.actionbarsherlock.app.SherlockActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.widget.SearchView;

public class GeoPartnerActivity extends SherlockActivity {
    private ListView listView;
    PartnersModel partnersModel;
    PartnerListAdapter partnerAdpt;
    private SearchManager searchManager;
    private SearchView searchView;

    public GeoPartnerActivity() {
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_partner);
        listView = (ListView) findViewById(R.id.partnerList);
        partnersModel = new PartnersModel();
        partnerAdpt = new PartnerListAdapter(partnersModel);
        listView.setAdapter(partnerAdpt);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        getSupportMenuInflater().inflate(R.menu.activity_partners, menu);
        searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
        if (null != searchView) {
            searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
            searchView.setIconifiedByDefault(false);
        }

        SearchView.OnQueryTextListener queryTextListener = new SearchView.OnQueryTextListener() {
            public boolean onQueryTextChange(String newText) {
                return false;
            }

            public boolean onQueryTextSubmit(String query) {
                if (TextUtils.isEmpty(query)) {
                    listView.clearTextFilter();
                }
                else {
                    listView.setFilterText(query);
                }
                partnerAdpt.getFilter().filter(query);
                return true;
            }
        };

        searchView.setOnQueryTextListener(queryTextListener);
        searchView.setQueryHint("Salut StackExchange");
        return super.onCreateOptionsMenu(menu);
    }

    public class PartnersModel extends AbstractDynamicModel<Partner> {

        public PartnersModel() {
        }

        private HTTPRequest createRequest() {
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
            nameValuePairs.add(new BasicNameValuePair("currentIndex", getElements().size() + ""));
            nameValuePairs.add(new BasicNameValuePair("partnersNumber", "5"));

            return new HTTPRequest("http://xxxxxxxxxxxxxxxx/partners", nameValuePairs);
        }

        @Override
        protected BackgroundTask createBackgroundTask() {
            BackgroundTask backgroundTask = new BackgroundTask(GeoPartnerActivity.this, createRequest()) {
                List<Partner> lastLoaded = new ArrayList<Partner>();

                @Override
                protected List<Partner> getLoadedElements() {
                    return lastLoaded;
                }

                @Override
                protected void handleSuccess(Object object) {
                    lastLoaded.clear();
                    try {
                        JSONArray array = (JSONArray) object;
                        for (int i = 0; i < array.length(); i++) {
                            JSONObject jsonObject = (JSONObject) array.get(i);

                            Partner partner = new Partner(jsonObject);

                            lastLoaded.add(partner);
                        }

                    }
                    catch (JSONException e) {
                        e.printStackTrace();
                    }

                }
            };
            return backgroundTask;
        }

        @Override
        public List<Partner> getElements() {
            return super.getElements();
        }

        @Override
        protected Context getContext() {
            return GeoPartnerActivity.this;
        }

    }

    private class PartnerListAdapter extends AbstractExtendedDynamicViewAdapter<Partner> implements Filterable {

        private PartnersModel partnerList, partnerFullList;
        private PartnerFilter partnerFilter;

        public PartnerListAdapter(PartnersModel model) {
            super(GeoPartnerActivity.this, model);
            partnerList = model;
            partnerFullList = new PartnersModel();
        }

        @Override
        public Filter getFilter() {
            if (partnerFilter == null) {
                partnerFilter = new PartnerFilter();
            }
            return partnerFilter;
        }

        public void notifyDataSetChanged() {
            super.notifyDataSetChanged();
        }

        @Override
        protected int getResourceID() {
            return PartnerViewHolder.ResourceId;
        }

        @Override
        protected ViewHolder createViewHolder(View convertView) {
            return new PartnerViewHolder(convertView);
        }

        public class PartnerFilter extends Filter {

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults results = new FilterResults();

                List<Partner> partnerFilteredList = new ArrayList<Partner>();
                for (Iterator<Partner> iterator = partnerList.iterator(); iterator.hasNext();) {

                    Partner partner = iterator.next();
                    partnerFullList.getElements().add(partner);

                    if (false == partner.getName().toUpperCase().contains(constraint.toString().toUpperCase())) {
                        partnerFilteredList.add(partner);
                    }
                }
                results.values = partnerFilteredList;
                results.count = partnerFilteredList.size();

                return results;
            }

            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                if (results.count == 0)
                    partnerAdpt.notifyDataSetInvalidated();
                else {
                    for (Iterator<Partner> iterator = ((List<Partner>) results.values).iterator(); iterator.hasNext();) {
                        Partner p = (Partner) iterator.next();
                        if (partnerAdpt.partnerList.getElements().remove(p));
                            p.setName("del-> " + p.getName());  
                    }

                    //listView.setAdapter(null);
                    //listView.setAdapter(new PartnerListAdapter(partnerList));
                    ((PartnerListAdapter) listView.getAdapter()).notifyDataSetChanged();
                    listView.refreshDrawableState();
                    listView.invalidateViews();
                }
            }
        }
    }
}

这里是菜单布局

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:id="@+id/menu_search"
        android:actionViewClass="com.actionbarsherlock.widget.SearchView"
        android:icon="@drawable/toolbar_find"
        android:showAsAction="always"
        android:title="Search">
    </item>
</menu>

这是过滤前的截图:

之后:

我已经用“del->”标记了项目的名称,所以它们都被识别了,但没有从列表中删除!!!

编辑:

这是顶级适配器 AbstractDynamicViewAdapter:

public abstract class AbstractDynamicViewAdapter extends BaseAdapter {
    protected final Context _context;

    protected final ArrayList<AdapterItem> _list;

    private final LayoutInflater _inflater;

    private final int _progressResourceId;
    private final int _unavailableResourceId;
    private final int _emptyResourceId;

    protected boolean _isInitialization = false;
    protected boolean _isRequestSubmited = false;

    public AbstractDynamicViewAdapter(Context context, int progressResourceId, int unavailableResourceId,
            int emptyResourceId) {
        _context = context;
        _inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        _list = new ArrayList<AdapterItem>();

        _progressResourceId = progressResourceId;
        _unavailableResourceId = unavailableResourceId;
        _emptyResourceId = emptyResourceId;
    }

    protected abstract View onDataView(int position, AdapterItem item, View convertView, ViewGroup parent);

    protected abstract void onDataLoad();

    protected abstract boolean isMoreToLoad();

    protected abstract void onSubmitDataRequest();

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

    @Override
    public Object getItem(int position) {
        Object result = null;

        if (position < _list.size()) {
            result = _list.get(position);
        }

        return result;
    }

@Override
/* Override this method when implementing stable id */
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (_list.size() > position) {
        AdapterItem item = _list.get(position);

        if (item.viewType == ViewType.Data) {
            convertView = onDataView(position, item, convertView, parent);
        }
        else {
            int resourceid = getResourceByViewType(item.viewType);
            convertView = tryInflateView(convertView, resourceid, parent);
            tryCreateViewHolder(convertView, item, resourceid);

            if (!_isRequestSubmited && item.viewType == ViewType.Progress) {
                submitDataRequest();
            }
        }
    }

    return convertView;
}
protected int getResourceByViewType(ViewType expectedType) {
    int result = 0;

    switch (expectedType) {
        case Progress:
            result = _progressResourceId;
            break;
        case Unavailable:
            result = _unavailableResourceId;
            break;
        case Empty:
            result = _emptyResourceId;
            break;
        default:
            break;
    }

    return result;
}

protected void tryCreateViewHolder(View viewSource, AdapterItem item, int resourceId) {
    ViewHolder viewItem = (ViewHolder) viewSource.getTag();
    if (viewItem == null) {
        viewItem = new ViewHolder(viewSource, resourceId);
    }
}

protected View tryInflateView(View viewSource, int resourceId, ViewGroup parent) {
    View result = null;

    if (viewSource != null && viewSource.getTag() != null) {
        ViewHolder viewItem = (ViewHolder) viewSource.getTag();
        // try to re-use view if it has the same type
        if (viewItem != null && viewItem.resourceId == resourceId) {
            result = viewSource;
        }
    }

    if (result == null) {
        // create new view
        result = _inflater.inflate(resourceId, parent, false);
    }

    return result;
}

    protected void addItem(Object value, Object tag) {
        AdapterItem item = new AdapterItem(value, tag);
        _list.add(item);
    }

    protected void removeItem(Object item) {
        _list.remove(item);
    }

    protected void addUnavailableItem() {
        AdapterItem item = new AdapterItem(ViewType.Unavailable);
        _list.add(item);
    }

    protected void submitDataRequest() {
        showProgress();
        onSubmitDataRequest();
        _isRequestSubmited = true;
    }

    protected void setDataCompleted() {
        _list.clear();
        onDataLoad();
        if (isMoreToLoad()) {
            showProgress();
        }
        notifyDataSetChanged();

        _isRequestSubmited = false;
    }

    private void removeAnyBut(ViewType type) {
        if (type != ViewType.Progress) {
            tryEndProgress();
        }

        if (type != ViewType.Empty) {
            tryEndEmpty();
        }

        if (type != ViewType.Unavailable) {
            tryEndUnavailable();
        }
    }

    private void tryShowItem(ViewType type) {
        removeAnyBut(type);

        if (_list.size() == 0 || _list.get(_list.size() - 1).viewType != type) {
            _list.add(new AdapterItem(type));
        }

        notifyDataSetChanged();
    }

    protected void showUnavailable() {
        tryShowItem(ViewType.Unavailable);
    }

    protected void showProgress() {
        tryShowItem(ViewType.Progress);
    }

    protected void showEmpty() {
        tryShowItem(ViewType.Empty);
    }

    private void tryRemoveItem(ViewType type) {
        if (_list.size() > 0 && _list.get(_list.size() - 1).viewType == type) {
            _list.remove(_list.size() - 1);
        }
    }

    protected void tryEndProgress() {
        tryRemoveItem(ViewType.Progress);
    }

    protected void tryEndUnavailable() {
        tryRemoveItem(ViewType.Unavailable);
    }

    protected void tryEndEmpty() {
        tryRemoveItem(ViewType.Empty);
    }

}

和中间的适配器 AbstractExtendedDynamicViewAdapter :

public abstract class AbstractExtendedDynamicViewAdapter<T> extends AbstractDynamicViewAdapter {
    private final AbstractDynamicModel<T> _model;

    private boolean offlineModedataLoaded = false;

    private Handler handler = new Handler() {
        @Override
        public void dispatchMessage(Message msg) {
            setDataCompleted();
        }
    };

    public AbstractExtendedDynamicViewAdapter(Context context, AbstractDynamicModel<T> model) {
        super(context, R.layout.progress_item, R.layout.unavailable_item, R.layout.empty_item);

        _model = model;
        _model.setLoadCompleted(handler);
        submitDataRequest();
    }

    @Override
    public View onDataView(int position, AdapterItem item, View convertView, ViewGroup parent) {
        convertView = tryInflateView(convertView, getResourceID(), parent);
        ViewHolder viewHolder = (ViewHolder) convertView.getTag();
        if (viewHolder == null) {
            viewHolder = createViewHolder(convertView);
        }
        viewHolder.render(item);
        return convertView;
    }
    public boolean removeElement(Object obj) {
        //return _list.remove(obj);
        return _model.getElements().remove(obj);
    }

    protected abstract int getResourceID();

    protected abstract ViewHolder createViewHolder(View convertView);

    @Override
    protected boolean isMoreToLoad() {
        if (Utils.isConnected(_context)) {
            offlineModedataLoaded = true;
            return true;
        }
        else
            if (false == offlineModedataLoaded) {
                offlineModedataLoaded = true;
                return true;
            }
        return false;
    }

    @Override
    protected void onDataLoad() {
        if (_model.getElements().isEmpty()) {
            addUnavailableItem();
            showUnavailable();
        }
        else {
            for (int i = 0; i < _model.getElements().size(); i++) {

                addItem(_model.getElements().get(i), null);
            }
        }
    }

    @Override
    protected void onSubmitDataRequest() {
        _model.loadMore();
    }

}

【问题讨论】:

  • 适配器的基类没有使用与您过滤相同的 PartnersModel 实例...
  • 什么是“AbstractExtendedDynamicViewAdapter”?
  • @kozaxinan,AbstractExtendedDynamicViewAdapter 是 baseAdapter 的项目通用扩展
  • @Selvin,我没明白你的意思,抱歉。

标签: android android-listview baseadapter notifydatasetchanged android-searchmanager


【解决方案1】:
if (partnerAdpt.partnerList.getElements().remove(p));
                            p.setName("del-> " + p.getName());  

使用此代码,您只能更新过滤结果。您应该使用以下代码从您放入适配器的列表中删除此值:

super(GeoPartnerActivity.this, model);

尝试从适配器(而不是抽象)获取“模型”数据并删除“p”。

【讨论】:

  • 我已经尝试了所有我能想象到的方法......没有成功。根据您的建议,我尝试更改为 'partnersModel.getElements.remove(p);'但没有任何影响。对吗?
  • 您仍然使用本地变量。您应该在 baseadapter 中使用该列表。请添加从 baseadapter 获取模型的方法。
  • 你也可以发布你的适配器类吗?
  • 在编辑的问题中,我添加了以下方法public ArrayList&lt;AdapterItem&gt; getAdapterItemList() { return _list;},然后将其用作以下getAdapterItemList().remove(p);,但没有任何改变!
  • 实际上它看起来好像缺少一些方法或类,不是吗?
猜你喜欢
  • 2016-08-02
  • 1970-01-01
  • 1970-01-01
  • 2020-12-06
  • 1970-01-01
  • 1970-01-01
  • 2014-09-06
  • 2011-08-12
  • 1970-01-01
相关资源
最近更新 更多