【问题标题】:getCount() is being called before BaseAdapter constructor method finishes executing在 BaseAdapter 构造方法完成执行之前调用 getCount()
【发布时间】:2016-05-10 05:45:12
【问题描述】:

我是安卓新手。我正在尝试创建一个 GridView 由 ImageView 组成。图片来自 flickr,我正在使用 flickr API 搜索 flickr 并接收 JSON 响应。我解析 JSON 数据以获取图像 URL。 API 调用和解析 JSON 数据在扩展 BaseAdapter 的 FlickrAdapter 中完成。但问题是我的 getView() 方法从未被调用过。我搜索了stackoverflow for this,发现如果没有要显示的数据,则不会调用 getView()。但我在 FlickrAdapter 构造函数中设置数据。我在方法中设置了一些调试文本,我看到在设置数据之前调用了 getCount(),这意味着在 FlickrAdapter 构造函数完成执行之前调用了 getCount()。所以 getView() 永远不会被调用。 我希望在 FlickrAdapter 的构造函数方法完成执行后调用 getCount() 方法。 我该如何解决这个问题?

这是我的 BaseAdapter 和其他类的代码

FlickrAdapter.java

public class FlickrAdapter extends BaseAdapter {

public ArrayList<FlickrImage> flickrImagesList;
private Context context;

public static  FlickrAdapter instance;
FlickrAdapter(final Context context, String searchText, Activity activity) {
    this.flickrImagesList = new ArrayList<FlickrImage>();
    this.context = context;
    instance = this;
    Flickr flickr = new Flickr(searchText, context, activity);
    //row[0] = inflater.inflate(R.layout.template, null, false);
    Log.d("URL", flickr.buildApiUrl());
    DownloadManager.getJsonResponse(flickr.buildApiUrl(), context, new VolleyCallBack<JSONObject>() {
        @Override
        public void onSuccess(JSONObject success) {
            //Log.d("JSON",success.toString());
            try {
                success = success.getJSONObject("photos");
                JSONArray photo = success.getJSONArray("photo");

                for (int i = 0; i < photo.length(); i++) {
                    JSONObject tempObject = photo.getJSONObject(i);
                    String result = new StringBuilder("https://farm" + tempObject.get("farm").toString() +
                            ".staticflickr.com/" +
                            tempObject.get("server").toString() +
                            "/" +
                            tempObject.get("id").toString() +
                            "_" +
                            tempObject.get("secret").toString() +
                            "_n.jpg").toString();

                    FlickrImage image = new FlickrImage(i, result);
                    instance.flickrImagesList.add(image);

                    Log.d("SIZE", String.valueOf(instance.flickrImagesList.size()));

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

@Override
public int getCount() {
    Log.d("COUNT",String.valueOf(flickrImagesList.size()));
    return flickrImagesList.size();
}

@Override
public Object getItem(int position) {
    return flickrImagesList.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

class ViewHolder {
    ImageView myImage;

    ViewHolder(View v) {
        myImage = (ImageView) v.findViewById(R.id.individulaImage);
    }
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View row = convertView;
    ViewHolder holder = null;
    if (row == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        row = inflater.inflate(R.layout.individual_image, parent, false);
        holder = new ViewHolder(row);
        row.setTag(holder);
    } else {
        holder = (ViewHolder) row.getTag();
    }


    FlickrImage tempImage = flickrImagesList.get(position);
    Log.d("Address", tempImage.imageName);

    //ImageView iv = (ImageView) convertView.findViewById(R.id.individulaImage);

    //Picasso.with(context).load(tempImage.imageName).into(iv);
    return row;
}}

Flickr.java

public class Flickr {
private StringBuilder urlBuilder = new StringBuilder("https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=e78808f6cf756218d6981fcdf8021f0c&tags=");
private String apiUrl = "";
private Context context = null;
private Activity activity;
private String[] individualImageUrl;
private String keyWord = "";

public Flickr(String keyWord, Context context, Activity activity) {
    this.keyWord=keyWord;
    this.apiUrl = buildApiUrl();
    this.context = context;
    this.activity = activity;
    //Log.d("APIURL", this.apiUrl);
}

public String buildApiUrl() {
    String[] temp;
    StringBuilder sb = new StringBuilder();
    temp = this.keyWord.split(" ");
    for (int i = 0; i < temp.length; i++) {
        sb.append(temp[i]);
        if (i != (temp.length - 1)) {
            sb.append("+");
        }
    }
    urlBuilder.append(sb);
    urlBuilder.append("&text=");
    urlBuilder.append(sb);
    urlBuilder.append("&format=json&nojsoncallback=1");

    return urlBuilder.toString();
}}

FlickrImage.java

public class FlickrImage {
public int imageId;
public String imageName;

FlickrImage(int imageId, String imageURL) {
    this.imageId = imageId;
    this.imageName = imageURL;
    }
}

VolleyCallBack.java

public interface VolleyCallBack<T> {
public void onSuccess(T success);
}

下载管理器.java

public class DownloadManager {
public static void getJsonResponse(final String Url, Context context, final VolleyCallBack callBack) {
    JsonObjectRequest flickrJsonRequest = new JsonObjectRequest(Request.Method.GET, Url, null,
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject response) {
                    callBack.onSuccess(response);
                }
            },
            new Response.ErrorListener() {
                public void onErrorResponse(VolleyError error) {
                    error.printStackTrace();
                }
            });
    Volley.newRequestQueue(context).add(flickrJsonRequest);
}
}

【问题讨论】:

  • 我见过一些例子,其中一个通过启动 AsyncTask 加载数据(例如在 onCreate() 中)和在 onPostExecute() 中将它们推送到数据列表中(你的'flickrImagesList')和拨打notifyDatasetChanged(),可能值得一试。
  • 我对 AsyncTask 有一些想法,但对 notifyDatasetChanged() 没有。我会看看并试一试。谢谢
  • @0X0nosugar notifyDatasetChanged() 工作得很好。非常感谢人:)

标签: android json android-gridview baseadapter


【解决方案1】:

在您的构造函数完成之前不会调用它。您的 Web 代码在单独的线程中运行,因此您的构造函数代码完成,然后调用 getCount。一旦您的网络代码完成,就会调用 onSuccess。

永远不建议在适配器中运行网络代码。在您的 Activity 或 Fragment 中运行它,并在完成后在您的适配器上调用 notifyDatasetChanged()。

【讨论】:

  • 当我搜索某些东西时,我在调试日志中收到以下消息 05-10 11:15:54.677 22120-22120/com.example.mamun.wp D/COUNT: 0 05-10 11:15:54.677 22120-22120/com.example.mamun.wp D/COUNT: 0 05-10 11:15:54.677 22120-22120/com.example.mamun.wp D/COUNT: 0 05-10 11: 15:56.507 22120-22120/com.example.mamun.wp D/SIZE: 1 05-10 11:15:56.507 22120-22120/com.example.mamun.wp D/SIZE: 2 这里“COUNT”印在里面Adapter 构造函数中的 getCount 和“SIZE”。但是根据你告诉我的,“SIZE”应该总是在“COUNT”之前打印
  • 根据我告诉您的内容,count 大多会在尺寸之前打印,这就是您的问题。在你的 onSuccess 回调之前获取计数运行
  • 我明白了。我在回调之前进行了调试,并在计数之前打印了它。但是我仍然不知道如何在调用 getCount() 之前让我的 callBack 完成执行。有什么办法吗?
  • 如果不挂起您的设备,您将无法完成。我建议将网络代码移动到活动中,使用空列表设置适配器,然后在加载完成后调用 adapter.notifydatasetChanged。
  • 我会尝试并告诉你。感谢您的帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-17
  • 2015-08-20
  • 2021-01-06
相关资源
最近更新 更多