the google image search url looks like this https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=eden%20hazard&rsz=8&start=4 where the rsz parameter in the max images per page and the start parameter is the page number. I am able to get all imaged in a page. But have no idea to do that for say 20 pages, that is start= 0 ... 19. My code below shows how i did get the imaged from a page. Please let me know how i can make it get images for several pages. I tried using a for loop outside of me async task(okhttp enqueue).
package com.paveynganpi.allsearch;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Text;
import java.io.IOException;
import java.util.ArrayList;
public class ImageGrid extends ActionBarActivity {
private static final String TAG = ImageGrid.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_grid);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_image_grid, menu);
return true;
}
#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();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
protected GridView mGridView;//reference to gridview in fragment_image_grid.xml
protected int start = 0;//variable to change pages from google Api
//contains extra images urls to supply to ... when need
protected ArrayList<String> mBigImagesUrls;
//contains image urls to inject into gridview
protected static ArrayList<String> mSmalImagesUrls = new ArrayList<String>();
protected static String mEditedString;
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.fragment_image_grid, container, false);
final ArrayList<String> testList = new ArrayList<String>();
//gets the edited string from MainActivity
Bundle args = getActivity().getIntent().getExtras();
mEditedString = args.getString("space");
String imagesUrl = "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q="
+ mEditedString +"&rsz=8&start=" + start;
//populate(start,imagesUrl.substring(0,imagesUrl.length()-1));
if(isNetworkAvailable()) {
//using okHttp library to connect to imagesUrl and retrieve JSON Data
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(imagesUrl).
build();
Call call = client.newCall(request);
//runs the below code asynchronously
call.enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
Log.v(TAG, "error from request");
}
#Override
public void onResponse(Response response) throws IOException {
try {
String jsonData = response.body().string();
//Log.v(TAG, jsonData);
if (!response.isSuccessful()) {
alertUserAboutError();
} else {
mSmalImagesUrls = getCurrentDetails(jsonData);
getActivity().runOnUiThread(new Runnable(){
#Override
public void run(){
mGridView =(GridView) rootView.findViewById(R.id.imagesGrid);//reference to gridview
ImagesGridAdapter adapter = new ImagesGridAdapter(getActivity(),mSmalImagesUrls);
mGridView.setAdapter(adapter);
}
});
}
} catch (IOException | JSONException e) {
Log.e(TAG, "Exception caught :", e);
}
}
});
}
else{
Toast.makeText(getActivity(), "Network is unavailable", Toast.LENGTH_LONG).show();
}
return rootView;
}
//get data
private ArrayList<String> getCurrentDetails(String jsonData) throws JSONException {
JSONObject jsonObject = new JSONObject(jsonData);
JSONObject responseData = jsonObject.getJSONObject("responseData");
ArrayList<String> localList = new ArrayList<String>();
JSONArray results = responseData.getJSONArray("results");
for(int i =0;i<results.length(); i++){
localList.add(results.getJSONObject(i).getString("url"));
}
return localList;
}
//An AlertDialog to display to user when an error occurs
private void alertUserAboutError() {
AlertDialogFragment dialog = new AlertDialogFragment();
dialog.show(getActivity().getFragmentManager(),"error_dialog");
}
//checks if user is connected to a network
private boolean isNetworkAvailable() {
ConnectivityManager cm =
(ConnectivityManager)getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isAvailable = false;
if(activeNetwork != null && activeNetwork.isConnectedOrConnecting()){
isAvailable = true;
}
return isAvailable;
}
}
}
You could create a method such as:
public String getImagesForPage(int page){
return "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q="
+ mEditedString +"&rsz=8&start=" + page;
}
Then:
for (start=0;start<20;start++){
if(isNetworkAvailable()) {
//using okHttp library to connect to imagesUrl and retrieve JSON Data
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(getImagesForPage(start)).
build();
Call call = client.newCall(request);
//runs the below code asynchronously
call.enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
Log.v(TAG, "error from request");
}
#Override
public void onResponse(Response response) throws IOException {
try {
String jsonData = response.body().string();
//Log.v(TAG, jsonData);
if (!response.isSuccessful()) {
alertUserAboutError();
} else {
mSmalImagesUrls = getCurrentDetails(jsonData);
getActivity().runOnUiThread(new Runnable(){
#Override
public void run(){
mGridView =(GridView) rootView.findViewById(R.id.imagesGrid);//reference to gridview
ImagesGridAdapter adapter = new ImagesGridAdapter(getActivity(),mSmalImagesUrls);
mGridView.setAdapter(adapter);
}
});
}
...
}
I recommend you create a method just with your connection logic. This code will download the 20 pages of contents and update your gridView everytime a request finishes. So, in the end of it, you'll have your gridView with the last page content. To just store the content of the pages, create a HashMap<Integer,List<String>> to store the urls for each page.
Related
In my app, I am trying to add sorting such as: sort by popular, top rated, etc.
with sorting options in AlertDialog.
My problem is that choosing the option to sort by GridView doesn't update or change ImageView
I tried the following but it doesn't work:
adapter.notifyDataSetChanged();
gridView.invalidateViews();
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Point;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.BoolRes;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.StringRequest;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
/**
* Created by macbook on 9/18/17.
*/
public class MoviesFragment extends Fragment implements AdapterView.OnItemClickListener {
static GridView gridView;
static int width;
static ArrayList<String> posters;
private final static String API_KEY = "0000000000000000000";
final static String URL_BASE = "https://api.themoviedb.org/3/movie/";
static String url_sorted ="popular?api_key=" ;
ImageAdapter adapter;
public MoviesFragment()
{
}
// inflate view and init grideView with set adapter
#Nullable
#Override
public View onCreateView (LayoutInflater inflater, #Nullable ViewGroup
container, #Nullable Bundle savedInstanceState){
View view = inflater.inflate(R.layout.movies_fragment, container, false);
setHasOptionsMenu(true);
// getwidth
WindowManager wm = (WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
if(MainActivity.TABLET)
{
width = size.x/6;
}else
{
width = size.x/2;
}
if(getActivity() != null)
{
posters = new ArrayList<String>();
adapter = new ImageAdapter(getActivity(),posters,width);
gridView = (GridView)view.findViewById(R.id.grideView);
gridView.setAdapter(adapter);
gridView.setColumnWidth(width);
gridView.setOnItemClickListener(this);
}
return view;
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(getActivity(),position+"",Toast.LENGTH_SHORT).show();
}
#Override
public void onStart() {
super.onStart();
getActivity().setTitle("Most Popular Movies");
loadPoster(url_sorted);
}
public void loadPoster(String url) {
if (isNetworkAvailable()) {
gridView.setVisibility(View.VISIBLE);
getJsonImageUrl(url);
} else {
gridView.setVisibility(View.GONE);
TextView text = new TextView(getActivity());
RelativeLayout relativeLayout = (RelativeLayout) getActivity().findViewById(R.id.relative);
text.setText("no Internet Connection...");
relativeLayout.addView(text);
}
}
private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager
= (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
public Boolean getJsonImageUrl( String urlSort)
{
Toast.makeText(getActivity(),urlSort,Toast.LENGTH_LONG).show();
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, URL_BASE + urlSort+ API_KEY, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
int count = 0 ;
JSONArray obj = null;
try {
obj = response.getJSONArray("results");
} catch (JSONException e) {
e.printStackTrace();
}
while(count <obj.length())
{
JSONObject jsonObject = null;
String imgURL = null;
try {
jsonObject = obj.getJSONObject(count);
imgURL = jsonObject.getString("poster_path");
} catch (JSONException e) {
e.printStackTrace();
}
posters.add(imgURL);
count++;
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getActivity(),"ERROR",Toast.LENGTH_LONG).show();
}
}
);
Mysingleton.getInstence(getContext()).addToRequestque(jsonObjectRequest);
return true;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId())
{
case R.id.preferncesMenu:
break;
case R.id.filter:
// Intent i = new Intent(getActivity().getApplication(),SettingAactivity.class);
//startActivity(i);
showSortDialog();
break;
}
return false;
}
private void showSortDialog() {
final CharSequence[] sortBy = new String[] {"Popular", "Top Rated","Latest","Upcoming","Now playing"};
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Sort by");
builder.setSingleChoiceItems(sortBy, -1, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
String newUrl;
gridView.setAdapter(null);
switch(which)
{
case 0:
newUrl = "popular?api_key=";
getActivity().setTitle("Most Popular Movies");
//loadPoster(newUrl);
break;
case 1:
newUrl = "top_rated?api_key=";
getActivity().setTitle("Top Rated Movies");
adapter.notifyDataSetChanged();
gridView.invalidateViews();
loadPoster(newUrl);
Toast.makeText(getActivity(),newUrl,Toast.LENGTH_LONG).show();
dialog.dismiss();
break;
case 2:
url_sorted = "latest?api_key=";
getActivity().setTitle("latest Movies");
break;
case 3:
url_sorted = "upcoming?api_key=";
getActivity().setTitle("UpComing Movies");
break;
case 5:
url_sorted = "now_playing?api_key=";
getActivity().setTitle("Now Playing Movies");
break;
}
}
});
builder.create().show();
}
}
The problem was calling notifyDataSetChanged() from a non UI Thread.
So after call notifyDataSetChanged() from UI Thread its work perfectly
Code:
public void refresh()
{
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
adapter.notifyDataSetChanged();
gridView.invalidate();
}
});
}
Basically inside your adapter you need to have mechanism to pass in/update the data object.
Add a method inside your adapter class which will be called when new data is available.
public void swapItems(List<Item> itemsList){
mItemsList.clear();
mItemsList.addAll(itemsList);
notifyDataSetChanged();
}
Then from your activity, after you have received your new data, just call this method from your adapter instance.
adapter.swapItems(newItemsList);
Just change the above code to match your data type. But that's basically how it's done. And if you want to be more fancy explore Android data binding.
I only see you calling notifyDataSetChanged after you set the adapter to null. I'm not sure why you would set the adapter to null and then attempt to use it. You should be crashing, not just seeing data not updated.
After your getjson call you should be calling notifyDataSetChanged to show all the new items you got. If sort is to change the sort order, then you should implement your sort on the list, then call notifyDataSetChanged again.
I'm not sure why you are nulling it out. If you do this, you should be fine.
I'm a high school student working for a magazine in South Korea known as Teen 10 Magazine. As an aspiring computer science major, I decided to make an RSS reader app for my magazine in order to showcase my skills for college applications (and also to create an app, which has always been my interest). Basically, I want to format my app to be similar to your typical news app (ex. CNN, BBC, etc).
Category Screen
In a DrawerLayout (as seen in the Category Screen), I decided to make a tab for each different category (such as News, Features, Entertainment, etc), including the Home category, which is where the categories the articles are under don't matter. When users click on each different tab, it gives them a list of articles that are categorized under that category. In order to get this data, I'm parsing the data to get the title (which is displayed in the list) and the link (which is set to an Intent so that users can access the article in the Web when it is clicked)
However, while some of the categories do work (Home, Lifestyle, Fashion), the rest of the categories are stuck in the loading screen for almost an infinite amount of time.
Example of loading category
I'm pretty sure that the codes of the categories that work and the categories that don't are the same (for reference, I copied and pasted and adjusted each different category accordingly, which could also be an issue but I'm not sure), and are getting their data from the appropriate sites.
Is it perhaps there are too many parsers (RssParser does the actual parsing and seven different "RssService"s use the parser to parse the data from each different category) for my app to work with? My app does seem to crash once in a while though...
I will post my codes below:
MainActivity.java:
package com.hfad.teen10magazine;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v7.app.ActionBarDrawerToggle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.ShareActionProvider;
import android.support.v4.widget.DrawerLayout;
public class MainActivity extends Activity {
/* adds the fragment to the activity */
private ShareActionProvider shareActionProvider;
private String[] titles;
private ListView drawerList;
private DrawerLayout drawerLayout;
private ActionBarDrawerToggle drawerToggle;
private int currentPosition = 0;
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//Code to run when an item in the navigation drawer gets clicked
selectItem(position);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
titles = getResources().getStringArray(R.array.titles);
drawerList = (ListView)findViewById(R.id.drawer);
drawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
//Initialize the ListView
drawerList.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_activated_1, titles));
drawerList.setOnItemClickListener(new DrawerItemClickListener());
//Display the correct fragment.
if (savedInstanceState != null) {
currentPosition = savedInstanceState.getInt("position");
setActionBarTitle(currentPosition);
} else {
selectItem(0);
}
//Create the ActionBarDrawerToggle
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout,
R.string.open_drawer, R.string.close_drawer) {
//Called when a drawer has settled in a completely closed state
#Override
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
invalidateOptionsMenu();
}
//Called when a drawer has settled in a completely open state.
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
invalidateOptionsMenu();
}
};
drawerLayout.addDrawerListener(drawerToggle);
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
getFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
FragmentManager fragMan = getFragmentManager();
Fragment fragment = fragMan.findFragmentByTag("visible_fragment");
if (fragment instanceof TopFragment) {
currentPosition = 0;
}
if (fragment instanceof LifestyleFragment) {
currentPosition = 1;
}
if (fragment instanceof EntFragment) {
currentPosition = 2;
}
if (fragment instanceof NewsFragment) {
currentPosition = 3;
}
if (fragment instanceof FeaturesFragment) {
currentPosition = 4;
}
if (fragment instanceof AcademicsFragment) {
currentPosition = 5;
}
if (fragment instanceof FashionFragment) {
currentPosition = 6;
}
setActionBarTitle(currentPosition);
drawerList.setItemChecked(currentPosition, true);
}
}
);
}
private void selectItem(int position) {
// update the main content by replacing fragments
currentPosition = position;
Fragment fragment;
switch(position) {
case 1:
fragment = new LifestyleFragment();
break;
case 2:
fragment = new EntFragment();
break;
case 3:
fragment = new NewsFragment();
break;
case 4:
fragment = new FeaturesFragment();
break;
case 5:
fragment = new AcademicsFragment();
break;
case 6:
fragment = new FashionFragment();
break;
default:
fragment = new TopFragment();
}
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, fragment, "visible_fragment");
ft.addToBackStack(null);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
//Set the action bar title
setActionBarTitle(position);
//Close the drawer
drawerLayout.closeDrawer(drawerList);
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// If the drawer is open, hide action items related to the content view
boolean drawerOpen = drawerLayout.isDrawerOpen(drawerList);
menu.findItem(R.id.action_share).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
drawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
drawerToggle.onConfigurationChanged(newConfig);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("position", currentPosition);
}
private void setActionBarTitle(int position) {
String title="";
titles=getResources().getStringArray(R.array.titles);
if (position == 0){
title = getResources().getString(R.string.app_name);
} else {
title = titles[position];
}
getActionBar().setTitle(title);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
MenuItem menuItem = menu.findItem(R.id.action_share);
shareActionProvider = (ShareActionProvider) menuItem.getActionProvider();
setIntent("This is example text");
return super.onCreateOptionsMenu(menu);
}
private void setIntent(String text) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, text);
shareActionProvider.setShareIntent(intent);
}
}
RssItem.java:
package com.hfad.teen10magazine;
public class RssItem {
private final String title;
private final String link;
private final String pubDate;
public RssItem(String title, String link, String pubDate) {
this.title = title;
this.link = link;
this.pubDate = pubDate;
}
public String getTitle() {
return title;
}
public String getLink() {
return link;
}
public String getDate() {
return pubDate;
}
}
RssParser.java:
package com.hfad.teen10magazine;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.util.Xml;
public class RssParser {
// We don't use namespaces
private final String ns = null;
public List<RssItem> parse(InputStream inputStream) throws XmlPullParserException, IOException {
try {
XmlPullParser parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(inputStream, null);
parser.nextTag();
return readFeed(parser);
} finally {
inputStream.close();
}
}
private List<RssItem> readFeed(XmlPullParser parser) throws XmlPullParserException, IOException {
parser.require(XmlPullParser.START_TAG, null, "rss");
String title = null;
String link = null;
String pubDate = null;
List<RssItem> items = new ArrayList<RssItem>();
while (parser.next() != XmlPullParser.END_DOCUMENT) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
if (name.equals("title")) {
title = readTitle(parser);
} else if (name.equals("link")) {
link = readLink(parser);
} else if (name.equals("pubDate")) {
pubDate = readDate(parser);
}
if (title != null && link != null && pubDate != null) {
RssItem item = new RssItem(title, link, pubDate);
items.add(item);
title = null;
link = null;
pubDate = null;
}
}
return items;
}
private String readLink(XmlPullParser parser) throws XmlPullParserException, IOException {
parser.require(XmlPullParser.START_TAG, ns, "link");
String link = readText(parser);
parser.require(XmlPullParser.END_TAG, ns, "link");
return link;
}
private String readTitle(XmlPullParser parser) throws XmlPullParserException, IOException {
parser.require(XmlPullParser.START_TAG, ns, "title");
String title = readText(parser);
parser.require(XmlPullParser.END_TAG, ns, "title");
return title;
}
private String readDate(XmlPullParser parser) throws XmlPullParserException, IOException {
parser.require(XmlPullParser.START_TAG, ns, "pubDate");
String pubDate = readText(parser);
parser.require(XmlPullParser.END_TAG, ns, "pubDate");
return pubDate;
}
// For the tags title and link, extract their text values.
private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
String result = "";
if (parser.next() == XmlPullParser.TEXT) {
result = parser.getText();
parser.nextTag();
}
return result;
}
}
Constants.java:
package com.hfad.teen10magazine;
public class Constants {
public static final String TAG = "Teen10MagazineApp";
}
RssAdapter.java:
package com.hfad.teen10magazine;
import java.util.List;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class RssAdapter extends BaseAdapter {
/* puts the RSS items in a list */
private final List<RssItem> items;
private final Context context;
public RssAdapter(Context context, List<RssItem> items) {
this.items = items;
this.context = context;
}
#Override
public int getCount() {
return items.size();
}
#Override
public Object getItem(int position) {
return items.get(position);
}
#Override
public long getItemId(int id) {
return id;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = View.inflate(context, R.layout.rss_item, null);
holder = new ViewHolder();
holder.itemTitle = (TextView) convertView.findViewById(R.id.itemTitle);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.itemTitle.setText(items.get(position).getTitle());
return convertView;
}
static class ViewHolder {
TextView itemTitle;
}
}
Along with the main codes, for the sake of time, I will post the codes of one category that works (the fragment it is placed in and the RssService used to get it) and the codes of one that doesn't work. If you need more information or codes, please contact me and I will be happy to provide information:
LifeStyleFragment.java (Works):
package com.hfad.teen10magazine;
import android.app.Fragment;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.Toast;
import java.util.List;
public class LifestyleFragment extends Fragment implements AdapterView.OnItemClickListener {
private ProgressBar progressBar;
private ListView listView;
private View view;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (view == null) {
view = inflater.inflate(R.layout.fragment_layout, container, false);
progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
listView = (ListView) view.findViewById(R.id.listView);
listView.setOnItemClickListener(this);
startService();
} else {
// If we are returning from a configuration change:
// "view" is still attached to the previous view hierarchy
// so we need to remove it and re-attach it to the current one
ViewGroup parent = (ViewGroup) view.getParent();
parent.removeView(view);
}
return view;
}
private void startService() {
Intent intent = new Intent(getActivity(), RssService_Lifestyle.class);
intent.putExtra(RssService_Lifestyle.RECEIVER, resultReceiver);
getActivity().startService(intent);
}
private final ResultReceiver resultReceiver = new ResultReceiver(new Handler()) {
#SuppressWarnings("unchecked")
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
List<RssItem> items = (List<RssItem>) resultData.getSerializable(RssService_Lifestyle.ITEMS);
if (items != null) {
RssAdapter adapter = new RssAdapter(getActivity(), items);
listView.setAdapter(adapter);
} else {
Toast.makeText(getActivity(), "An error occurred while downloading the rss feed.",
Toast.LENGTH_LONG).show();
}
progressBar.setVisibility(View.GONE);
listView.setVisibility(View.VISIBLE);
};
};
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
RssAdapter adapter = (RssAdapter) parent.getAdapter();
RssItem item = (RssItem) adapter.getItem(position);
Uri uri = Uri.parse(item.getLink());
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
}
RssService_Lifestyle.java:
package com.hfad.teen10magazine;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URL;
import java.util.List;
import org.xmlpull.v1.XmlPullParserException;
import android.app.IntentService;
import android.content.Intent;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.util.Log;
public class RssService_Lifestyle extends IntentService {
/* parse the rss feed on lifestyle and send the list of items to LifestyleFragment */
private static final String RSS_LINK = "http://www.teen10mag.com/category/lifestyle/feed/";
public static final String ITEMS = "items";
public static final String RECEIVER = "receiver";
public RssService_Lifestyle() {
super("RssService_Lifestyle");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d(Constants.TAG, "Service started");
List<RssItem> rssItems = null;
try {
RssParser parser = new RssParser();
rssItems = parser.parse(getInputStream(RSS_LINK));
} catch (XmlPullParserException | IOException e) {
Log.w(e.getMessage(), e);
}
Bundle bundle = new Bundle();
bundle.putSerializable(ITEMS, (Serializable) rssItems);
ResultReceiver receiver = intent.getParcelableExtra(RECEIVER);
receiver.send(0, bundle);
}
public InputStream getInputStream(String link) {
try {
URL url = new URL(link);
return url.openConnection().getInputStream();
} catch (IOException e) {
Log.w(Constants.TAG, "Exception while retrieving the input stream", e);
return null;
}
}
}
AcademicsFragment.java (Doesn't work):
package com.hfad.teen10magazine;
import java.util.List;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.Toast;
public class AcademicsFragment extends Fragment implements AdapterView.OnItemClickListener {
private ProgressBar progressBar;
private ListView listView;
private View view;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (view == null) {
view = inflater.inflate(R.layout.fragment_layout, container, false);
progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
listView = (ListView) view.findViewById(R.id.listView);
listView.setOnItemClickListener(this);
startService();
} else {
// If we are returning from a configuration change:
// "view" is still attached to the previous view hierarchy
// so we need to remove it and re-attach it to the current one
ViewGroup parent = (ViewGroup) view.getParent();
parent.removeView(view);
}
return view;
}
private void startService() {
Intent intent = new Intent(getActivity(), RssService_Academics.class);
intent.putExtra(RssService_Academics.RECEIVER, resultReceiver);
getActivity().startService(intent);
}
private final ResultReceiver resultReceiver = new ResultReceiver(new Handler()) {
#SuppressWarnings("unchecked")
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
List<RssItem> items = (List<RssItem>) resultData.getSerializable(RssService_Academics.ITEMS);
if (items != null) {
RssAdapter adapter = new RssAdapter(getActivity(), items);
listView.setAdapter(adapter);
} else {
Toast.makeText(getActivity(), "An error occurred while downloading the rss feed.",
Toast.LENGTH_LONG).show();
}
progressBar.setVisibility(View.GONE);
listView.setVisibility(View.VISIBLE);
}
};
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
RssAdapter adapter = (RssAdapter) parent.getAdapter();
RssItem item = (RssItem) adapter.getItem(position);
Uri uri = Uri.parse(item.getLink());
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
}
RssService_Academics.java:
package com.hfad.teen10magazine;
import android.app.IntentService;
import android.content.Intent;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.util.Log;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URL;
import java.util.List;
public class RssService_Academics extends IntentService {
/* parse the rss feed on academics and send the list of items to AcademicsFragment */
private static final String RSS_LINK = "http://www.teen10mag.com/category/academics/feed/";
public static final String ITEMS = "items";
public static final String RECEIVER = "receiver";
public RssService_Academics() {
super("RssService_Academics");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d(Constants.TAG, "Service started");
List<RssItem> rssItems = null;
try {
RssParser parser = new RssParser();
rssItems = parser.parse(getInputStream(RSS_LINK));
} catch (XmlPullParserException | IOException e) {
Log.w(e.getMessage(), e);
}
Bundle bundle = new Bundle();
bundle.putSerializable(ITEMS, (Serializable) rssItems);
ResultReceiver receiver = intent.getParcelableExtra(RECEIVER);
receiver.send(0, bundle);
}
public InputStream getInputStream(String link) {
try {
URL url = new URL(link);
return url.openConnection().getInputStream();
} catch (IOException e) {
Log.w(Constants.TAG, "Exception while retrieving the input stream", e);
return null;
}
}
}
This is my first question, so I tried to be as detailed as possible. If my explanations were unreasonably lengthy, I do apologize. This is also my first time coding something this extensive, so forgive me if I seem to make amateur mistakes...
Thank you in advance for all of your help!!
[EDIT]
When I click on the category that doesn't work, the logcat turns up like this:
09-21 19:29:59.237 1541-1866/system_process W/ActivityManager: Unable to start service Intent { cmp=com.hfad.teen10magazine/.RssService_News (has extras) } U=0: not found
09-21 19:30:13.209 2808-2808/com.hfad.teen10magazine I/Choreographer: Skipped 31 frames! The application may be doing too much work on its main thread.
09-21 19:30:21.122 2808-2814/com.hfad.teen10magazine W/art: Suspending all threads took: 13.025ms`
I am developing a MovieApp which loads movie posters in MainActivity Fragment using AsyncTask background thread. I am using gridview and BaseAdapter to display images. Following is the code.
MainActivityFragment.java :
package com.android.example.cinemaapp.app;
import android.app.Fragment;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.GridView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
public class MainActivityFragment extends Fragment{
MoviePosterAdapter moviePosterAdapter;
GridView posterGridView;
public HashMap<String, JSONObject> movieMap;
public MainActivityFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public void onStart(){
super.onStart();
updateMovies();
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.moviefragment, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_refresh) {
updateMovies();
}
return super.onOptionsItemSelected(item);
}
public void updateMovies(){
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
String sortBy = sharedPreferences.getString(getString(R.string.pref_sort_key), getString(R.string.pref_sort_popular));
new FetchMoviePosterTask().execute(sortBy);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
moviePosterAdapter = new MoviePosterAdapter(getActivity());
posterGridView = (GridView) rootView.findViewById(R.id.gridview_movie);
posterGridView.setAdapter(moviePosterAdapter);
posterGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
// logic to start detail activity
startActivity(intent);
}
});
return rootView;
}
public class FetchMoviePosterTask extends AsyncTask<String, String, Void> implements Serializable {
#Override
protected Void doInBackground(String... params) {
Log.v("FetchMoviePosterTask", "In background method");
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
String movieJsonStr;
try {
//logic to create uri builder
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.
movieJsonStr = 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();
// Log.v("MainActivityFragment", "Movie json "+movieJsonStr);
try {
String[] posterPaths = getPosterPaths(movieJsonStr);
for(String path : posterPaths){
publishProgress(path);
}
}catch(JSONException je){
Log.e("MoviePosterPath","Error while parsing JSON");
}
} catch (IOException e) {
Log.e("MoviePosterAdapter", "Error ", e);
movieJsonStr = null;
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("MoviePosterAdapter", "Error closing stream", e);
}
}
}
return null;
}
public String[] getPosterPaths(String movieJsonStr) throws JSONException{
final String POSTER_PATH = //some value
final String POSTER_SIZE = //some value
JSONObject jsonObject = new JSONObject(movieJsonStr);
JSONArray results = jsonObject.getJSONArray("results");
String[] posterStrs = new String[results.length()];
movieMap = new HashMap<String, JSONObject>();
for(int i =0; i < results.length(); i++){
JSONObject movieObj = (JSONObject) results.get(i);
posterStrs[i] = POSTER_PATH + POSTER_SIZE + movieObj.getString("poster_path");
movieMap.put(posterStrs[i], movieObj);
}
return posterStrs;
}
#Override
protected void onProgressUpdate(String... posterValues){
Log.v("FetchMoviePosterTask", "In onProgress method");
moviePosterAdapter.add(posterValues[0]);
super.onProgressUpdate(posterValues);
}
#Override
protected void onPostExecute(Void result) {
Log.v("FetchMoviePosterTask", "In onPostExecute method");
moviePosterAdapter.notifyDataSetChanged();
super.onPostExecute(result);
}
}
}
MoviePosterAdapter.java :
package com.android.example.cinemaapp.app;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
public class MoviePosterAdapter extends BaseAdapter {
ArrayList<String> movieArray = new ArrayList<String>();
private Context mContext;
public MoviePosterAdapter(Context c) {
mContext = c;
}
void add(String path){
movieArray.add(path);
}
void clear(){
movieArray.clear();
}
void remove(int index){
movieArray.remove(index);
}
#Override
public int getCount() {
return movieArray.size();
}
#Override
public Object getItem(int position) {
return movieArray.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.setScaleType(ImageView.ScaleType.FIT_XY);
} else {
imageView = (ImageView) convertView;
}
Picasso.with(mContext).load(movieArray.get(position)).into(imageView);
return imageView;
}
}
Problem : When the application is first launched, UI is not getting populated with imageviews. In Logcat I could see control is flowing through doBackground(), onProgressUpdate() and onPostExecute().
When I click 'Refresh' button or If i navigate to some other activity or app and return to Movie app UI (onResume()) it is working perfectly fine. Images are displayed.
Many thanks in advance!
You should change updateMovies(); from onStart() to onCreateView. As Gabe Sechan said, you're wrong about the lifecycle. Try to do some research on the Fragment lifecycle.
Just you need to call method updateMovies(); from onCreateView() after posterGridView = (GridView) rootView.findViewById(R.id.gridview_movie);
remove call from start();
I am getting image urls using google image search apis. i use okhttp to connect to the url. this is done in my activity's oncreate method. in the oncreate() method of fragment i get all the image urls and store them in mSmallIMagesUrl, in the oncreateView() i try to display the images using a customized adapter. but when i run my app, hit the search button, it shows a blank page, when i go back and click the search button(there is always text in the search box) it shows images of the the previous search text. i dont know why it this,below is my code, please let me know what i am missing. thanks
package com.paveynganpi.allsearch;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Text;
import java.io.IOException;
import java.util.ArrayList;
public class ImageGrid extends ActionBarActivity {
private static final String TAG = ImageGrid.class.getSimpleName();
protected int start = 0;//variable to change pages from google Api
//contains extra images urls to supply to ... when need
protected static ArrayList<ArrayList<String>> mBigImagesUrls = new ArrayList<ArrayList<String>>();
//contains image urls to inject into gridview
protected static ArrayList<String> mSmalImagesUrls = new ArrayList<>();
protected static String mEditedString;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_grid);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
for (int start = 0; start < 2; start++) {
if (isNetworkAvailable()) {
//using okHttp library to connect to imagesUrl and retrieve JSON Data
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(getImagePage(start)).
build();
Call call = client.newCall(request);
//runs the below code asynchronously
call.enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
Log.v(TAG, "error from request");
}
#Override
public void onResponse(Response response) throws IOException {
try {
String jsonData = response.body().string();
//Log.v(TAG, jsonData);
if (!response.isSuccessful()) {
alertUserAboutError();
} else {
// mSmalImagesUrls = getCurrentDetails(jsonData);
mBigImagesUrls.add(getCurrentDetails(jsonData));
Log.d(TAG, mBigImagesUrls.size() + " big size");
Log.d(TAG, mSmalImagesUrls.size() + " small size");
}
} catch (IOException | JSONException e) {
Log.e(TAG, "Exception caught :", e);
}
}
});
} else {
Toast.makeText(this, "Network is unavailable", Toast.LENGTH_LONG).show();
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_image_grid, menu);
return true;
}
#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();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private String getImagePage(int start) {
return "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q="
+ mEditedString + "&rsz=8&start=" + start;
}
//get data
private ArrayList<String> getCurrentDetails(String jsonData) throws JSONException {
JSONObject jsonObject = new JSONObject(jsonData);
JSONObject responseData = jsonObject.getJSONObject("responseData");
ArrayList<String> localList = new ArrayList<String>();
JSONArray results = responseData.getJSONArray("results");
for (int i = 0; i < results.length(); i++) {
localList.add(results.getJSONObject(i).getString("url"));
}
return localList;
}
//An AlertDialog to display to user when an error occurs
private void alertUserAboutError() {
AlertDialogFragment dialog = new AlertDialogFragment();
dialog.show(getFragmentManager(), "error_dialog");
}
//checks if user is connected to a network
private boolean isNetworkAvailable() {
ConnectivityManager cm =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isAvailable = false;
if (activeNetwork != null && activeNetwork.isConnectedOrConnecting()) {
isAvailable = true;
}
return isAvailable;
}
#Override
public void onBackPressed() {
super.onBackPressed();
Log.d(TAG,"back was pressed");
mBigImagesUrls.clear();
mSmalImagesUrls.clear();
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
protected GridView mGridView;//reference to gridview in fragment_image_grid.xml
static String mEditedString;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, mBigImagesUrls.size() + " final big size");
Log.d(TAG, mSmalImagesUrls.size() + "final small size");
for(int i =0;i<mBigImagesUrls.size();i++){
for(int j =0;j<8;j++){
mSmalImagesUrls.add(mBigImagesUrls.get(i).get(j));
}
}
}
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.fragment_image_grid, container, false);
final ArrayList<String> testList = new ArrayList<String>();
//gets the edited string from MainActivity
Bundle args = getActivity().getIntent().getExtras();
mEditedString = args.getString("space");
mGridView = (GridView)rootView.findViewById(R.id.imagesGrid);//reference to gridview
ImagesGridAdapter adapter = new ImagesGridAdapter(getActivity(), mSmalImagesUrls);
mGridView.setAdapter(adapter);
return rootView;
}
}
}
Since you are making an asynchronous request, the response is not available immediately. You can display a ProgressBar while the list of images is being downloaded, and then display the list when it has completed downloading.
After that, notify your adapter that the dataset has changed.
We have code that creates a list view with detailed view upon click. There is a wrapper class called drink content containing a drink object and a static code segment that makes a call to an asyncTask that calls our web service. We need to build the URL based on data from another activity but I don't understand the way in which the object is created. We can't seem to replace the general DrinkContent references in the list and detail fragments with a single reference to an instantiated instance of DrinkContent. We wanted to use the instantiated instance of drink content so we could write a constructor that would take in URL parameters generated during another activity. We can pass the URL data to the fragments, but when a constructor was written multiple instances of Drink content were being created and our web service request didn't work. We are storing the parameters in another activities shared preferences and passing them to the new activity.
Code for DrinkListActivity:
package com.cs4720.drinkengine_android;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.NavUtils;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
public class DrinkListActivity extends FragmentActivity
implements DrinkListFragment.Callbacks {
private boolean mTwoPane;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drink_list);
if (findViewById(R.id.drink_detail_container) != null) {
mTwoPane = true;
((DrinkListFragment) getSupportFragmentManager()
.findFragmentById(R.id.drink_list))
.setActivateOnItemClick(true);
}
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent i = new Intent(DrinkListActivity.this, LeaderboardActivity.class);
startActivity(i);
}
});
}
public void onItemSelected(String id) {
if (mTwoPane) {
Bundle arguments = new Bundle();
arguments.putString(DrinkDetailFragment.ARG_ITEM_ID, id);
DrinkDetailFragment fragment = new DrinkDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.drink_detail_container, fragment)
.commit();
} else {
Intent detailIntent = new Intent(this, DrinkDetailActivity.class);
detailIntent.putExtra(DrinkDetailFragment.ARG_ITEM_ID, id);
startActivity(detailIntent);
}
}
}
code for DrinkListFragment
package com.cs4720.drinkengine_android;
import com.cs4720.drinkengine_android.dummy.DrinkContent;
import com.cs4720.drinkengine_android.dummy.DrinkContent.GetDrinksTask;
import android.R;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class DrinkListFragment extends ListFragment {
private static final String STATE_ACTIVATED_POSITION = "activated_position";
private Callbacks mCallbacks = sDummyCallbacks;
private int mActivatedPosition = ListView.INVALID_POSITION;
public interface Callbacks {
public void onItemSelected(String id);
}
private static Callbacks sDummyCallbacks = new Callbacks() {
public void onItemSelected(String id) {
}
};
public DrinkListFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(new ArrayAdapter<DrinkContent.Drink>(getActivity(),
R.layout.simple_list_item_activated_1,
R.id.text1,
DrinkContent.ITEMS));
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (savedInstanceState != null && savedInstanceState
.containsKey(STATE_ACTIVATED_POSITION)) {
setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION));
}
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!(activity instanceof Callbacks)) {
throw new IllegalStateException("Activity must implement fragment's callbacks.");
}
mCallbacks = (Callbacks) activity;
}
#Override
public void onDetach() {
super.onDetach();
mCallbacks = sDummyCallbacks;
}
#Override
public void onListItemClick(ListView listView, View view, int position, long id) {
super.onListItemClick(listView, view, position, id);
mCallbacks.onItemSelected(DrinkContent.ITEMS.get(position).name);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mActivatedPosition != ListView.INVALID_POSITION) {
outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
}
}
public void setActivateOnItemClick(boolean activateOnItemClick) {
getListView().setChoiceMode(activateOnItemClick
? ListView.CHOICE_MODE_SINGLE
: ListView.CHOICE_MODE_NONE);
}
public void setActivatedPosition(int position) {
if (position == ListView.INVALID_POSITION) {
getListView().setItemChecked(mActivatedPosition, false);
} else {
getListView().setItemChecked(position, true);
}
mActivatedPosition = position;
}
}
code for DrinkDetailActivity
package com.cs4720.drinkengine_android;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.NavUtils;
import android.view.MenuItem;
public class DrinkDetailActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drink_detail);
getActionBar().setDisplayHomeAsUpEnabled(true);
if (savedInstanceState == null) {
Bundle arguments = new Bundle();
arguments.putString(DrinkDetailFragment.ARG_ITEM_ID,
getIntent().getStringExtra(DrinkDetailFragment.ARG_ITEM_ID));
DrinkDetailFragment fragment = new DrinkDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.add(R.id.drink_detail_container, fragment)
.commit();
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
NavUtils.navigateUpTo(this, new Intent(this, DrinkListActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
code for drinkDetailFragment
package com.cs4720.drinkengine_android;
import com.cs4720.drinkengine_android.dummy.DrinkContent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class DrinkDetailFragment extends Fragment {
public static final String ARG_ITEM_ID = "item_id";
DrinkContent.Drink mItem;
public DrinkDetailFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments().containsKey(ARG_ITEM_ID)) {
mItem = DrinkContent.ITEM_MAP.get(getArguments().getString(ARG_ITEM_ID));
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_drink_detail, container, false);
if (mItem != null) {
String miss="";
if(mItem.missing == 0){
miss = "You can make this Drink!";
}
else{
miss = "Missing "+ mItem.missing + " ingredients";
}
StringBuilder sb = new StringBuilder();
sb.append("Name: " + mItem.name
+ "\n" + miss
+ "\nDecription: " + mItem.description
+ "\nCalories: " + mItem.calories
+ "\nStrength: " + mItem.strength
+ "\nIngredients: \n");
for(int i = 0; i < mItem.units.size(); i++)
sb.append(mItem.units.get(i) + " " + mItem.ingredients.get(i) + "\n");
((TextView) rootView.findViewById(R.id.drink_detail)).setText(sb.toString());
}
return rootView;
}
}
code for DrinkContent
package com.cs4720.drinkengine_android.dummy;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONObject;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.util.Log;
public class DrinkContent {
public static class Drink {
public String name;
public int missing;
public String description;
public int calories;
public int strength;
public List<String> units;
public List<String> ingredients;
public Drink(String name) {
super();
this.name = name;
}
#Override
public String toString() {
return name;
}
}
public static String url = "http://drinkengine.appspot.com/view";
public static List<Drink> ITEMS = new ArrayList<Drink>();
public static Map<String, Drink> ITEM_MAP = new HashMap<String, Drink>();
static{
new GetDrinksTask().execute(url);
}
private static void addItem(Drink item) {
ITEMS.add(item);
ITEM_MAP.put(item.name, item);
}
public static String getJSONfromURL(String url) {
// initialize
InputStream is = null;
String result = "";
// http post
try {
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
is = entity.getContent();
} catch (Exception e) {
Log.e("DrinkEngine", "Error in http connection " + e.toString());
}
// convert response to string
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
result = sb.toString();
} catch (Exception e) {
Log.e("DrinkEngine", "Error converting result " + e.toString());
}
return result;
}
// The definition of our task class
public static class GetDrinksTask extends AsyncTask<String, Integer, String> {
SharedPreferences prefs;
#Override
protected void onPreExecute() {
}
#Override
protected String doInBackground(String... params) {
String url = params[0];
ArrayList<Drink> lcs = new ArrayList<Drink>();
try {
String webJSON = getJSONfromURL(url);
JSONArray drinks = new JSONArray(webJSON);
for (int i = 0; i < drinks.length(); i++) {
JSONObject jo = drinks.getJSONObject(i);
Drink current = new Drink(jo.getString("name"));
current.missing = Integer.parseInt(jo.getString("missing"));
current.description = jo.getString("description");
current.calories = Integer.parseInt(jo.getString("calories"));
current.strength = Integer.parseInt(jo.getString("strength"));
JSONArray units = jo.getJSONArray("units");
current.units = new ArrayList<String>();
for(int j = 0; j < units.length(); j++){
current.units.add(units.getString(j));
}
JSONArray ingredients = jo.getJSONArray("ingredients");
current.ingredients = new ArrayList<String>();
for(int j = 0; j < ingredients.length(); j++){
current.ingredients.add(ingredients.getString(j));
}
addItem(current);
}
} catch (Exception e) {
Log.e("DrinkEngine", "JSONPARSE:" + e.toString());
}
return "Done!";
}
#Override
protected void onProgressUpdate(Integer... ints) {
}
#Override
protected void onPostExecute(String result) {
// tells the adapter that the underlying data has changed and it
// needs to update the view
}
}
}
So now that youve seen the code the question might make more sense. We need to access our URL params from within drink content. But those parameters changed based on user input from another activity. We store those params in the other activities shared prefs and them pass them the DrinkListActivity and attempted to write a constructor that would take in the params and build the url properly. This did not work when we replaced the generalized DrinkContent and DrinkContent.LIST references with our instance we created. So basically how do we get the info inside of this class from our shared prefs?
SharedPreferences are shared across application level and not only activity level. It can actually be shared between applications if it is set to public. You should go read the documentation here and here as it explains this quite well.