自定义适配器并不总是正确更新

时间:2015-10-01 16:08:54

标签: android gridview adapter picasso

我的ImageAdapter似乎有问题。它应该更新GridView但不会这样做。

代码:

public class MainActivityFragment extends Fragment {

    ImageAdapter imageAdapter;
    GridView gridView;

    public MainActivityFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false);
        gridView = (GridView) rootView.findViewById(R.id.gridView);
        imageAdapter = new ImageAdapter(getActivity(),new ArrayList<Movie>());
        gridView.setAdapter(imageAdapter);
        return rootView;
    }

    @Override
    public void onStart() {
        super.onStart();
        UpdateMovies();
    }

    private void UpdateMovies() {
        FetchMoviesTask task = new FetchMoviesTask();
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
        String sort = preferences.getString(getString(R.string.pref_sort_key), getString(R.string.pref_sort_default));
        task.execute(sort);
    }

    public class ImageAdapter extends BaseAdapter {
        private Context mContext;
        private ArrayList<Movie> data;


        public ImageAdapter(Context c, ArrayList<Movie> movies) {
            mContext = c;
            data = movies;
        }

        public int getCount() {
            return data.size();
        }

        public Object getItem(int position) {
            return null;
        }

        public long getItemId(int position) {
            return 0;
        }

        // create a new ImageView for each item referenced by the Adapter
        public View getView(int position, View convertView, ViewGroup parent) {
            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(mContext.LAYOUT_INFLATER_SERVICE);
            View gridView;
            ImageView imageView;
            if (convertView == null) {
                // if it's not recycled, initialize some attributes
                gridView = new GridView(mContext);
                gridView = inflater.inflate(R.layout.grid_item_poster, null);
                imageView = (ImageView)gridView.findViewById(R.id.poster);
            } else {
                imageView = (ImageView) convertView;
            }
            if (data.size() != 0) {
                Log.v("IMAGE_ADAPTER","SetView= " + data.get(position).poster);
                Picasso.with(mContext).load(data.get(position).poster).into(imageView);
            }
            return imageView;
        }

        public void updatePosters(ArrayList<Movie> newMovies) {
            data.clear();
            data.addAll(newMovies);
            this.notifyDataSetChanged();
        }
    }
    public class FetchMoviesTask extends AsyncTask<String, Void, ArrayList<Movie>> {

        private final String LOG_TAG = FetchMoviesTask.class.getName();


        private ArrayList<Movie> getMovieDataFromJson(String movieJsonStr, int numDays)
                throws JSONException {

            // These are the names of the JSON objects that need to be extracted.
            final String MOV_LIST = "results";
            final String MOV_ID = "id";
            final String MOV_TITLE = "original_title";
            final String MOV_OVERVIEW = "overview";
            final String MOV_RATING = "vote_average";
            final String MOV_DATE = "release_date";
            final String MOV_POSTER = "poster_path";

            JSONObject listJson = new JSONObject(movieJsonStr);
            JSONArray movieArray = listJson.getJSONArray(MOV_LIST);

            ArrayList<Movie> movies = new ArrayList<>();
            for(int i = 0; i < movieArray.length(); i++) {

                int id;
                String title;
                String overview;
                String rating;
                String date;
                String poster;

                // Get the JSON object representing the day
                JSONObject movie = movieArray.getJSONObject(i);

                id = movie.getInt(MOV_ID);
                title = movie.getString(MOV_TITLE);
                overview = movie.getString(MOV_OVERVIEW);
                rating = movie.getString(MOV_RATING);
                date = movie.getString(MOV_DATE);
                poster = movie.getString(MOV_POSTER);

                Movie newMovie = new Movie(id, title, overview, rating, date, poster);

                movies.add(newMovie);
            }

            for (Movie s : movies) {
                Log.v(LOG_TAG, "Movie entry: " + s.print());
            }
            return movies;

        }

        @Override
        protected void onPostExecute(ArrayList<Movie> result) {
            if(result != null){
                Log.v(LOG_TAG,"DATA SET CHANGED! SIZE= " + result.size());
                imageAdapter.updatePosters(result);
            }
        }

        @Override
        protected ArrayList<Movie> doInBackground(String... params) {

            if(params.length == 0){
                return null;
            }

            // These two need to be declared outside the try/catch
            // so that they can be closed in the finally block.
            HttpURLConnection urlConnection = null;
            BufferedReader reader = null;

            // Will contain the raw JSON response as a string.
            String movieJsonStr = null;

            String format = "JSON";
            String units = "metric";
            String apiKey = "********************";
            int numDays = 7;

            try {
                // Construct the URL for the OpenWeatherMap query
                // Possible parameters are avaiable at OWM's forecast API page, at
                // http://openweathermap.org/API#forecast
                final String MOVIE_BASE_URL = "http://api.themoviedb.org/3/discover/movie?";
                final String SORT_PARAM = "sort_by";
                final String DESC = ".desc";
                final String API_PARAM = "api_key";

                Uri builtUri = Uri.parse(MOVIE_BASE_URL).buildUpon()
                        .appendQueryParameter(SORT_PARAM,(params[0]+DESC))
                        .appendQueryParameter(API_PARAM,apiKey)
                        .build();

                URL url = new URL(builtUri.toString());

                Log.v(LOG_TAG, "Built URI " + builtUri.toString());

                // Create the request to OpenWeatherMap, and open the connection
                urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setRequestMethod("GET");
                urlConnection.connect();

                // Read the input stream into a String
                InputStream inputStream = urlConnection.getInputStream();
                StringBuffer buffer = new StringBuffer();
                if (inputStream == null) {
                    // Nothing to do.
                    return null;
                }
                reader = new BufferedReader(new InputStreamReader(inputStream));

                String line;
                while ((line = reader.readLine()) != null) {
                    // Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
                    // But it does make debugging a *lot* easier if you print out the completed
                    // buffer for debugging.
                    buffer.append(line + "\n");
                }

                if (buffer.length() == 0) {
                    // Stream was empty.  No point in parsing.
                    return null;
                }
                movieJsonStr = buffer.toString();

                Log.v(LOG_TAG,"Movie JSON String: " + movieJsonStr);
            } catch (IOException e) {
                Log.e(LOG_TAG, "Error ", e);
                // If the code didn't successfully get the weather data, there's no point in attemping
                // to parse it.
                return null;
            } finally {
                if (urlConnection != null) {
                    urlConnection.disconnect();
                }
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (final IOException e) {
                        Log.e(LOG_TAG, "Error closing stream", e);
                    }
                }
            }
            try {
                return getMovieDataFromJson(movieJsonStr, numDays);
            }catch (JSONException e){
                Log.e(LOG_TAG, e.getMessage(), e);
                e.printStackTrace();
            }
            return null;
        }
    }
}

