【问题标题】:The content of the adapter has changed but ListView did not receive a notification android google places适配器的内容发生了变化,但 ListView 没有收到通知 android google places
【发布时间】:2015-09-14 14:09:02
【问题描述】:

我正在使用 google 地方自动完成功能,但出现以下错误: (并不总是只发生几次)

 java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(-1, class android.widget.ListPopupWindow$DropDownListView) with Adapter(class locationplacesautocomplete.GooglePlacesAutocompleteAdapter)]

 at android.widget.ListView.layoutChildren(ListView.java:1582)
            at android.widget.AbsListView.onLayout(AbsListView.java:2627)
            at android.view.View.layout(View.java:16821)
            at android.view.ViewGroup.layout(ViewGroup.java:5328)
            at android.widget.FrameLayout.layoutChildren(FrameLayout.java:573)
            at android.widget.FrameLayout.onLayout(FrameLayout.java:508)
            at android.view.View.layout(View.java:16821)
            at android.view.ViewGroup.layout(ViewGroup.java:5328)

阅读以下消息后,我将 runOnUiThread() 用于 notifyDataSetChanged() 但仍然无法正常工作。

我将添加适配器类:

package locationplacesautocomplete;

import android.app.Activity;
import android.content.Context;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import java.util.ArrayList;
import java.util.HashMap;

import datatypes.AutoCompleteData;

/**
 * This class implements the adapter for google places auto complete
 * Created by edenbensimon on 07/06/15.
 */
public class GooglePlacesAutocompleteAdapter extends ArrayAdapter implements Filterable {

    // Holds an array list with the results
    private Object[] resultList;
    private HashMap<String, String> result;
    private Activity _activity;

    // Default ctor
    public GooglePlacesAutocompleteAdapter(Context context, int textViewResourceId, Activity activity) {
        super(context, textViewResourceId);
        _activity = activity;
    }

    @Override
    public int getCount() {
        return resultList.length;
    }

    @Override
    public String getItem(int index) {
        return resultList[index].toString();
    }

    @Override
    public Filter getFilter() {
        Filter filter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults filterResults = new FilterResults();
                if (constraint != null) {
                    // Retrieve the autocomplete results.
                    result = AutoCompleteLogic.autocomplete(constraint.toString());
                    resultList = result.keySet().toArray();

                    // Assign the data to the FilterResults
                    filterResults.values = resultList;
                    filterResults.count = resultList.length;
                }
                return filterResults;
            }
            @Override
            protected void publishResults(CharSequence constraint, final FilterResults results) {
                _activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (results != null && results.count > 0) {
                            notifyDataSetChanged();
                        } else {
                            notifyDataSetInvalidated();
                        }
                    }
                });
            }
        };
        return filter;
    }

    /**
     * Returns an array list with only description about the place
     */
    private ArrayList getDescOnly(ArrayList values) {
        ArrayList returnValue = new ArrayList<String>();
        for (int i = 0; i < values.size(); i++) {
            returnValue.add(((AutoCompleteData)values.get(i)).getDescription());
        }

        return returnValue;
    }

    public HashMap<String, String> getResult() {
        return result;
    }

    public void setResult(HashMap<String, String> result) {
        this.result = result;
    }

    public Object[] getResultList() {
        return resultList;
    }

    public void setResultList(Object[] resultList) {
        this.resultList = resultList;
    }
}

这是我的计算逻辑

/**
 * This method gets the current input and returns list with all suitable cities
 * @return
 */
public static HashMap autocomplete(String input) {

    // Initialize the variable
    HashMap<String, String> result = null;

    // The url connection will be used
    HttpURLConnection conn = null;

    // String builder for the json results
    StringBuilder jsonResults = new StringBuilder();
    try {
        // Build the string for the url
        StringBuilder sb = new StringBuilder(PLACES_API_BASE + TYPE_AUTOCOMPLETE + OUT_JSON);
        sb.append("?key=" + API_KEY);

        // This parameter is used for choosing specific country, not must.
        sb.append("&input=" + URLEncoder.encode(input, "utf8"));


  // Create the url
    URL url = new URL(sb.toString());
    conn = (HttpURLConnection) url.openConnection();
    InputStreamReader in = new InputStreamReader(conn.getInputStream());

    // Load the results into a StringBuilder
    int read;
    char[] buff = new char[1024];
    while ((read = in.read(buff)) != -1) {
        jsonResults.append(buff, 0, read);
    }
} catch (MalformedURLException e) {
    Log.e(LOG_TAG, "Error processing Places API URL", e);
    return result;
} catch (IOException e) {
    Log.e(LOG_TAG, "Error connecting to Places API", e);
    return result;
} finally {
    if (conn != null) {
        conn.disconnect();
    }
}

try {
    // Create a JSON object hierarchy from the results
    JSONObject jsonObj = new JSONObject(jsonResults.toString());
    JSONArray predsJsonArray = jsonObj.getJSONArray("predictions");

    // Extract the Place descriptions from the results
    result = new HashMap<>(predsJsonArray.length());
    for (int i = 0; i < predsJsonArray.length(); i++) {
        result.put(predsJsonArray.getJSONObject(i).getString("description"),
                   predsJsonArray.getJSONObject(i).getString("place_id"));
    }
} catch (JSONException e) {
    Log.e(LOG_TAG, "Cannot process JSON results", e);
}

return result;

}

有人知道出了什么问题吗?拿什么卡?

提前非常感谢, 伊甸园

【问题讨论】:

  • 做一些调试;什么时候发生?这个if (results != null &amp;&amp; results.count &gt; 0) 可能是罪魁祸首。
  • 我目前正在尝试调试,但问题是它经常发生一次......很难抓住它。感谢您对 if 的指出,我现在再次检查一下
  • @mvai 到目前为止似乎并不相关

标签: android listview exception android-arrayadapter google-places-api


【解决方案1】:

尝试在每次数据更改/设置后在适配器中调用notifyDataSetChanged

【讨论】:

  • 你能解释一下在哪里以及为什么吗?
  • 因为您正在使用 setter 方法更新数据,但小部件不会知道此更新。所以小部件和适配器不同步。 notifyDataSetChanged 将通知小部件与适配器同步。
  • 感谢您的精彩解释。您的意思是在执行过滤后设置它?
  • 现在还:在 performFiltering() 期间发生异常! android.view.ViewRootImpl$CalledFromWrongThreadException: 只有创建视图层次结构的原始线程才能触摸它的视图。
  • 你的意思是正确的:在 performFiltering // 将数据分配给 FilterResults filterResults.values = resultList; filterResults.count = 结果列表.长度; if (filterResults != null && filterResults.count > 0) { notifyDataSetChanged(); }
猜你喜欢
  • 1970-01-01
  • 2014-06-21
  • 1970-01-01
  • 1970-01-01
  • 2015-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多