I am currently working on an online android learning project and am facing issue with refreshing my grid view.
My app displays a grid with several images initially. On click of the Refresh Button from the Menu, the GridView should be populated with the new images.Also,on click of any image, app goes to Detail Activity which shows the current image URL.
Currently I first populate the GridView with sample images, using my custom adapter & Picasso. Then an AsyncTask executes which gets the new image URLs from a JSON. This new imageURL List has to be fed to my adapter so that the grid displays the new images.
However, I am not able to accomplish this. My initial grid shows images and on click of these, I get their URL on detail activity screen as expected. However, when I click on the Refresh in the menu, I don't see the new images. I am trying to set the adapter with the updated URL array in the onPostExecute().
On click of the old image I see the new URL in the detail activity, however once I click back the image is still not updated and URL changes back to the old one. Sometimes when I scroll the new image shows up and then app crashes.
So the basic issue is that even after getting the new URLs, I am unable to populate the GridView with new images. Any help on this will be appreciated. Thanks,
Code Snippet:
public class MovieListFragment extends Fragment {
public CustomAdapter customAdapter;
public GridView gv;
public List<String> allImages=new ArrayList<String>();
public List<String> newImages=new ArrayList<String>();
public String LOG_TAG=MovieListFragment.class.getSimpleName();
public int abc=0;
public MovieListFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootview= inflater.inflate(R.layout.movie_list_fragment, container, false);
//Fake Data Creation for 1st time GridView load.
allImages.add("http://www.pnas.org/site/misc/images/15-01065.500.jpg");
allImages.add("http://41.media.tumblr.com/78335e84b3b353ad60c335b24a5f267e/tumblr_nz2bke3fJ51rldeoho1_500.jpg");
allImages.add("http://41.media.tumblr.com/78335e84b3b353ad60c335b24a5f267e/tumblr_nz2bke3fJ51rldeoho1_500.jpg");
allImages.add("http://41.media.tumblr.com/78335e84b3b353ad60c335b24a5f267e/tumblr_nz2bke3fJ51rldeoho1_500.jpg");
allImages.add("http://41.media.tumblr.com/78335e84b3b353ad60c335b24a5f267e/tumblr_nz2bke3fJ51rldeoho1_500.jpg");
allImages.add("http://www.pnas.org/site/misc/images/15-01065.500.jpg");
allImages.add("http://www.pnas.org/site/misc/images/15-01065.500.jpg");
allImages.add("http://www.pnas.org/site/misc/images/15-01065.500.jpg");
allImages.add("http://www.pnas.org/site/misc/images/15-01065.500.jpg");
//Set Adapter
gv = (GridView) rootview.findViewById(R.id.gridview);
customAdapter=new CustomAdapter(getActivity(),allImages);
gv.setAdapter(customAdapter);
//On Click Listener
gv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(getActivity(), DetailActivity.class);
intent.putExtra("imageURL", allImages.get(position).toString());
startActivity(intent);
}
});
return rootview;
}
//My Custom Adapter
public class CustomAdapter extends BaseAdapter{
private Context mContext;
private List<String> myImageList;
public CustomAdapter(Context c, List<String> finalImageList) {
mContext = c;
myImageList=finalImageList;
notifyDataSetChanged();
}
#Override
public int getCount() {
return myImageList.size();
}
#Override
public Object getItem(int position) {
return myImageList.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
// if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(500, 500));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
// imageView.setPadding(2, 2, 2, 2);
} else {
imageView = (ImageView) convertView;
}
Picasso.with(getActivity())
.load(myImageList.get(position))
.into(imageView);
return imageView;
}
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.movie_list_fragment_menu, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id=item.getItemId();
if(id==R.id.action_refresh){
updateMovieList();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
private void updateMovieList() {
FetchMovieDetailsTask fetchMovieDetailsTask=new FetchMovieDetailsTask();
fetchMovieDetailsTask.execute("Popularity");
}
public class FetchMovieDetailsTask extends AsyncTask<String, Void, String[]>{
public String LOG_TAG_SECOND=FetchMovieDetailsTask.class.getSimpleName();
#Override
protected String[] doInBackground(String... params) {
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
// Will contain the raw JSON response as a string.
String movieDetailJsonStr = "";
String filterType = "";
String api_key = "e77c4d231a4c24ffe0357b694751910c";
if (params[0].equals("Popularity")) {
filterType = "vote_average.desc";
} else if (params[0].equals("Rating")) {
filterType = "popularity.desc";
}
try {
final String MOVIEDETAIL_BASE_URL = "https://api.themoviedb.org/3/discover/movie?";
final String FILTER_PARAM = "sort_by";
final String APP_KEY_PARAM = "api_key";
Uri builtUri = Uri.parse(MOVIEDETAIL_BASE_URL).buildUpon()
.appendQueryParameter(FILTER_PARAM, filterType)
.appendQueryParameter(APP_KEY_PARAM, api_key).build();
URL url = new URL(builtUri.toString());
Log.v(LOG_TAG_SECOND, builtUri.toString());
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) {
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
}
movieDetailJsonStr = buffer.toString();
Log.v(LOG_TAG_SECOND, " Movie Details JSON " + movieDetailJsonStr);
try {
getMovieDetailsFromJSON(movieDetailJsonStr);
} catch (JSONException e) {
e.printStackTrace();
}
} catch (IOException e) {
Log.e(LOG_TAG, "Error ", e);
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);
}
}
}
return null;
}
private String[] getMovieDetailsFromJSON(String movieDetailsJSON) throws JSONException{
final String MOV_TITLE = "title";
final String MOV_OVERVIEW = "overview";
final String MOV_RATING = "vote_average";
final String MOV_POSTER_PATH = "poster_path";
final String MOV_LIST = "results";
JSONObject movieListJSON = new JSONObject(movieDetailsJSON);
JSONArray movieListArray = movieListJSON.getJSONArray(MOV_LIST);
int numOfMovies=8;
allImages.clear();
String[] resultStrs = new String[numOfMovies];
String[] resultPosters= new String[numOfMovies];
for(int i=0; i<numOfMovies; i++){
String title;
String overview;
String rating;
String poster_path;
JSONObject movieDetails=movieListArray.getJSONObject(i);
overview=movieDetails.getString(MOV_OVERVIEW);
title=movieDetails.getString(MOV_TITLE);
rating=movieDetails.getString(MOV_RATING);
poster_path=movieDetails.getString(MOV_POSTER_PATH);
resultStrs[i]=title + "\n" + overview + "\n" + rating + "\n" + poster_path;
resultPosters[i]=poster_path;
makePosterURL(resultPosters[i]);
}
for (String s : resultStrs) {
Log.v(LOG_TAG_SECOND, "MOVIE DETAILS: " + s);
}
return resultStrs;
}
private void makePosterURL(String resultPoster) {
String baseURL="http://image.tmdb.org/t/p/w500";
//resultPoster=resultPoster.replace("\\", "");
String finalURL="";
finalURL=baseURL+resultPoster;
Log.v(LOG_TAG_SECOND, "Final Poster URL " + finalURL);
allImages.add(finalURL);
}
#Override
protected void onPostExecute(String[] strings) {
if(strings!=null){
customAdapter=new CustomAdapter(getActivity(), allImages);
gv.invalidateViews();
gv.setAdapter(customAdapter);
}
// super.onPostExecute(strings);
}
}
Because you always return null in your doInBackground() so the code never resets your adapter with the updated lits. To update your updater you just need to call
adapter.notifyDataSetChanged();
in your onPostExecuted()
btw, your getMovieDetailsFromJSON() return type String[] is useless the same as doInBackgound() and you should make it void as you don't use the value.
Related
[EDIT: Was able to solve this by passing a blank image to the list array on fragment load]
I am working on an app where grid views are refreshed dynamically fetching data from API. My gridview is not refrishing on load. The refresh is happening on clicking other options (like sort) or by just changing orientation in the app. How do I get it to refresh on load. I have tried calling the refresh function from onStart(), onCreate() and onCreateView() but it isn't working.
Github: https://github.com/abhrajitmukherjee/PopularMovies
Main code:
public class MainActivityFragment extends Fragment {
private ImageAdapter mImageAdapter;
public ArrayList<String[]> mThumbIds;
private GridView gridview;
public MainActivityFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Add this line in order for this fragment to handle menu events.
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_fragment_main, menu);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.v("Initiate","Starts here-------------------");
updateMovieThumbs(getString(R.string.base_uri_popular));
gridview = (GridView) getActivity().findViewById(R.id.gridview);
mImageAdapter = new ImageAdapter(getActivity());
gridview.setAdapter(mImageAdapter);
updateMovieThumbs(getString(R.string.base_uri_popular));
gridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
Intent intent = new Intent(getActivity(), MovieDetailsActivity.class)
.putExtra(getString(R.string.intent_poster_path), mThumbIds.get(position)[0])
.putExtra(getString(R.string.intent_title),mThumbIds.get(position)[1])
.putExtra(getString(R.string.intent_overview),mThumbIds.get(position)[2])
.putExtra(getString(R.string.intent_vote_avg),mThumbIds.get(position)[3])
.putExtra(getString(R.string.intent_release_date),mThumbIds.get(position)[4]);
startActivity(intent);
}
});
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_toprated) {
updateMovieThumbs(getString(R.string.base_uri_toprated));
} else if (id == R.id.action_popular) {
updateMovieThumbs(getString(R.string.base_uri_popular));
}
return true;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_main, container, false);
mThumbIds = new ArrayList<String[]>();
return v;
}
#Override
public void onStart() {
super.onStart();
}
private void updateMovieThumbs(String sortType) {
FetchMovieDatabase movieTask = new FetchMovieDatabase();
movieTask.execute(sortType);
Log.v("getCount", "Get Main count=" + Integer.toString(mThumbIds.size()));
}
public class FetchMovieDatabase extends AsyncTask<String, Void, ArrayList<String[]>> {
private final String LOG_TAG = FetchMovieDatabase.class.getSimpleName();
private ArrayList<String[]> getMovieDataJson(String movieJsonStr)
throws JSONException {
final String RESULTS = "results";
final String ORIGINAL_TITLE="original_title";
final String POSTER="poster_path";
final String OVERVIEW="overview";
final String VOTES="vote_average";
final String RELEASE="release_date";
ArrayList<String[]> newThumbids=new ArrayList<String[]>();
JSONObject movieJson = new JSONObject(movieJsonStr);
JSONArray movieArray = movieJson.getJSONArray(RESULTS);
for (int i = 0; i < movieArray.length(); i++) {
JSONObject results = movieArray.getJSONObject(i);
String posterPath = getString(R.string.api_image_base_path)+results.getString(POSTER);
String title=results.getString(ORIGINAL_TITLE);
String overview=results.getString(OVERVIEW);
String voteAvg=results.getString(VOTES);
String releaseDate=results.getString(RELEASE);
String[] outputAttr={posterPath,title,overview,voteAvg,releaseDate};
Log.v(LOG_TAG, posterPath);
newThumbids.add(outputAttr);
Log.v(LOG_TAG, Integer.toString(newThumbids.size()));
}
return newThumbids;
}
#Override
protected ArrayList<String[]> doInBackground(String... params) {
if (params.length == 0) {
return null;
}
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
String movieJsonStr = null;
try {
final String BASE_URL = params[0];
final String API_KEY = "api_key";
Uri builtUri = Uri.parse(BASE_URL).buildUpon()
.appendQueryParameter(API_KEY, BuildConfig.MOVIES_API_KEY)
.build();
URL url = new URL(builtUri.toString());
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) {
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
return null;
}
movieJsonStr = buffer.toString();
} catch (IOException e) {
Log.e(LOG_TAG, "Error ", e);
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 getMovieDataJson(movieJsonStr);
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(ArrayList<String[]> result) {
if (result != null) {
if (mThumbIds.size()>0){
mThumbIds.clear();
}
mThumbIds = (ArrayList<String[]>) result.clone();
Log.v(LOG_TAG, "Postexecute count:"+Integer.toString( mThumbIds.size()));
mImageAdapter.notifyDataSetChanged();
}
}
}
public class ImageAdapter extends BaseAdapter {
private Context mContext;
public ImageAdapter(Context c) {
mContext = c;
}
public int getCount() {
Log.v("getCount", "Get Count=" + Integer.toString(mThumbIds.size()));
// return 5;
return mThumbIds.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) {
ImageView imageView;
if (convertView == null) {
// if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setAdjustViewBounds(true);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
} else {
imageView = (ImageView) convertView;
}
Picasso.with(getActivity()).load(mThumbIds.get(position)[0]).into(imageView);
return imageView;
}
}
}
The problem is i can't figure out why the grid won't filled with the images, the first time i run the app. If i do refresh or change to landscape mode the images load and the app works fine. I assume it has to be the List that i gave to the Adapter, somehow i lost his reference the first time and when the onCreateView calls again(refresh/landscape) it gets fixed. i tried to change the places where i define the adaptor, the list, etc and some methods too like setGridData but it doesn't work. Maybe you can help me
This is the code of the Fragment and the asynkTask(by the way it works fine).
public class MovieFragment extends Fragment {
private GridViewAdapter mGridViewAdapter;
private ArrayList<Movie> mMovieList = new ArrayList<Movie>();
public MovieFragment() {
}
#Override
public void onStart() {
super.onStart();
FetchMoviesTask movieTask = new FetchMoviesTask();
movieTask.execute("popular");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Add this line in order for this fragment to handle menu events.
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.moviefragment, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_refresh) {
FetchMoviesTask movieTask = new FetchMoviesTask();
movieTask.execute("popular");
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.moviefragment, container, false);
mGridViewAdapter = new GridViewAdapter(getActivity(),R.layout.movie_list_item, mMovieList);
GridView movieGrid= (GridView) rootView.findViewById(R.id.gridview_movie);
movieGrid.setAdapter(mGridViewAdapter);
return rootView;
}
public class FetchMoviesTask extends AsyncTask<String, Void, Movie[]> {
private final String LOG_TAG = FetchMoviesTask.class.getSimpleName();
private Movie[] getMoviesDataFromJson(String moviesJsonStr) throws JSONException{
final String OMDB_RESULTS="results";
final String OMBD_POSTER_PATH="poster_path";
final String OMBD_RELEASE_DATE="release_date";
final String OMBD_OVERVIEW="overview";
final String OMBD_ORIGINAL_TITLE="original_title";
final String OMBD_VOTE_AVERAGE="vote_average";
final String url= "http://image.tmdb.org/t/p/";
final String imageSize="w185";
JSONObject moviesJson = new JSONObject(moviesJsonStr);
JSONArray moviesArray = moviesJson.getJSONArray(OMDB_RESULTS);
Movie[] results = new Movie[moviesArray.length()];
//CUIDADO ACA NO SE SI SE PASA POR UNO
for (int i=0; i<moviesArray.length();i++){
JSONObject movie=moviesArray.getJSONObject(i);
Movie index=new Movie();
index.setPoster_path(url+imageSize+movie.getString(OMBD_POSTER_PATH));
index.setOriginalTitle(movie.getString(OMBD_ORIGINAL_TITLE));
index.setOverview(movie.getString(OMBD_OVERVIEW));
index.setReleaseDate(movie.getString(OMBD_RELEASE_DATE));
index.setVoteAverage(movie.getDouble(OMBD_VOTE_AVERAGE));
results[i]=index;
}
return results;
}
#Override
protected Movie[] doInBackground(String... params) {
Movie[] imageMovies;
// If there's no zip code, there's nothing to look up. Verify size of 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 moviesJsonStr = null;
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 =
"https://api.themoviedb.org/3/movie/"+params[0];
final String APPID_PARAM = "api_key";
Uri builtUri = Uri.parse(MOVIE_BASE_URL).buildUpon()
.appendQueryParameter(APPID_PARAM, BuildConfig.OPEN_MOVIEDB_API_KEY)
.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;
}
moviesJsonStr = buffer.toString();
imageMovies = getMoviesDataFromJson(moviesJsonStr);
} 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;
} catch (JSONException 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);
}
}
}
return imageMovies;
}
#Override
protected void onPostExecute(Movie[] movies) {
if(movies!=null){
mGridViewAdapter.setGridData(Arrays.asList(movies));
}
}
}
}
And this is the code of the Adapter:
public class GridViewAdapter extends ArrayAdapter {
private static final String LOG_TAG = GridViewAdapter.class.getSimpleName();
private Context mContext;
private int mLayoutResourceId;
private ArrayList<Movie> mGridData;
/**
* This is our own custom constructor (it doesn't mirror a superclass constructor).
* The context is used to inflate the layout file, and the List is the data we want
* to populate into the lists
*
* #param context The current context. Used to inflate the layout file.
* #param movieList A List of AndroidFlavor objects to display in a list
*/
public GridViewAdapter(Activity context, int layoutResourceId, ArrayList<Movie> movieList) {
// Here, we initialize the ArrayAdapter's internal storage for the context and the list.
// the second argument is used when the ArrayAdapter is populating a single TextView.
// Because this is a custom adapter for two TextViews and an ImageView, the adapter is not
// going to use this second argument, so it can be any value. Here, we used 0.
super(context, layoutResourceId, movieList);
mContext=context;
mLayoutResourceId=layoutResourceId;
mGridData=movieList;
}
/**
* Updates grid data and refresh grid items.
*/
public void setGridData(List<Movie> movies) {
mGridData.clear();
mGridData.addAll(movies);
notifyDataSetChanged();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
ImageView imageView;
if (row == null) {
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
row = inflater.inflate(mLayoutResourceId, parent, false);
imageView = (ImageView) row.findViewById(R.id.list_item_movie_imageview);
row.setTag(imageView);
} else {
imageView = (ImageView) row.getTag();
}
Movie movie = mGridData.get(position);
Picasso.with(mContext).load(movie.getPoster_path()).into(imageView);
Log.d(LOG_TAG,movie.getOriginalTitle());
return row;
}
}
The movie class is a simple class with the data. The log in the getView() method pop up only once in the first run, but it has to be 20 times.
I had a similar issue with this project as well. Try the following:
mGridViewAdapter.notifyDataSetChanged()
Currently. you're not calling it on any object. If that doesn't work, try this method instead:
mGridViewAdapter.notifyDataSetInvalidated()
Further reading: How to refresh Android listview?
I am taking an online course and making an android application for my self learning. In this application I want to show thumbnails of movie posters in a gridView. Now my question is how can I pass my movies arrayList to custom adapter from asyncTask. Is there something I can achieve in onPostExecute method. I mean how can I set data source for my adapter asynchronously in onPostExecute method of asyncTask?
here is my code.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FetchMovies mMovies = new FetchMovies(this);
mMovies.execute("popularity.desc");
GridView gridView= (GridView) findViewById(R.id.gridview);
gridView.setAdapter(new CustomAdapter(this,new ArrayList<MovieContract>()));
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
Toast.makeText(MainActivity.this, "" + position,
Toast.LENGTH_SHORT).show();
}
});
}}
public class CustomAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<MovieContract> movie_list;
public CustomAdapter(Context context, ArrayList<MovieContract> movie_list) {
mContext = context;
this.movie_list= movie_list;
}
#Override
public int getCount() {
return movie_list.size();
}
#Override
public MovieContract getItem(int position) {
return movie_list.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setPadding(8, 8, 8, 8);
Picasso.with(mContext).load("http://image.tmdb.org/t/p/w500/" + movie_list.get(position).getMovie_poster()).into(imageView);
} else {
imageView = (ImageView) convertView;
}
// imageView.setImageResource(mThumbIds[position]);
return imageView;
}}
public class FetchMovies extends AsyncTask<String,Void,ArrayList<MovieContract>> {
private CustomAdapter customAdapter;
private Context context;
private ArrayList<MovieContract> mMovie_list = new ArrayList<>();
private MovieContract mMovieContract;
private String poster_path;
public final String LOG_Tag=FetchMovies.class.getSimpleName();
public FetchMovies(Context context) {
this.context = context;
}
#Override
protected ArrayList doInBackground(String[] params) {
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
String MoviesJsonStr = null;
String Api_key= "xxxxxxxxxxxxxxxxxxxxxx";
try {
final String Movies_base="http://api.themoviedb.org/3/discover/movie?";
final String Sort_param="sort_by";
final String ApiKey_param="api_key";
final String Image_Size="w500";
Uri MovieUriBuilder=Uri.parse(Movies_base).buildUpon()
.appendQueryParameter(Sort_param,params[0])
.appendQueryParameter(ApiKey_param, Api_key)
.build();
Log.v(LOG_Tag, "URI Builder" + MovieUriBuilder.toString());
URL url= new URL(MovieUriBuilder.toString());
urlConnection=(HttpURLConnection)url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream inputStream= urlConnection.getInputStream();
StringBuffer buffer= new StringBuffer();
if(inputStream==null){
MoviesJsonStr=null;
}
reader= new BufferedReader(new InputStreamReader(inputStream));
String Result;
while ((Result=reader.readLine())!=null){
buffer.append(Result + '\n');
}
if (buffer.length() == 0) {
MoviesJsonStr = null;
}
MoviesJsonStr = buffer.toString();
Log.v(LOG_Tag,"Forecast Jason String " + MoviesJsonStr);
}
catch (IOException e){
Log.e("FetchMovies", "Error ", e);
MoviesJsonStr=null;
}
finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("PlaceholderFragment", "Error closing stream", e);
}
}
}
try {
return ParseMoviesJsonString(MoviesJsonStr);
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
private ArrayList<MovieContract> ParseMoviesJsonString(String movieJsonStr ) throws JSONException{
final String json_result="results";
final String json_poster_path="poster_path";
final String json_original_title="original_title";
final String json_title="title";
final String json_releaseDate="release_date";
final String json_overview="overview";
final String json_vote_average="vote_average";
ArrayList<MovieContract> movie_list= new ArrayList<>();
JSONObject MovieJson = new JSONObject(movieJsonStr);
JSONArray MovieArray = MovieJson.getJSONArray(json_result);
String[] resultStrs = new String[MovieArray.length()];
for(int i = 0; i < MovieArray.length(); i++) {
//JSONObject Movieobject = MovieArray.getJSONObject(i);
JSONObject result_movie=MovieArray.getJSONObject(i);
MovieContract movie = new MovieContract();
movie.setTitle(result_movie.getString(json_original_title));
movie.setMovie_poster(result_movie.getString(json_poster_path));
movie.setPlot_synopsis(result_movie.getString(json_overview));
movie.setRelease_date(result_movie.getString(json_releaseDate));
movie.setVote_average(result_movie.getString(json_vote_average));
movie_list.add(movie);
}
for (MovieContract result : movie_list){
Log.v(LOG_Tag," preparing data " + result.getMovie_poster() + " " +result.getPlot_synopsis() );
}
return movie_list;
}
#Override
protected void onPostExecute(ArrayList<MovieContract> Movie_list) {
}}
Declare a your CustomAdapter as an instance variable in the activity:
private CustomAdapter customAdapter;
Create the Adapter and set the RecyclerView adapter this way:
customAdapter = new CustomAdapter(this,new ArrayList<MovieContract>());
gridView.setAdapter(customAdapter);
Create an update data method for your CustomAdapter:
public void updateMovies(ArrayList<MovieContract> movie_list) {
this.movie_list= movie_list;
}
Then in onPostExecute:
customAdapter.updateMovies(movie_list);
customAdapter.notifyDataSetChanged();
I always do this to make async task more usable
create an Object in your async task class
OnResult onresult;
in your Async task create an interface
public interface OnResult{
public void onfinishprogress(ArrayList<> resultlist);
}
//create a method in async task
public void setOnResult(OnResult onresult)
{
this.onresult=onresult;
}
in your onPostExecute(..) set the result
onPostExecute(ArrayList<MovieContract> Movie_list){
if(this.onresult!=null)
this.onresult.onfinishprogress(Movie_list);
}
now come how to get the result in MainActivity
FetchMovies fmv=FetchMovies();
fmv.execute(url);
//now get the result from the interface created above
fmv.setOnResult(new OnResult(){
onfinishprogress(ArrayList<> resultlist)
{
//here you get the resultlist which you passed up there.
gridView.setAdapter(customAdapter);
}
});
I am building this movie app that displays movies in a gridview on the main panel, then I can click them and display some information about that movie, also I have some settings to change the criteria of the movies displayed: popular, top rated or favorites. The favorites are a local collection saved in sharedPreferences chosen by the user.
Here is where it all happens:
public class MovieFragment extends Fragment{
public String[][] matrixMoviesInfo;
public GridView gridView;
public String[] mArrayImages;
private String baseUrl;
private String apiKey;
public MovieFragment(){
matrixMoviesInfo = new String[20][10];
mArrayImages = new String[20];
baseUrl = "http://api.themoviedb.org/3/movie/";
apiKey = "?api_key=37068e0a72b2cc1751b4246899923ba7";
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
#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);
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
Intent intent = new Intent(getActivity(), DetailActivity.class)
.putExtra(Intent.EXTRA_TEXT, matrixMoviesInfo[position]);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
});
return rootView;
}
private void setImages() {
for(int i=0;i<mArrayImages.length;i++){
if(matrixMoviesInfo[i][0]!=null) {
mArrayImages[i] = matrixMoviesInfo[i][0];
}
}
gridView.setAdapter(null);
gridView.setAdapter(new ImageAdapter(getActivity(), mArrayImages));
Log.v(null, "SETIMAGESCALLED");
}
private void updateMovies() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
String preference = prefs.getString(getString(R.string.pref_sortby_key), getString(R.string.pref_sortby_default));
if(preference.toLowerCase().equals("favorites")){
SharedPreferences preferences = getContext().getSharedPreferences("favorites_list", Context.MODE_PRIVATE);
Map<String, ?> allEntries = preferences.getAll();
String[] keyNames = new String[allEntries.size()];
Log.v(null,"SIZE: "+allEntries.size());
String[] keyValues;
int iterator=0;
for (Map.Entry<String, ?> entry : allEntries.entrySet()) {
Log.v("KEY: " +entry.getKey(), "VALUE: "+entry.getValue().toString());
}
for (Map.Entry<String, ?> entry : allEntries.entrySet()) {
if(entry.getKey()!=null) {
keyNames[iterator] = entry.getKey();
keyValues = entry.getValue().toString().split("#");
for (int i = 0; i < 10; i++) {
Log.v("INDEX: " + i, " VALUES: " + keyValues[i]);
matrixMoviesInfo[iterator][i] = keyValues[i];
}
iterator++;
}
}
setImages();
}else{
Log.v(null,"EXECUTETASK");
new FetchMoviesTask().execute(baseUrl+preference.toLowerCase()+apiKey, "i");
}
}
#Override
public void onStart() {
super.onStart();
updateMovies();
}
public class FetchMoviesTask extends AsyncTask<String, String, Void> {
private final String LOG_TAG = FetchMoviesTask.class.getSimpleName();
private Void getMovieDetailsFromJson(String movieJSONstr) throws JSONException {
final String OWM_RESULTS = "results";
final String OWM_ID = "id";
final String OWM_POSTERPATH = "poster_path";
final String OWM_TITLE = "original_title";
final String OWM_OVERVIEW = "overview";
final String OWM_USERRATING = "vote_average";
final String OWM_RELEASEDATE = "release_date";
JSONObject movieJson = new JSONObject(movieJSONstr);
JSONArray movieArray = movieJson.getJSONArray(OWM_RESULTS);
for(int i = 0; i < movieArray.length(); i++) {
JSONObject movieObj = movieArray.getJSONObject(i);
matrixMoviesInfo[i][0] = movieObj.getString(OWM_POSTERPATH);
matrixMoviesInfo[i][1] = movieObj.getString(OWM_ID);
matrixMoviesInfo[i][2] = movieObj.getString(OWM_TITLE);
matrixMoviesInfo[i][3] = movieObj.getString(OWM_OVERVIEW);
matrixMoviesInfo[i][4] = movieObj.getString(OWM_USERRATING);
matrixMoviesInfo[i][5] = movieObj.getString(OWM_RELEASEDATE);
}
for(int i=0;i<20;i++) {
new FetchMoviesTask().execute(baseUrl + matrixMoviesInfo[i][1] + "/reviews" + apiKey, Integer.toString(i));
new FetchMoviesTask().execute(baseUrl + matrixMoviesInfo[i][1] + "/videos" + apiKey, "v");
}
Log.v(null,"GETMOVIEDETAILS");
return null;
}
private Void getMovieReviewsFromJson(String movieJSONstr, String position) throws JSONException{
int pos = Integer.parseInt(position);
final String OWM_RESULTS = "results";
final String OWM_AUTHOR = "author";
final String OWM_CONTENT = "content";
final String OWM_TOTALRESULTS = "total_results";
JSONObject movieJson = new JSONObject(movieJSONstr);
JSONArray movieArray = movieJson.getJSONArray(OWM_RESULTS);
int numberOfResults = Integer.parseInt(movieJson.getString(OWM_TOTALRESULTS));
if(numberOfResults >= 1) {
matrixMoviesInfo[pos][6] = movieArray.getJSONObject(0).getString(OWM_AUTHOR);
matrixMoviesInfo[pos][7] = movieArray.getJSONObject(0).getString(OWM_CONTENT);
}
if(numberOfResults > 1) {
matrixMoviesInfo[pos][8] = movieArray.getJSONObject(1).getString(OWM_AUTHOR);
matrixMoviesInfo[pos][9] = movieArray.getJSONObject(1).getString(OWM_CONTENT);
}
return null;
}
private Void getMovieVideosFromJson(String movieJSONstr){
return null;
}
#Override
protected Void doInBackground(String... params) {
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
String movieJSONstr = null;
try{
URL url = new URL(params[0]);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if(inputStream == null){
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while((line = reader.readLine()) != null){
buffer.append(line + "\n");
}
if(buffer.length() == 0){
movieJSONstr = null;
}
movieJSONstr = buffer.toString();
} catch (IOException e) {
Log.e(LOG_TAG, "Error ", e);
return null;
} finally{
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("MovieFragment", "Error closing stream", e);
}
}
}
try{
if(params[1].equals("i")){
Log.v(null,"EXECUTEGETMOVIEDETAILS");
return getMovieDetailsFromJson(movieJSONstr);
}
else {
if (params[1].equals("v")){
return getMovieVideosFromJson(movieJSONstr);}
else{
return getMovieReviewsFromJson(movieJSONstr, params[1]);}
}
}catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
String[] mArrayImages = new String[20];
for(int i=0;i<20;i++){
mArrayImages[i] = matrixMoviesInfo[i][0];
}
gridView.setAdapter(new ImageAdapter(getActivity(), mArrayImages));
Log.v(null, "IMAGES SET GRIDVIEW REFRESHED");
}
}
Class Explanation:
There is 2 paths:
Popular or TopRated: starts on method UpdateMovies, then executes the asynctask to fetch data from the api, followed by the execution of the getMoviesFromJson that extracts all the information related to all movies. Then it ends on onPostExecute that populates the gridview with the ImageAdapter.
Favorites: starts on method UpdateMovies, here it fetchs the data from sharedpreferences and populates the array with that data, then it calls the method setImages to populate the gridView with the ImageAdapter.
Here is my problem: when I am displaying the popular movies and change the setting to favorites, it displays the right movies on the sharedpreferences but it is not "cleaning" the remaining ones from the gridview.
Also how can I adjust the scroll of the gridview to match the cells it has (when there is no movie to populate a cell, I hide it like this:
imageView.setVisibility(View.GONE);
Make an Adapter for the gridview that extends from BaseAdapter, or use an Adapter that extends from BaseAdapter.
then call notifyDataSetChanged on that adapter when the contents of your collection has changed.
I seem to have a problem with my ImageAdapter. It should update a GridView but does not do it.
Code:
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>
The strange thing is that when I add a ArrayList with elements when I create my ImageAdapter in onCreateView, it does work but when I leave that list unpopulated it does not update.
Anyone got any clue what to do?
Been searching for the solution the whole day now. :D
Thanks in advance.
I have weird impression that something is wrong with your getView() method - I can be wrong but try this one:
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;
}
Moreover this comment - create a new ImageView for each item referenced by the Adapter is invalid because adapter reuse views, which are outside of the screen, so sometimes instead of creating new instance of ImageView, list displays old one with new data
Edit
Try to create new data list instead of cleaning old one:
public void updatePosters(ArrayList<Movie> newMovies) {
data = new ArrayList<Movies>();
data.addAll(newMovies);
this.notifyDataSetChanged();
}
You getView is not correctly implemented. Firs of all it is very weird what you are trying to achieve there, you are inflating something just to get an ImageView from that layout. You could instead instantiate the ImageView inside the method:
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;
}