fragment_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivityFragment">

<GridView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/gridView"
    android:columnWidth="180dp"
    android:gravity="center"
    android:numColumns="auto_fit"
    android:stretchMode="columnWidth"/>

grid_item_poster.xml

<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="120dp"
    android:scaleType="centerCrop"
    android:id="@+id/poster"
    android:adjustViewBounds="true">

</ImageView>

奇怪的是,当我在onCreateView中创建我的ImageAdapter时添加带有元素的ArrayList时,它确实有效,但是当我将该列表保留为未填充时,它不会更新。

任何人都有任何线索该怎么办? 一整天都在寻找解决方案。 :d

提前致谢。

2 个答案:

答案 0 :(得分:1)

我觉得你的getView()方法有问题我有一种奇怪的印象 - 我可能错了,但试试这个:

public View getView(int position, View convertView, ViewGroup parent) {
    LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(mContext.LAYOUT_INFLATER_SERVICE);
    ImageView imageView;
    if (convertView == null) {
        convertView = inflater.inflate(R.layout.grid_item_poster, null);
        imageView = (ImageView) convertView.findViewById(R.id.poster);
        convertView.setTag(imageView);
    } else {
        imageView = (ImageView) convertView.getTag();
    }
    if (data.size() != 0 && data.get(position) != null) {
        Log.v("IMAGE_ADAPTER","SetView= " + data.get(position).poster);
        Picasso.with(mContext).load(data.get(position).poster).into(imageView);
    } else {  
      //I think that you should reset image when there is a issue with data set
      imageView.setImageResource(-1);
    }
    return imageView;
}

此外,此评论 - create a new ImageView for each item referenced by the Adapter无效,因为适配器重用视图位于屏幕之外,因此有时不会创建新的ImageView实例,列表会显示旧数据的新数据

修改

尝试创建新数据列表而不是清除旧数据列表:

    public void updatePosters(ArrayList<Movie> newMovies) {
        data = new ArrayList<Movies>();
        data.addAll(newMovies);
        this.notifyDataSetChanged();
    }

答案 1 :(得分:0)

getView未正确实施。首先,你想要在那里实现它是非常奇怪的,你正在膨胀一些东西只是为了从该布局获得一个ImageView。您可以在方法中实例化ImageView:

public View getView(int position, View convertView, ViewGroup parent) {
    View view=convertView;
    if (view == null) {
        view=new ImageView(mContext);
        view.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout
            .LayoutParams.MATCH_PARENT,LinearLayout
            .LayoutParams.WRAP_CONTENT));
        view.setScaleType(ImageView.ScaleType.CENTER_CROP);

    }
    final String url=data.get(position).poster;
    if (!TextUtis.isEmpty(url) {
        Log.v("IMAGE_ADAPTER","SetView= " + url);
        Picasso.with(mContext).load(url).into(((ImageView)view));
    } else {
        Picasso.with(mContext).load(android.R.color.transparent).into(((ImageView)view);
    }
    return view;
}