I have two fragments each being inflated from a sliding menu. One fragment works as expected, the other one force closes the app. The Fragments are identical, except in name. the second has a runtime, fatal exception main in the log.
Here is the Fragment(s):
public class FeedZFragment extends Fragment {
private static final String TAG = "RecyclerViewExample";
private List<FeedZ> feedItemList = new ArrayList<FeedZ>();
//added static might remove
private static RecyclerView mRecyclerView;
private static MyRecyclerAdapterZ adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate( R.layout.fragment_recyclerview, container, false);
/* Allow activity to show indeterminate progress-bar */
getActivity().requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
/* Initialize recycler view */
mRecyclerView = (RecyclerView) getActivity().findViewById(R.id.my_recycler_view);
mRecyclerView.setLayoutManager(new GridLayoutManager(getActivity(),2));
/*Downloading data from below url*/
final String url = "http://www.thisismysite.com/a.json";
new AsyncHttpTask().execute(url);
return rootView;
}
public class AsyncHttpTask extends AsyncTask<String, Void, Integer> {
/* #Override
protected void onPreExecute() {
setProgressBarIndeterminateVisibility(true);
}*/
#Override
protected Integer doInBackground(String... params) {
InputStream inputStream = null;
Integer result = 0;
HttpURLConnection urlConnection = null;
try {
/* forming th java.net.URL object */
URL url = new URL(params[0]);
urlConnection = (HttpURLConnection) url.openConnection();
/* for Get request */
urlConnection.setRequestMethod("GET");
int statusCode = urlConnection.getResponseCode();
/* 200 represents HTTP OK */
if (statusCode == 200) {
BufferedReader r = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
response.append(line);
}
parseResult(response.toString());
result = 1; // Successful
}else{
result = 0; //"Failed to fetch data!";
}
} catch (Exception e) {
Log.d(TAG, e.getLocalizedMessage());
}
return result; //"Failed to fetch data!";
}
#Override
protected void onPostExecute(Integer result) {
// setProgressBarIndeterminateVisibility(false);
/* Download complete. Lets update UI */
if (result == 1) {
adapter = new MyRecyclerAdapterZ(getActivity(), feedItemList);
mRecyclerView.setAdapter(adapter);
} else {
Log.e(TAG, "Failed to fetch data!");
}
}
}
private void parseResult(String result) {
try {
JSONObject response = new JSONObject(result);
JSONArray products = response.optJSONArray("products");
/*Initialize array if null*/
if (null == feedItemList) {
feedItemList = new ArrayList<FeedZ>();
}
for (int i = 0; i < products.length(); i++) {
JSONObject product = products.optJSONObject(i);
FeedZ item = new FeedZ();
item.setTitle(product.optString("title"));
item.setImage_url(product.optString("image_url"));
item.setPackage_url(product.optString("package_url"));
item.setIds(product.optString("ids"));
feedItemList.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
the error is:
java.lang.NullPointerException
at com.nmthemes.WallFragment.onCreateView(WallFragment.java:44)
SOLUTION:
they weren't exactly identical.
getActivity().findViewById(R.id.my_recycler_view); should have been:
rootView.findViewById(R.id.my_recycler_view);
I changed it in one, not the other.
Related
[Update] Added repository link to download the project
I'm having this activity which connects to a URL to fetch data and display it using RecyclerView with a custom adapter. How can I edit this code to use AsyncTaskLoader instead of AsyncTask? here's the repository to download the very simple project Soonami tutorial app
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
public static QuakesAdapter quakesAdapter;
public static ArrayList<Event> eventsList = new ArrayList<>();
public static final String USGS_REQUEST_URL =
"https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&starttime=2018-01-01&endtime=2018-12-01&minmagnitude=6&limit=50";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recycler_view);
quakesAdapter = new QuakesAdapter(this, eventsList);
//defining recyclerView and setting the adapter
quakesAdapter.notifyDataSetChanged();
FetchData fetchData= new FetchData();
fetchData.execute();
}
private class FetchData extends AsyncTask<String, Void, ArrayList<Event>> {
String myDdata = "";
String line = "";
#Override
protected ArrayList<Event> doInBackground(String... params) {
try {
//opening the connection
if (httpURLConnection.getResponseCode() == 200) {
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
while(line != null){
line = bufferedReader.readLine();
myDdata = myDdata + line;
}
JSONObject jsonObject = new JSONObject(myDdata);
eventsList.clear();
JSONArray jsonArray = jsonObject.getJSONArray("features");
for(int i = 0; i < jsonArray.length(); i++){
//getting values of the 3 attributes
eventsList.add(new Event(title, time, tsunamiAlert));
}
if (inputStream != null) {
inputStream.close();
}
} else {
Log.e("Connection Error: ", "Error response code: " + httpURLConnection.getResponseCode());
}
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
catch (MalformedURLException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(ArrayList<Event> result) {
super.onPostExecute(result);
quakesAdapter.notifyDataSetChanged();
}
}
}
I have tested multiple examples but they have different codes and triggers multiple errors with my code like this one and still looking for a solution which makes my code works fine.
Set adpter in your recyclerview and then call the loader like this way:
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<List<Event>> {
{
private RecyclerView recyclerView;
public static QuakesAdapter quakesAdapter;
public static ArrayList<Event> eventsList = new ArrayList<>();
public static final String USGS_REQUEST_URL =
"https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&starttime=2018-01-01&endtime=2018-12-01&minmagnitude=6&limit=50";
#Override
protected void onCreate (Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recycler_view);
quakesAdapter = new QuakesAdapter(this, eventsList);
//defining recyclerView and setting the adapter
recyclerView.setAdapter(quakesAdapter);
getSupportLoaderManager().initLoader(1, null, this).forceLoad();
}
#Override
public Loader<List<Event>> onCreateLoader ( int id, Bundle args){
return new FetchData(MainActivity.this);
}
#Override
public void onLoadFinished (Loader < List < Event >> loader, List < Event > data){
quakesAdapter.setData(data);
}
#Override
public void onLoaderReset (Loader < List < Event >> loader) {
quakesAdapter.setData(new ArrayList<Event>());
}
Performs actual task in background and returns the result.
private static class FetchData extends AsyncTaskLoader<List<Event>>{
String myDdata = "";
String line = "";
public FetchData(Context context) {
super(context);
}
#Override
public List<Event> loadInBackground () {
try {
List<Event> list = new ArrayList<Event>();
//opening the connection
if (httpURLConnection.getResponseCode() == 200) {
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
while (line != null) {
line = bufferedReader.readLine();
myDdata = myDdata + line;
}
JSONObject jsonObject = new JSONObject(myDdata);
JSONArray jsonArray = jsonObject.getJSONArray("features");
for (int i = 0; i < jsonArray.length(); i++) {
//getting values of the 3 attributes
eventsList.add(new Event(title, time, tsunamiAlert));
}
if (inputStream != null) {
inputStream.close();
}
} else {
Log.e("Connection Error: ", "Error response code: " + httpURLConnection.getResponseCode());
}
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
return eventsList;
}
}
Add a method in your adapter like this:
public void setData(List<Event> data) {
this.data=data;
notifyDataSetChanged();
}
Which kind of error do you encounter?
I suggest using Java Interface and CallBack method for your AsynkTask, in this scenario, whenever your AsynkTask task is done, it notify the Activity with that callback method and you can execute notifyDataSetChange method of the adapter.
How can I get array list back to fragment after parsing to set into RecyclerView.
I tried to do that but when I call api it run background thread, till I get ArrayList from background my fragment created and it set null array to recycler adapter.
Then, I tried this way its working but I think it is a wrong approach. Please guide me -
How can I set adapter in Fragment after parsing data and send ArrayList back to fragment and set to RecyclerView adapter?
Here is my code fragment code
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
setHasOptionsMenu(true);
View view=inflater.inflate(R.layout.first_fragment,null);
recyclerView=(RecyclerView)view.findViewById(R.id.mFirstRecyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(this.getActivity()));
mswipeRefreshLayout = (SwipeRefreshLayout)view.findViewById(R.id.swipelayoutm);
ParseDataClass mparser = new ParseDataClass(getActivity(),recyclerView,mswipeRefreshLayout);
mparser.execute("http://192.168.8.100/fetchtext.php", "1");
recyclerView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
#Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
if (scrollX == 0) {
mswipeRefreshLayout.setEnabled(true);
} else mswipeRefreshLayout.setEnabled(false);
}
});
return view;
}
#Override
public String toString() {
return "FirstFragment";
}
#Override
public void onPrepareOptionsMenu(Menu menu) {
menu.findItem(R.id.rightimageitem).setVisible(false);
super.onPrepareOptionsMenu(menu);
}
}
And Here it is my parser class
public ParseDataClass(Context context,RecyclerView recyclerView,SwipeRefreshLayout swipeRefreshLayout) {
this.context = context;
progressDialog = new ProgressDialog(this.context);
progressDialog.setCancelable(false);
progressDialog.setMessage("Retrieving data...");
progressDialog.setTitle("Please wait");
progressDialog.setIndeterminate(true);
arrayList = new ArrayList<DataStored>();
getArraylist = new ArrayList<DataStored>();
this.recyclerView=recyclerView;
this.swipeRefreshLayout=swipeRefreshLayout;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog.show();
}
private static final String TAG = "Parser";
#Override
protected String doInBackground(String... strings) {
URL url = null;
int arryLength = strings.length;
HttpURLConnection httpURLConnection = null;
try {
url = new URL(strings[0]);
String catId = strings[1];
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoOutput(true);
httpURLConnection.setDoInput(true);
OutputStream outputStream = httpURLConnection.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
String post_data = URLEncoder.encode("catId", "UTF-8") + "=" + URLEncoder.encode(catId, "UTF-8");
bufferedWriter.write(post_data);
bufferedWriter.flush();
bufferedWriter.close();
outputStream.close();
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"));
String result = "";
String line = "";
while ((line = bufferedReader.readLine()) != null) {
result += line;
}
bufferedReader.close();
inputStream.close();
httpURLConnection.disconnect();
return result;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
try {
// RestaurantData restaurantData;
if (s != null) {
JSONObject jsonObject = new JSONObject(s);
JSONArray jsonArray = jsonObject.getJSONArray("result");
for (int i = 0; i < jsonArray.length(); i++) {
jsonObject = jsonArray.getJSONObject(i);
String branchname = jsonObject.getString("brancname");
String branchaddress = jsonObject.getString("branchaddres");
String brandname = jsonObject.getString("brandsNae");
String brandlogo = jsonObject.getString("brndlogo");
String branchlogo = jsonObject.getString("brnchlogo");
String discAmount = jsonObject.getString("distAmount");
dataStored = new DataStored(branchname, branchaddress, brandname, brandlogo, branchlogo, discAmount);
arrayList.add(dataStored);
}
myAdapter = new MyRecyclerAdapter(context, arrayList, swipeRefreshLayout);
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
recyclerView.setAdapter(myAdapter);
} else {
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState() == NetworkInfo.State.CONNECTED ||
connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState() == NetworkInfo.State.CONNECTED) {
//we are connected to a network
connected = true;
} else {
connected = false;
}
if (connected == false) {
Toast.makeText(context, "Null Data", Toast.LENGTH_LONG).show();
recyclerView.setAdapter(null);
}
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(context, "Error in Parsing =" + e, Toast.LENGTH_LONG).show();
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
}
Now I am setting recycler view in parser class not in fragment my question is ..
how can I get ArrayList back to fragment after parsing then set into recylerview adapter in fragment.
How can I set adapter in Fragment after parsing data and send
ArrayList back to fragment and set to RecyclerView adapter?
Simple,
Step 1: Create an interface
public interface OnDataRetrievalCallback {
void onDataRetrieval(ArrayList<DataStored> dataSet);
}
Step 2: Create interface instance and setter in your Parser class
public class ParseDataClass extends AsyncTask<...> {
....
...
arrayList = new ArrayList<DataStored>();//Your arrayList to be filled
private OnDataRetrievalCallback onDataRetrievalCallback;
public void setOnDataRetrievalCallback(OnDataRetrievalCallback callback) {
this.onDataRetrievalCallback = callback;
}
// You can send the data back to Fragment via onDataRetrievalCallback
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
// After parsing and filling up the data into arrayList
onDataRetrievalCallback.onDataRetrieval(arrayList); //arrayList to be sent
}
}
Step 3: set DataRetrievalCallback from your Fragment
public class MyFragment extends Fragment {
#Override
onCreateView(.....) {
ParseDataClass mparser = new ParseDataClass(getActivity(),recyclerView,mswipeRefreshLayout);
mparser.setOnDataRetrievalCallback(new OnDataRetrievalCallback{
public void onDataRetrieval(ArrayList<DataStored> dataSet) {
//dataSet is your arrayList, use it to set the adapter
}
});
mparser.execute("http://192.168.8.100/fetchtext.php", "1");
}
}
I want to count the number of elements I am getting through the JSON array, and display it over the TextView using .settext() method.
I am getting the following JSON ARRAY :
{
"result":
[
{
"id":"283",
"fullname":"shyam",
"contactno":"898888888",
"collegename":"mjc",
"emailaddress":"shyamzawar",
"eventname":"gaming"
},
{
"id":"285",
"fullname":"ffca",
"contactno":"8888888888",
"collegename":"Brihan maharashtra College of Commerce (BMCC)",
"emailaddress":"shyamzawar#ymail.com",
"eventname":"FootBall"
}
]
}
Below is my activity :
private static final String TAG = "userList";
private List<FeedItem> feedsList;
private RecyclerView mRecyclerView;
private MyRecyclerAdapter adapter;
private ProgressBar progressBar;
private TextView ParticipantsCounts;
int count=0;
private SwipeRefreshLayout swipeRefreshLayout;
private final String url="http://bmcctroika.hol.es/get-data.php";;
private int offSet = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_admin);
// Initialize recycler view
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
progressBar.setVisibility(View.VISIBLE);
ParticipantsCounts= (TextView) findViewById(R.id.ParticipantsCount);
// Downloading data from below url
new AsyncHttpTask().execute(url);
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
refreshitems();
}
});
}
private void refreshitems() {
new AsyncHttpTask().execute(url);
}
#Override
public void onRefresh() {
new AsyncHttpTask().execute(url);
}
public class AsyncHttpTask extends AsyncTask<String, Void, Integer> {
#Override
protected void onPreExecute() {
setProgressBarIndeterminateVisibility(true);
}
#Override
protected Integer doInBackground(String... params) {
Integer result = 0;
HttpURLConnection urlConnection;
try {
URL url = new URL(params[0]);
urlConnection = (HttpURLConnection) url.openConnection();
int statusCode = urlConnection.getResponseCode();
// 200 represents HTTP OK
if (statusCode == 200)
{
BufferedReader r = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = r.readLine()) != null)
{
response.append(line);
}
parseResult(response.toString());
result = 1; // Successful
} else {
result = 0; //"Failed to fetch data!";
}
} catch (Exception e) {
Log.d(TAG, e.getLocalizedMessage());
}
return result; //"Failed to fetch data!";
}
#Override
protected void onPostExecute(Integer result)
{
// Download complete.
progressBar.setVisibility(View.GONE);
if (result == 1)
{
adapter = new MyRecyclerAdapter(AdminActivity.this, feedsList);
mRecyclerView.setAdapter(adapter);
} else
{
Toast.makeText(AdminActivity.this, "Failed to fetch data!", Toast.LENGTH_SHORT).show();
}
swipeRefreshLayout.setRefreshing(false);
}
}
private void parseResult(String result) {
try {
JSONObject response = new JSONObject(result);
JSONArray posts = response.optJSONArray("result");
feedsList = new ArrayList<>();
for (int i = 0; i < posts.length(); i++) {
JSONObject post = posts.optJSONObject(i);
FeedItem item = new FeedItem();
item.setTitle(post.optString("fullname"));
item.setContact(post.optString("contactno"));
item.setEmail(post.optString("emailaddress"));
item.setEventname(post.optString("eventname"));
item.setCollegename(post.optString("collegename"));
feedsList.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
You need to get the lenght of the result JSONArray. So in your code, you can get the length of posts -- JSONArray posts = response.optJSONArray("result");.
This will give you the number of items in the result array:
private void parseResult(String result) {
try {
JSONObject response = new JSONObject(result);
JSONArray posts = response.optJSONArray("result");
int number = posts.length();
//then to set it to the text view:
ParticipantsCounts.setText(String.valueOf(number));
//the rest of your code ...
feedsList = new ArrayList<>();
for (int i = 0; i < posts.length(); i++) {
JSONObject post = posts.optJSONObject(i);
FeedItem item = new FeedItem();
item.setTitle(post.optString("fullname"));
item.setContact(post.optString("contactno"));
item.setEmail(post.optString("emailaddress"));
item.setEventname(post.optString("eventname"));
item.setCollegename(post.optString("collegename"));
feedsList.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
I am working on my movie project which fetch movie poster from URL, and then putting them into a gridview. I use asynctask to fetch JSON and the parse the url within the json file. However, when I launch my app, the grid is all empty and doing nothing until I rotate my screen or resume my app. Once I rotate my screen or resume my app. It shows all picture. I remove my api key on my code here.
public class FetchMovieTask extends AsyncTask<Void, Void, ArrayList<String>> {
private final String LOG_TAG = FetchMovieTask.class.getSimpleName();
#Override
protected ArrayList<String> doInBackground(Void... params) {
String api_key = "";
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
String movieJsonStr = null;
try {
Uri.Builder builder = new Uri.Builder();
builder.scheme("http")
.authority("api.themoviedb.org")
.appendPath("3")
.appendPath("discover")
.appendPath("movie")
.appendQueryParameter("api_key", api_key);
String myUrl = builder.build().toString();
URL Url = new URL(myUrl);
Log.v(LOG_TAG, myUrl);
// 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.
movieJsonStr = 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.
movieJsonStr = null;
}
movieJsonStr = buffer.toString();
Log.v("KPN", movieJsonStr);
} catch (IOException e) {
Log.e(LOG_TAG, "Error ", e);
// If the code didn't successfully get the weather data, there's no point in attempting
// to parse it.
movieJsonStr = null;
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 {
MovieURL = getPosterUrlFromJson(movieJsonStr);
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
e.printStackTrace();
}
return null;
}
}
private ArrayList<String> getPosterUrlFromJson(String forcastMovieStr)
throws JSONException {
final String OWM_PosterUrl = "poster_path";
final String OWM_releaseDate = "release_date";
final String OWM_overview = "overview";
final String OWM_vote_average = "vote_average";
final String OWM_original_title = "original_title";
final String OWM_results = "results";
JSONObject movieJson = new JSONObject(forcastMovieStr);
JSONArray movieArray = movieJson.getJSONArray(OWM_results);
ArrayList<String> resultStrs = new ArrayList<>();
String posterurl = "http://image.tmdb.org/t/p/w185/";
for (int i = 0; i < movieArray.length(); i++) {
// For now, using the format "Day, description, hi/low"
String title;
String overview;
String poster;
// Get the JSON object for movie poster
JSONObject moveposter = movieArray.getJSONObject(i);
poster = moveposter.getString(OWM_PosterUrl);
resultStrs.add(i,posterurl + poster);
}
return resultStrs;
}
protected void onPostExecute(ArrayList<String> strings) {
MovieURL.clear();
for (String s : strings) {
MovieURL.add(s);
}
}
Main:
public class MainActivity extends AppCompatActivity {
public static ArrayList<String> MovieURL = new ArrayList();
public static ImageListAdapter mImageListAdapter;
public GridView gridview;
#Override
protected void onStart() {
super.onStart();
new FetchMovieTask().execute();
mImageListAdapter = new ImageListAdapter(this,MovieURL);
gridview.setAdapter(mImageListAdapter);
gridview.invalidateViews();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridview = (GridView) findViewById(R.id.gridview);
}
private void updateMovieURL(){
new FetchMovieTask().execute();
gridview.invalidateViews();
}
ImagelistAdapter class
public class ImageListAdapter extends ArrayAdapter {
private Context context;
private LayoutInflater inflater;
private ArrayList<String> imageUrls;
public ImageListAdapter(Context context, ArrayList <String> imageUrls) {
super(context, R.layout.image_view, imageUrls);
this.context = context;
this.imageUrls = imageUrls;
inflater = LayoutInflater.from(context);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (null == convertView) {
convertView = inflater.inflate(R.layout.image_view, parent, false);
}
Picasso.with(context).load(imageUrls.get(position))
.placeholder(R.drawable.loading)
.into((ImageView) convertView);
return convertView;
}
}
THanks guys
In postExecute do this:
protected void onPostExecute(ArrayList<String> strings) {
MovieURL.clear();
for (String s : strings) {
MovieURL.add(s);
}
mImageListAdapter.notifyDataSetChanged();
}
I found my problem on the asynctask, I didnt override the onPostExecute method. After I override my onPostExecute, I initial my grid view
#Override
protected void onPostExecute(ArrayList<String> strings) {
super.onPostExecute(strings);
mImageListAdapter = new ImageListAdapter(MainActivity.this, MovieURL);
gridview.setAdapter(mImageListAdapter);
}
I tried the code below and also tried the AsyncTaskLoader approach. The app crashes when I instantiate the AsyncTask. Pleas advise me on the best approach to load JSON in a list fragment inside tab host.
The code below is the tab fragment (I use action bar tabs in main activity):
public class TabTop extends ListFragment {
Context context = getActivity().getBaseContext();
String API_URL = "http://api.rottentomatoes.com/api/public/v1.0/movies/770672122/similar.json?apikey=crhhxb4accwwa6cy6fxrm8vj&limit=1";
ArrayList<Deal> deals;
DealsListAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
#SuppressWarnings("unused")
int a = 0;
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
GetTopDeals getTopDeals = new GetTopDeals(context);
getTopDeals.execute(API_URL);
super.onActivityCreated(savedInstanceState);
}
class GetTopDeals extends AsyncTask<String, Void, ArrayList<Deal>>{
ProgressDialog progressDialog;
public GetTopDeals(Context activity) {
this.progressDialog = new ProgressDialog(activity);
}
#Override
protected void onPostExecute(ArrayList<Deal> result) {
adapter = new DealsListAdapter(context, result);
setListAdapter(adapter);
super.onPostExecute(result);
}
#Override
protected void onPreExecute() {
progressDialog.setCancelable(true);
progressDialog.setProgress(0);
progressDialog.setMessage("loading Top deals...");
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
super.onPreExecute();
}
#Override
protected ArrayList<Deal> doInBackground(String... urls) {
String response = sendRequest(urls[0]); // make request for json
return processResponse(response); // parse the Json and return ArrayList to postExecute
}
private String sendRequest(String apiUrl) {
BufferedReader input = null; // get the json
HttpURLConnection httpCon = null; // the http connection object
StringBuilder response = new StringBuilder(); // hold all the data from the jason in string separated with "\n"
try {
URL url = new URL(apiUrl);
httpCon = (HttpURLConnection) url.openConnection();
if (httpCon.getResponseCode() != HttpURLConnection.HTTP_OK) { // check for connectivity with server
return null;
}
input = new BufferedReader(new InputStreamReader(httpCon.getInputStream())); // pull all the json from the site
String line;
while ((line = input.readLine()) != null) {
response.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (httpCon != null) {
httpCon.disconnect();
}
}
return response.toString();
}
}
public ArrayList<Deal> processResponse(String response) {
try {
JSONObject responseObject = new JSONObject(response); // Creates a new JSONObject with name/value mappings from the JSON string.
JSONArray results = responseObject.getJSONArray("movies"); // Returns the value mapped by name if it exists and is a JSONArray.
deals = new ArrayList<Deal>();
for (int i = 0; i < results.length(); i++) { // in this loop i copy the json array to movies arraylist in order to display listView
JSONObject jMovie = results.getJSONObject(i);
int api_id = jMovie.getInt("id");
String name = jMovie.getString("title");
String content = jMovie.getString("synopsis");
JSONObject posters = jMovie.getJSONObject("posters");
String image_url = posters.getString("profile");
}
}catch (JSONException e) {
e.printStackTrace();
}
return deals;
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
Intent intent = new Intent(getActivity().getBaseContext(), DealInformation.class);
startActivity(intent);
super.onListItemClick(l, v, position, id);
}
}
Make your asynctask in his own file.
And when your asynctask is finish, implement OnPostExecute which is automatically call. Notify your adapter by a notifyDataSetChanged like that :
#Override
protected void onPostExecute(List<NewItem> list) {
Adapter.getListe().clear();
Adapter.getListe().addAll(list);
Adapter.notifyDataSetChanged();
}
thank you guys,
i want to post my answer. after some research i decided to go with AsyncTaskLoader.
this is my code
public class TabOurPicks extends ListFragment implements LoaderCallbacks<String[]> {
// when activity loads- onActivityCreated() calls the initLoader() who activate onCreateLoader()
#Override
public void onActivityCreated(Bundle savedInstance) {
super.onActivityCreated(savedInstance);
setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, new String[]{}));
getLoaderManager().initLoader(0, null,this).forceLoad();
}
// onCreateLoader instantiate the asynctaskloaser who work in bg
#Override
public RSSLoader onCreateLoader(int arg0, Bundle arg1) {
return new RSSLoader(getActivity()); //
}
// after bg process invoke onLoadFinished() who work in ui thread
#Override
public void onLoadFinished(Loader<String[]> loader, String[] data) {
setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, data
) );
}
#Override
public void onLoaderReset(Loader<String[]> arg0) {
// TODO Auto-generated method stub
}
and this is the inner class for the loader:
static public class RSSLoader extends AsyncTaskLoader<String[]>
{
public RSSLoader(Context context) {
super(context);
}
#Override
public String[] loadInBackground() {
String url = "http://api.rottentomatoes.com/api/public/v1.0/movies/770672122/similar.json?apikey=crhhxb4accwwa6cy6fxrm8vj&limit=1";
String response = sendRequest(url);
return processResponse(response);
}
private String sendRequest(String url) {
BufferedReader input = null; // get the json
HttpURLConnection httpCon = null; // the http connection object
StringBuilder response = new StringBuilder(); // hold all the data from the jason in string separated with "\n"
try {
URL apiUrl = new URL(url);
httpCon = (HttpURLConnection) apiUrl.openConnection();
if (httpCon.getResponseCode() != HttpURLConnection.HTTP_OK) { // check for connectivity with server
return null;
}
input = new BufferedReader(new InputStreamReader(httpCon.getInputStream())); // pull all the json from the site
String line;
while ((line = input.readLine()) != null) {
response.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (httpCon != null) {
httpCon.disconnect();
}
}
return response.toString();
}
private String[] processResponse(String response) {
String[] deals = null;
try {
JSONObject responseObject = new JSONObject(response); // Creates a new JSONObject with name/value mappings from the JSON string.
JSONArray results = responseObject.getJSONArray("movies"); // Returns the value mapped by name if it exists and is a JSONArray.
deals = new String[10];
for (int i = 0; i < 9; i++) { // in this loop i copy the json array to movies arraylist in order to display listView
JSONObject jMovie = results.getJSONObject(i);
String name = jMovie.getString("title");
deals[i] = name;
}
}catch (JSONException e) {
e.printStackTrace();
}
return deals;
}
}
}
It doesn't matter if your asynctask has its own file. You just don't want your activity to extends asynctask as this would make your activity asynchronous - but this is impossible to do anyways due to java's double inheritance rule.
Based on the architecture of your app and your programming style the asyntask can be an inner class in the activity. on the PostExecute method make sure you have given data to your adapter and that the adapter is set to the list, then just run notifyDataSetChanged().
Assuming your asynctask is loading data from cache or the network you are on the right track with your approach to this.