I've a fragment which is called from the MainActivity. And this Fragment fetches a JSON file of image URL's and displays images on the screen.
I've used Fresco library to download these images and then pop as a image list view. The images are automatically cached by the Fresco Library.
I want to remove all cached images when I perform a back press from the Fragment.
The images are immediately uncached as the user scrolls down the list and I want to uncache all images when user performs a backPress in the Fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_gallery, container, false);
private List<gallery_adapter> gallery_adapterList = new ArrayList<>();
ListView list = (ListView) view.findViewById(R.id.galleryList);
gallery_adapterList.clear();
if(isNetworkConnected()){
new galleryImages().execute("http://www.myurl.json");
}else
Toast.makeText(context,"No Internet Connection!",Toast.LENGTH_SHORT).show();
return view;
}
public class galleryImages extends AsyncTask<String, String, String> {
HttpURLConnection connection;
BufferedReader reader;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
try {
URL url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
String str = builder.toString();
return str;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if(s!=null){
try {
JSONObject parent = new JSONObject(s);
JSONArray images = parent.getJSONArray("images");
if(images!=null){
for(int i=0; i<images.length();i++){
JSONObject child = images.getJSONObject(i);
gallery_adapterList.add(new gallery_adapter(child.getString("url"),child.getString("text")));
}
displayList();
}else
Toast.makeText(context,"error",Toast.LENGTH_SHORT).show();
} catch (JSONException e) {
Toast.makeText(context, "Images not yet added. Try later",Toast.LENGTH_SHORT).show();
}
}else
Toast.makeText(context, "Images not yet added. Try later",Toast.LENGTH_SHORT).show();
}
}
Display list method
private void displayList() {
ArrayAdapter<gallery_adapter> adapter = new galleryAdapterList();
list.setAdapter(adapter);
}
public class galleryAdapterList extends ArrayAdapter<gallery_adapter> {
galleryAdapterList() {
super(context, R.layout.gallery_item, gallery_adapterList);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.gallery_item, parent, false);
}
gallery_adapter current = gallery_adapterList.get(position);
TextView mText=(TextView) convertView.findViewById(R.id.galleryText);
mText.setText(current.getText());
uri = Uri.parse(current.getUrl());
//code to remove images from cache
ImagePipeline imagePipeline = Fresco.getImagePipeline();
imagePipeline.evictFromCache(uri);
//code ends here
SimpleDraweeView mImage = (SimpleDraweeView) convertView.findViewById(R.id.galleryImage);
mImage.setImageURI(uri);
return convertView;
}
}
I think what you was it's this however if I may why do you want to clear the cache? Because the next time the user opens the activity he needs to wait for the json response again
Below are option that you can do so:
1.You can cache backpress event in Fragment and call your function to clear cache images ,Handle Back Press.
2.Track Fragment by it's onAttach(Context) , Mean while you need to write FragmentManager.addOnBackStackChangedListener(); it will be called if you have added your fragment with addtoBackStack .
Related
hi guys i want to sent location name and some other string values to the server...i am new in android so i dont know much about it....i pass the location and other values with url...url hits but the values are not receive by the server..help please me out...
public class SearchResult extends AppCompatActivity {
private ListView lvSearch;
private ProgressDialog dialog;
private final String URL_TO_HIT = "http://www.abcd.com/mobile_search.php";
private String location = "bathinda";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search_result);
setContentView(R.layout.activity_search_result);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle("Search Result");
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onBackPressed();
}
});
dialog = new ProgressDialog(this);
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.setMessage("Loading. Please wait...");
// Create default options which will be used for every
// displayImage(...) call if no options will be passed to this method
DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(true)
.build();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
.defaultDisplayImageOptions(defaultOptions)
.build();
ImageLoader.getInstance().init(config); // Do it on Application start
lvSearch = (ListView)findViewById(R.id.lvSearch);
Bundle bundle = getIntent().getExtras();
String bar = bundle.getString("bar");
String nights = bundle.getString("nights");
String nearby = bundle.getString("nearby");
String deals = bundle.getString("deals");
// To start fetching the data when app start, uncomment below line to start the async task.
new JSONTask().execute(URL_TO_HIT, location, bar, nights, nearby, deals );
}
public class JSONTask extends AsyncTask<String,String, List<SearchData> >{
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog.show();
}
#Override
protected List<SearchData> doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line ="";
while ((line = reader.readLine()) != null){
buffer.append(line);
}
String finalJson = buffer.toString();
JSONObject parentObject = new JSONObject(finalJson);
JSONArray parentArray = parentObject.getJSONArray("search");
List<SearchData> searchDataList = new ArrayList<>();
Gson gson = new Gson();
for(int i=0; i<parentArray.length(); i++) {
JSONObject finalObject = parentArray.getJSONObject(i);
/**
* below single line of code from Gson saves you from writing the json parsing yourself which is commented below
*/
SearchData searchData = gson.fromJson(finalObject.toString(), SearchData.class);
searchDataList.add(searchData);
}
return searchDataList;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
} finally {
if(connection != null) {
connection.disconnect();
}
try {
if(reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(final List<SearchData> result) {
super.onPostExecute(result);
dialog.dismiss();
if(result != null) {
SearchAdapter adapter = new SearchAdapter(getApplicationContext(), R.layout.searchresultrow, result);
lvSearch.setAdapter(adapter);
} else {
Toast.makeText(getApplicationContext(), "Not able to fetch data from server, please check internet", Toast.LENGTH_SHORT).show();
}
}
}
public class SearchAdapter extends ArrayAdapter{
private List<SearchData> searchDataList;
private int resource;
private LayoutInflater inflater;
public SearchAdapter(Context context, int resource, List<SearchData> objects) {
super(context, resource, objects);
searchDataList = objects;
this.resource = resource;
inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if(convertView == null){
holder = new ViewHolder();
convertView = inflater.inflate(resource, null);
holder.searchimg11 = (ImageView)convertView.findViewById(R.id.searchimg1);
holder.barname1 = (TextView)convertView.findViewById(R.id.barname);
holder.address1 = (TextView)convertView.findViewById(R.id.address);
holder.offer1 = (TextView)convertView.findViewById(R.id.offer);
holder.hourtext1 = (TextView)convertView.findViewById(R.id.hourtext);
holder.coststext1 = (TextView)convertView.findViewById(R.id.coststext);
holder.textv11 = (TextView)convertView.findViewById(R.id.textv1);
holder.featuredtext1 = (TextView)convertView.findViewById(R.id.featuredtext);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
//final ProgressBar progressBar = (ProgressBar)convertView.findViewById(R.id.progressBar);
// Then later, when you want to display image
ImageLoader.getInstance().displayImage(searchDataList.get(position).getBar_image(), holder.searchimg11, new ImageLoadingListener() {
#Override
public void onLoadingStarted(String imageUri, View view) {
// progressBar.setVisibility(View.VISIBLE);
}
#Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
//progressBar.setVisibility(View.GONE);
}
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
// progressBar.setVisibility(View.GONE);
}
#Override
public void onLoadingCancelled(String imageUri, View view) {
// progressBar.setVisibility(View.GONE);
}
});
holder.barname1.setText(searchDataList.get(position).getBarname());
holder.address1.setText(searchDataList.get(position).getLocation());
holder.offer1.setText( searchDataList.get(position).getOffers());
holder.hourtext1.setText( searchDataList.get(position).getOpen_hours());
holder.coststext1.setText(searchDataList.get(position).getCost_for_two());
holder.textv11.setText(searchDataList.get(position).getFreebe());
holder.featuredtext1.setText(searchDataList.get(position).getFeaured());
return convertView;
}
class ViewHolder{
private ImageView searchimg11;
private TextView address1;
private TextView offer1;
private TextView hourtext1;
private TextView coststext1;
private TextView textv11;
private TextView barname1;
private TextView featuredtext1;
}
}
}
You are not passing any parameters to the server there . You are calling URL without any parameters
Read this solution to know how to pass parameters to HttpURLConnection using POST
How to add parameters to HttpURLConnection using POST
I did not go through your code. I suggest you to use the library to do much of the work instead of you developing on top of HTTP stack.
Use Retrofit(http://square.github.io/retrofit/) or Volley(https://developer.android.com/training/volley/index.html).
Retrofit is easy to use and manage but volley give you lot of control. Since you are new to programming on the client side, I suggest you use the Retrofit. You can't go wrong with sending JSON data, and few post using this libraries.
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 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.
I am working on an app which performs (in an AsyncTask) a query to a remote server obtaining a JSON string.
To show the data on my ListView i have extended an ArrayAdapter.
When i execute my app, from the LogCat i can see that data is retrieved correctly but not shown in the ListView.
The only way i have to make everything work (and data be shown on the ListView) is by running the app in Debug mode, set a breakpoint on the line
myListView.setAdapter(myAdapter);
wait for a couple seconds and then resume the application.
After this procedure, everything works correctly.
Why is this happening?
Is the AsyncTask the right way for such a long operation, or should I use some other approach (but i don't know which one!).
Here is the MainActivity code
public class MainActivityFragment extends Fragment {
private List<Station> stationList = new ArrayList<Station>();
private StationAdapter stationsAdapter;
private ProgressDialog pd;
private String LOG_TAG = "ProvaAsyncTask";
public MainActivityFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
mioAsync mioTask = new mioAsync();
mioTask.execute();
stationsAdapter = new StationAdapter(stationList, getActivity());
ListView stationsListView = (ListView) rootView.findViewById(R.id.miaListView);
stationsListView.setAdapter(stationsAdapter);
return rootView;
}
public class mioAsync extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Creo la ProgressDialog che precede il caricamento dei dati
pd = new ProgressDialog(getActivity());
pd.setMessage(MainActivityFragment.this.getString(R.string.preloader_stations_list));
pd.show();
}
#Override
protected Void doInBackground(Void... params) {
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
String forecastJsonStr = null;
try {
URL url = new URL("*remoteserver*");
// Create the request to the server, 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) {
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
}
forecastJsonStr = 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{
getStationsListFromJson(forecastJsonStr);
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
pd.dismiss();
}
private void getStationsListFromJson(String stationsJsonStr) throws JSONException {
JSONArray stationsArray = new JSONArray(stationsJsonStr);
String nomeStaz;
String numSat;
stationList.clear();
for (int i = 0; i < stationsArray.length(); i++) {
JSONObject j = stationsArray.optJSONObject(i);
Iterator it = j.keys();
while (it.hasNext()) {
String n = it.next().toString();
numSat = j.getString(n) + " stazioni";
n = it.next().toString();
nomeStaz = j.getString(n);
stationList.add(new Station(nomeStaz, numSat));
}
}
}
}
}
The JSON string i get in return is like this
[{"nome":"Station1","satelliti":"11"},{"nome":"Station2","satelliti":"9"},{"nome":"Station3","satelliti":"8"}]
Here is where i extend the ArrayList
public class StationAdapter extends ArrayAdapter<Station> {
private List<Station> stationsList;
private Context context;
public StationAdapter(List<Station> lista, Context cont){
super(cont, R.layout.listitems, lista);
this.stationsList = lista;
this.context = cont;
}
public int getCount() {
return stationsList.size();
}
public Station getItem(int position) {
return stationsList.get(position);
}
public long getItemId(int position) {
return stationsList.get(position).hashCode();
}
public View getView(int position, View convertView, ViewGroup parent){
View v = convertView;
StationHolder holder = new StationHolder();
// controllo che il convertview non sia null
if (convertView == null){
// This a new view we inflate the new layout
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.listitems, null);
// Now we can fill the layout with the right values
TextView stationName = (TextView) v.findViewById(R.id.testataUno);
TextView satellitesNumber = (TextView) v.findViewById(R.id.testataDue);
holder.stationNameView = stationName;
holder.satellitesNumberView = satellitesNumber;
v.setTag(holder);
} else {
holder = (StationHolder) v.getTag();
}
Station p = stationsList.get(position);
holder.stationNameView.setText(p.getName());
holder.satellitesNumberView.setText("" + p.getSatellites());
return v;
}
/* *********************************
* We use the holder pattern
* It makes the view faster and avoid finding the component
* **********************************/
private static class StationHolder {
public TextView stationNameView;
public TextView satellitesNumberView;
}
}
Here is the Station code
public class Station {
private String name;
private String satellites;
public Station(String nome, String satelliti){
this.name = nome;
this.satellites = satelliti;
}
public String getName(){
return this.name;
}
public String getSatellites(){
return this.satellites;
}
public void setName(String nome){
this.name = nome;
}
public void setSatellites(String satelliti){
this.satellites = satelliti;
}
}
You got the flow broken. It works in debug mode only because you stop execution of UI thread on your breakpoint, but line before your breakpoint you fired AsyncTask, and as this is not stopped, it downloads the data while you enjoy your breakpoint. You most likely assumed that AsyncTask (which is abbreviation of Asynchronous Task) is... well... synchronous. It's not. Your main code will not wait for asynctask,it will start it and continue. You need to rework your code and in asynctask's onPostExecute() method update your dataset based on downloaded content and then call notifyDatasetChanged() on your list's adapter. That should trigger list refresh.
I need to delete a list item from listview on clicking a delete button in android eclipse. The list values are populated from mysql database(JSON), so on deleting, I need to delete the same from database also.
Here is my main Activity; I need to delete a listitem from a listview on clicking a delete button on each item in the listview:
public class MainActivity extends Activity implements AsyncResponse2 {
private ProgressDialog dialog;
ListView l1;
//for getting count
TextView count;
private static final String TAG_COUNT = "cnt";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE); //to hide title bar
setContentView(R.layout.activity_main);
l1=(ListView)findViewById(R.id.listView1);
/** Reference to the delete button of the layout main.xml */
Button btnDel = (Button) findViewById(R.id.deleteid);
initView();
//str for getting count
count=(TextView)findViewById(R.id.countid);
//to display count while loading(so outside buttonclick)
String key1 = "saasvaap123";
String signupid1 = "8";
String url2 = "http://gooffers.in/omowebservices/index.php/webservice/Public_User/saved_offers_list?";
//http://gooffers.in/omowebservices/index.php/webservice/Public_User/saved_offers_list?key=saasvaap123&signup_id=8
//put the below lines outside button onclick since we load the values into edittext when opening the app
CustomHttpClient2 task2 = new CustomHttpClient2();
task2.execute(url2,key1,signupid1);
task2.delegate = MainActivity.this;
//end
}
//str getting count
//str customhttp2
private class CustomHttpClient2 extends AsyncTask<String, String, String>{
public AsyncResponse2 delegate=null;
private String msg;
#Override
protected void onPostExecute(String result2) {
// TODO Auto-generated method stub
super.onPostExecute(result2);
delegate.processFinish2(result2);
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
if(params == null) return null;
// get url from params
String url2 = params[0];
String key1 = params[1];
String signupid1 = params[2];
ArrayList<NameValuePair> postParameters;
postParameters = new ArrayList<NameValuePair>();
postParameters.add(new BasicNameValuePair("key",key1));
postParameters.add(new BasicNameValuePair("signup_id",signupid1));
try {
// create http connection
HttpClient client = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url2);
httppost.setEntity(new UrlEncodedFormEntity(postParameters));
// connect
HttpResponse response = client.execute(httppost);
// get response
HttpEntity entity = response.getEntity();
if(entity != null){
return EntityUtils.toString(entity);
}
else{
return "No string.";
}
}
catch(Exception e){
return "Network problem";
}
}
}
public void processFinish2 (String output2){
Toast.makeText(MainActivity.this,output2, Toast.LENGTH_SHORT).show();
try{
//str
JSONObject jsonResponse = new JSONObject(output2);
JSONArray aJson = jsonResponse.getJSONArray("gen_off");
// create apps list
for(int i=0; i<aJson.length(); i++) {
JSONObject json = aJson.getJSONObject(i);
//end
//str
String strCount = json.getString(TAG_COUNT);
count.setText(strCount);//setting name to original name text
//end
}
}catch (JSONException e) {
Toast.makeText(MainActivity.this,"Exception caught!", Toast.LENGTH_SHORT).show();
}
}
//end getting count
private void initView() {
// show progress dialog
// dialog = ProgressDialog.show(this, "", "Loading...");
String key="saasvaap123";
String signup_id="8";
String url = "http://gooffers.in/omowebservices/index.php/webservice/Public_User/saved_offers_list?";
FetchDataTask task = new FetchDataTask();
task.execute(url,key,signup_id);
}
public class FetchDataTask extends AsyncTask<String, Void, String>{
// private final FetchDataListener listener;
private String msg;
#Override
protected String doInBackground(String... params) {
if(params == null) return null;
// get url from params
String url = params[0];
String key1 = params[1];
String signupid1 = params[2];
ArrayList<NameValuePair> postParameters;
postParameters = new ArrayList<NameValuePair>();
postParameters.add(new BasicNameValuePair("key",key1));
postParameters.add(new BasicNameValuePair("signup_id",signupid1));
//str
try {
// create http connection
HttpClient client = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
httppost.setEntity(new UrlEncodedFormEntity(postParameters));
// connect
HttpResponse response = client.execute(httppost);
// get response
HttpEntity entity = response.getEntity();
if(entity != null){
return EntityUtils.toString(entity);
}
else{
return "No string.";
}
}
catch(Exception e){
return "Network problem";
}
}
//end
//
#Override
protected void onPostExecute(String sJson) {
try {
JSONObject jsonResponse = new JSONObject(sJson);
JSONArray aJson = jsonResponse.getJSONArray("gen_off");
Toast.makeText(MainActivity.this, aJson.toString(),Toast.LENGTH_SHORT).show();
// create apps list
List<SavedOffers> apps = new ArrayList<SavedOffers>();
for(int i=0; i<aJson.length(); i++) {
JSONObject json = aJson.getJSONObject(i);
SavedOffers app = new SavedOffers();
app.setTitle(json.getString("title"));
app.setOriginalRate(json.getString("price"));
app.setOfferRate(json.getString("off_price"));
app.setPercentage(json.getString("percent"));
app.setSavings(json.getString("savings"));
app.setUrl(json.getString("image"));
// add the app to apps list
apps.add(app);
}
SavedOffersAdapter adapter = new SavedOffersAdapter(MainActivity.this, apps);
// set the adapter to list
l1.setAdapter(adapter);
//for delete
// adapter.notifyDataSetChanged();
/** Defining a click event listener for the button "Delete" */
Button btnDel = (Button) findViewById(R.id.deleteid);
OnClickListener listenerDel = new OnClickListener() {
#Override
public void onClick(View v) {
/** Getting the checked items from the listview */
SparseBooleanArray checkedItemPositions = l1.getCheckedItemPositions();
int itemCount = l1.getCount();
for(int i=itemCount-1; i >= 0; i--){
if(checkedItemPositions.get(i)){
adapter.remove(l1.get(i));
}
}
checkedItemPositions.clear();
adapter.notifyDataSetChanged();
}
};
/** Setting the event listener for the delete button */
btnDel.setOnClickListener(listenerDel);
/** Setting the adapter to the ListView */
l1.setAdapter(adapter); //end delete
//notify the activity that fetch data has been complete
// if(listener != null) listener.onFetchComplete(apps);
} catch (JSONException e) {
// msg = "Invalid response";
// if(listener != null) listener.onFetchFailure(msg);
// return;
}
}
/**
* This function will convert response stream into json string
* #param is respons string
* #return json string
* #throws IOException
*/
public String streamToString(final InputStream is) throws IOException{
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
}
catch (IOException e) {
throw e;
}
finally {
try {
is.close();
}
catch (IOException e) {
throw e;
}
}
return sb.toString();
}
}
}
// this is my adapter class , I think change is only needed in main activity
// , I need to delete a specific list item from listview on clicking the delete button
public class SavedOffersAdapter extends ArrayAdapter<SavedOffers>{
private List<SavedOffers> items;
Bitmap bitmap;
ImageView image;
public SavedOffersAdapter(Context context, List<SavedOffers> items) {
super(context, R.layout.app_custom_list, items);
this.items = items;
}
#Override
public int getCount() {
return items.size();
}
private class ViewHolder {
//TextView laptopTxt;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// ViewHolder holder;//added
View v = convertView;
if(v == null) {
LayoutInflater li = LayoutInflater.from(getContext());
v = li.inflate(R.layout.app_custom_list, null);
}
SavedOffers app = items.get(position);
if(app != null) {
TextView productName = (TextView)v.findViewById(R.id.nameid);
TextView originalRate = (TextView)v.findViewById(R.id.originalid);
originalRate.setPaintFlags(originalRate.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
TextView offerRate = (TextView)v.findViewById(R.id.offerid);
TextView percentage = (TextView)v.findViewById(R.id.discountid);
TextView savings = (TextView)v.findViewById(R.id.savingsid);
image =(ImageView)v.findViewById(R.id.prctimgid);
if(productName != null) productName.setText(app.getTitle());
if(originalRate != null) originalRate.setText(app.getOriginalRate());
if(offerRate != null) offerRate.setText(app. getOfferRate());
if(percentage != null) percentage.setText(app. getPercentage());
if(savings != null) savings.setText(app. getSavings());
if(image!=null){
new DownloadImageTask(image).execute(app.getUrl());
}
}
return v;
}
In your listviews adapter's getView method you link to the button on the layout your inflating and just attach a setOnClickListener... to the button and have it remove that item from your list or array that your adapter uses and then notifyDataHasChanged.
Delete that item from items in that position.
So 1. you want to delete the item from the ListView
2. you want to delete the item from the SQL DB.
The first one is very easy, but you kind of need to know the underlining adapter and how it serves data to your ListView. When you instantiate a BaseAdapter for the ListView you pass in a List or an array. This array will be the data your BaseAdapter serves to your ListView, each view in the listview will be showing an element from the array (done in getView()). If you dynamically delete one of those items, then adjust your array (or just use a List and it's .remove(), and finally notifyDataSetChanged(); your BaseAdapter will refresh your list without that View (or rather that View will be replaced with the new one). So for instance below I pass in a List<WeatherLocation> (WeatherLocation is a containing class that has weather stuff for a particular area (city, zipcode, degree"Biddeford", 04005, 72) to my BaseAdapter.
// Instantiate ListView
ListView lvLocations = (ListView) findViewById(R.id.lvLocations);
// Instantiate our BaseAdapter (pass in the List<WeatherLocation>)
WeatherLocationAdapter mWeatherLocationAdapter = new WeatherLocationAdapter(savedList, this, R.layout.view_weather_location);
lvLocations.setAdapter(mWeatherLocationAdapter);
This is an example of a regular ListView setting an Adapter to a custom BaseAdapter.
The BaseAdapter is so simple, that really the only method you care about (majorly) is the getView() method.
R.layout.view_weather_location is just a `LinearLayout` I made, it has 3 TextViews in it that I tie (show) my data with, by attaching data to those TextViews in the `getView()` method of the `BaseAdapter`. You would put a `Button there and tie it to what you want (to delete the data item)`.
public class WeatherLocationAdapter extends BaseAdapter{
private List <WeatherLocation> mLocations;
private Context mContext;
private int rowForLocationToInflate;
private LayoutInflater inflater;
public WeatherLocationAdapter(List<WeatherLocation> mLocations, Context mContext, int rowForLocationToInflate) {
this.mLocations = mLocations;
this.mContext = mContext;
this.rowForLocationToInflate = rowForLocationToInflate;
inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
//TODO just built up layout now must tie to it.
private void addLocation(WeatherLocation newLocation){
mLocations.add(newLocation);
//TODO maybe invalidate after adding new item.
}
#Override
public int getCount() {
return mLocations.size();
}
#Override
public WeatherLocation getItem(int position) {
return mLocations.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//TODO build a viewholder
View rowView = inflater.inflate(rowForLocationToInflate, parent, false);
TextView tvZipcode = (TextView) rowView.findViewById(R.id.tvZipCode);
TextView tvCity = (TextView) rowView.findViewById(R.id.tvCity);
TextView tvTemp = (TextView) rowView.findViewById(R.id.tvDegree);
tvZipcode.setText(mLocations.get(position).getZipcode());
tvCity.setText(mLocations.get(position).getCity());
tvTemp.setText(String.valueOf(mLocations.get(position).getTemperature()));
// If you had a Button in your LinearLayout you were attaching to you that you wanted to delete that view/item with, it would look something like this in my case.
Button bDel = (Button) row.findViewById(R.id.bDel);
bDel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mLocations.remove(position);
}
});
return rowView;
}
}
In the onClick you would also remove the item from the SQL db. I can show that too, but I feel you have some coding to do as it stands.