as i said in the title, i can't figure out how to get the populated array list from makePageRequest method, which uses an inner class
Using Facebook SDK forces me to use certain methods that doesn't allow me to get an arraylist values from method into a global field.
Here is my code from the ListFragment class
public class SelectionFragment extends ListFragment {
private static final String TAG = "SelectionFragment";
public static final String PAGE_URL = "1438734076389483/feed";
private static final int REAUTH_ACTIVITY_CODE = 100;
private static final String[] FROM = { "message", "crated_time", "likes" };
private static final int[] TO = { R.id.feed_box, R.id.created_time, R.id.like_count };
ArrayList<HashMap<String, String>> feedsList;
#Override
public void onAttach(Activity activity) {
Log.d(TAG, "onAttach method is called");
feedsList = new ArrayList<HashMap<String,String>>();
super.onAttach(activity);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG, "onCreateView method is called");
//super.onCreateView(inflater, container, savedInstanceState);
// Check for an open session
final Session session = Session.getActiveSession();
if (session != null && session.isOpened()) {
// Get the page's feed
makePageRequest(session);
Log.d(TAG, "makePageRequest method is called from onCreateView");
}
SimpleAdapter adapter = new SimpleAdapter(getActivity()
.getBaseContext(), feedsList, R.layout.row, FROM, TO);
setListAdapter(adapter);
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate method is called");
super.onCreate(savedInstanceState);
uiHelper = new UiLifecycleHelper(getActivity(), callback);
uiHelper.onCreate(savedInstanceState);
}
private void makePageRequest(final Session session) {
Log.d(TAG, "makePageRequest method is called");
// Make an API call to get the page feed
// and define a new callback to handle the response.
new Request(session, PAGE_URL, null, HttpMethod.GET, new Request.Callback() {
public void onCompleted(Response response) {
if (session == Session.getActiveSession()) {
if (response != null) {
jSONToArrayList(response);
}
}
if (response.getError() != null) {
// Handle errors
}
}
}).executeAsync();
}
public ArrayList<HashMap<String, String>> jSONToArrayList(
Response facebookJSON) {
Log.d(TAG, "jSONToArrayList method is called");
ArrayList<HashMap<String, String>> dataList = new ArrayList<HashMap<String, String>>();
JSONObject jSONGraphAPI;
JSONArray dataJSONArray;
int likeCount = 0;
String message = "", createdTime = "";
try {
jSONGraphAPI = facebookJSON.getGraphObject().getInnerJSONObject();
dataJSONArray = jSONGraphAPI.getJSONArray("data");
for (int i = 0; i < dataJSONArray.length(); i++) {
JSONObject feedItem = dataJSONArray.getJSONObject(i);
if (feedItem.has("created_time") && feedItem.has("message")) {
message = feedItem.getString("message");
createdTime = feedItem.getString("created_time");
if (feedItem.has("likes")) {
JSONObject likes = feedItem.getJSONObject("likes");
likeCount = likes.length();
}
// Adding value HashMap key => value
HashMap<String, String> map = new HashMap<String, String>();
map.put("message", message);
map.put("crated_time", createdTime);
map.put("likes", String.valueOf(likeCount));
dataList.add(map);
}
// Reset the values to put another data on the HashMap
likeCount = 0;
message = "";
createdTime = "";
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
feedsList = (ArrayList<HashMap<String, String>>) dataList.clone();
Log.i("feedsList from jSONToArrayList method: ", feedsList.toString());
return dataList;
}
}
The list that I want to get is feedsList to use it in my adapter. But everytime I run the code the list is empty in onCreateView method, but it's full in makePageRequest and jSONToArrayList method.
Here is a look at my logcat:
D/SelectionFragment(32558): onAttach method is called
D/SelectionFragment(32558): onCreate method is called
D/SelectionFragment(32558): onCreateView method is called
07-23 18:08:17.991: D/OpenGLRenderer(32558): Enabling debug mode 0
07-23 18:08:18.001: D/SelectionFragment(32558): makePageRequest method is called
07-23 18:08:19.221: D/SelectionFragment(32558): jSONToArrayList method is called
07-23 18:08:19.221: I/feedsList from jSONToArrayList method:(32558): [{crated_time=2014-07-23T17:53:22+0000, message=test 123, likes=2}, {crated_time=2014-07-14T10:05:09+0000, message=hello, likes=0}]
In your makePageRequest method you are making an asynchronous web service call. The callback that invokes jSONToArrayList(...) is only invoked when the HTTP call is complete.
But your code, in the onCreateView method, goes on, while another thread is making the HTTP request. So your code immediately passed the feedsList to the SimpleAdapter constructor while the list is still empty.
You should either recreate the SimpleAdapter after you re-assign the feedsList field, or you should not re-assign it (since you have already passed a reference to SimpleAdapter, in that case you need to keep using this reference.). Instead, you can call clear and addAll and make sure that the SimpleAdapter is properly notified of the change in the list contents.
Related
My app fetches data from a server and shows it in a listView. I’m sorting the data and want to show them as well so I thought to use radioButtons to change the view. With every button another content should be loaded into the List which the adapter shows. The problem is that no view comes up, my screen stays blank unfortunately. How do I load them correctly and change the input onClick? (In this case I want to show contactList and contactListTwo with the radioButtons)
That‘s my code so far. The part that I spoke about is at the bottom:
public class CallsFragment extends Fragment{
private String TAG = MainActivity.class.getSimpleName();
private ListView lv;
private static String url = "xx";
int a = 1;
String title;
private BaseAdapter mContactsAdapter;
private RadioGroup rg;
RadioButton rb1;
RadioButton rb2;
RadioButton rb3;
private final List<HashMap<String, String>> mContactsListItems = new ArrayList<>();
ArrayList<HashMap<String, String>> contactList;
ArrayList<HashMap<String, String>> contactListTwo;
private static final int rb1id = 2;
private static final int rb2id = 1;
private static final int rb3id = 0;
public CallsFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_calls, container, false);
contactList = new ArrayList<>();
contactListTwo = new ArrayList<>();
rg = (RadioGroup) view.findViewById(R.id.RGroup);
rb1 = (RadioButton) view.findViewById(R.id.radioButton5);
rb2 = (RadioButton) view.findViewById(R.id.radioButton4);
rb3 = (RadioButton) view.findViewById(R.id.radioButton6);
rb1.setId(rb1id);
rb2.setId(rb2id);
rb3.setId(rb3id);
((ListView) view.findViewById(R.id.list))
.setAdapter(mContactsAdapter);
return view;
}
private class GetContacts extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute () {
super.onPreExecute();
}
#Override
protected Void doInBackground (Void...arg0){
HttpHandler sh = new HttpHandler();
//request to url and getting response
String jsonStr = sh.makeServiceCall("https://creativecommons.tankerkoenig.de/json/list.php?lat=" + lat + "&lng=" + lon + "&rad=" + umkreis + "&sort=price&type="+ type +"&apikey=21f2ed18-88b1-5d26-34f3-28318713eaf4");
Log.e(TAG, "Response from url: " + jsonStr);
if (jsonStr != null) {
try {
JSONObject jsonObj = new JSONObject(jsonStr);
// Getting JSON Array node
JSONArray contacts = jsonObj.getJSONArray("stations");
// looping through All Contacts
for (int i = 0; i < contacts.length(); i++) {
JSONObject c = contacts.getJSONObject(i);
String id = c.getString("id");
String price = c.getString("price");
//tmp hash map for single contact
HashMap<String, String> contact = new HashMap<>();
// adding each child node to HashMap key => value
contact.put("id",id);
contact.put("price", price);
//adding contact to contact list
contactList.add(contact);
}
}
} catch (final JSONException e) {
Log.e(TAG, "Json parsing error: " + e.getMessage());
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
}
});
}
} else {
Log.e(TAG, "Couldn't get json from server.");
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
}
});
}
return null;
}
#Override
protected void onPostExecute (Void result){
super.onPostExecute(result);
/**
* Updating parsed JSON data into ListView
* */
mContactsAdapter = new SimpleAdapter(
getActivity(), mContactListItems,
R.layout.list_item, new String[]{"price", "brand",
"dist", "street", "houseNumber", "postcode", "place"}, new int[]{R.id.stoff,
R.id.brand, R.id.dist, R.id.street, R.id.houseNumber, R.id.postCode, R.id.place});
mContactListItems.addAll(contactListTwo);
mContactsAdapter.notifyDataSetChanged();
rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
mContactsListItems.clear();
switch (checkedId) {
case R.id.radioButton4:
mContactsListItems.addAll(contactList);
break;
case R.id.radioButton5:
mContactsListItems.addAll(contactListTwo);
break;
}
//mark as changed, update list
mContactsAdapter.notifyDataSetChanged();
}
});
}
}
You are passing one list object to your adapter (contactListTwo), but updating a different list object in your checked change listener (mContactsListItems). This means that your changes are totally invisible to your adapter.
To fix, change the list reference you pass to the adapter's constructor:
new SimpleAdapter(..., mContactsListItems, ...);
I notice that you never set the initial items to this list, so you may also have to call e.g. mContactsListItems.addAll(contactListTwo) before you create the adapter for the first time. That just depends on whether or not you want the list to be empty before the user changes the radio buttons.
Edit
There's a second problem: the way you assign your adapter to the ListView. In your onCreate(), I see this line:
((ListView) view.findViewById(R.id.list))
.setAdapter(mContactsAdapter);
At the point where this code runs, I don't see any initialization of mContactsAdapter, so unless you've omitted that code, this is going to be the same as writing setAdapter(null).
Later on, in onPostExecute(), you create a new adapter and assign it to mContactsAdapter. However, this doesn't actually affect the list view! You need to re-set the adapter if you re-assign its variable.
So you either have to initialize the adapter before you set it on your list view in onCreate() (which is fine to do even though you haven't loaded the data yet; the adapter will just be empty), or you have to call setAdapter() again in your onPostExecute() method to assign this new adapter to your list view.
I am quite new to the Android Development and I really need your help. My problem is in the MainActivity below. The app essentially displays a list of movies in the main activity and the movie details in another activity. And the problem is that whenever a user comes back from the MovieActivity to the MainActivity, the loader starts loading data again, although the movies are already there. And then it can not stop loading the data. It is really annoying. I want to get rid of this. So when a user comes back to the MainActivity, the loader will know that there is already loaded data and will not load anything again.If it helps, here is my full GitHub repo https://github.com/mateuszwojnarowicz/PopularMovies
I am stuck for about 3 weeks and have tried hundreds of possible solutions. Nothing seems to work. I feel really desperate.
Thank you so much for help,
Matthew
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<String> {
private MovieAdapter mAdapter;
private ArrayList<Movie> mMoviesCollection;
private SharedPreferences sharedPreferences;
private Resources resources;
private LoaderManager loaderManager;
private Loader<String> loader;
private RecyclerView.LayoutManager layoutManager;
private String sortBy;
#BindView(R.id.pb)
ProgressBar progressBar;
#BindView(R.id.er)
TextView errorTextView;
#BindView(R.id.rv)
RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
mMoviesCollection = new ArrayList<Movie>();
sharedPreferences = getSharedPreferences(Constants.SHARED_PREFS, Activity.MODE_PRIVATE);
resources = getResources();
sortBy = sharedPreferences.getString(Constants.KEY_SORT, null);
setSharedPref();
layoutManager = new GridLayoutManager(this, calculateNoOfColumns(this));
loaderManager = getLoaderManager();
loader = loaderManager.getLoader(Constants.LOADER_MOVIES_ID);
initialize();
makeOperationLoadMovies(sortBy);
}
public static int calculateNoOfColumns(Context context) {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
float dpWidth = displayMetrics.widthPixels / displayMetrics.density;
int noOfColumns = (int) (dpWidth / 150);
return noOfColumns;
}
//Set first-launch pref and set title according to pref
private void setSharedPref(){
if(!sharedPreferences.contains(Constants.KEY_SORT)) {
saveData(Constants.VALUE_POP);
setTitle(resources.getString(R.string.title_pop));
} else {
if (Objects.equals(sharedPreferences.getString(Constants.KEY_SORT, null), Constants.VALUE_POP)) {
setTitle(resources.getString(R.string.title_pop));
}
if (Objects.equals(sharedPreferences.getString(Constants.KEY_SORT, null), Constants.VALUE_TOP)) {
setTitle(resources.getString(R.string.title_top));
}
}
}
//Set up the RecyclerView
private void initialize(){
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
mMoviesCollection = new ArrayList<>();
mAdapter = new MovieAdapter(mMoviesCollection, this, this);
recyclerView.setAdapter(mAdapter);
}
private void makeOperationLoadMovies(String SORT_BY){
Bundle bundle = new Bundle();
bundle.putString(Constants.LOADER_MOVIES_EXTRA, SORT_BY);
if(recyclerView.isDirty()){
}
else if(loader==null){
loaderManager.initLoader(Constants.LOADER_MOVIES_ID, bundle, this);
}else{
loaderManager.restartLoader(Constants.LOADER_MOVIES_ID, bundle, this);
}
}
//Update shared pref
private void saveData(String SORT_VALUE){
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(Constants.KEY_SORT, SORT_VALUE);
editor.apply();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id){
case R.id.menu_fav:
startActivity(new Intent(MainActivity.this, FavoritesActivity.class));
break;
case R.id.menu_pop:
saveData(Constants.VALUE_POP);
Toast.makeText(this, resources.getString(R.string.message_popularity),Toast.LENGTH_LONG).show();
break;
case R.id.menu_top:
saveData(Constants.VALUE_TOP);
Toast.makeText(this, resources.getString(R.string.message_rating),Toast.LENGTH_LONG).show();
break;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onPause() {
super.onPause();
Parcelable recyclerViewState;
recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState();//save
recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);
}
#Override
protected void onPostResume() {
super.onPostResume();
Parcelable recyclerViewState;
recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState();//save
recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);
}
#SuppressLint("StaticFieldLeak")
#Override
public Loader<String> onCreateLoader(int id, final Bundle args) {
return new AsyncTaskLoader<String>(this) {
#Override
protected void onStartLoading() {
super.onStartLoading();
forceLoad();
progressBar.setVisibility(View.VISIBLE);
errorTextView.setVisibility(View.INVISIBLE);
}
#Override
public void deliverResult(String data) {
super.deliverResult(data);
}
#Override
public String loadInBackground() {
String jsonString = "";
URL url = NetworkUtils.buildUrl(args.getString(Constants.LOADER_MOVIES_EXTRA));
try {
jsonString += NetworkUtils.getResponseFromHttpUrl(url);
} catch (IOException e) {
e.printStackTrace();
}
if(jsonString.isEmpty()){
} else {
try {
JSONObject jsonObject = new JSONObject(jsonString);
JSONArray jsonArray = jsonObject.getJSONArray(Constants.JSON_KEY_MOVIE_RESULTS);
for (int i = 0; i < jsonArray.length(); i++) {
//Get 1 movie from JSON
String mTitle;
int mId;
String mPosterUrl;
String mPlot;
double mUserRating;
String mReleaseDate;
JSONObject Jmovie = (JSONObject) jsonArray.get(i);
mTitle = Jmovie.getString(Constants.JSON_KEY_MOVIE_TITLE);
mId = Jmovie.getInt(Constants.JSON_KEY_MOVIE_ID);
mPosterUrl = NetworkUtils.getPosterString(Jmovie.getString(Constants.JSON_KEY_MOVIE_POSTER_PATH));
mPlot = Jmovie.getString(Constants.JSON_KEY_MOVIE_OVERVIEW);
mUserRating = Jmovie.getDouble(Constants.JSON_KEY_MOVIE_VOTE_AVERAGE);
mReleaseDate = Jmovie.getString(Constants.JSON_KEY_MOVIE_RELEASE_DATE);
//Get videos
ArrayList<Video> mVideos = new ArrayList<Video>();
URL videosURL = NetworkUtils.buildUrlVideos(String.valueOf(mId));
String videosJSON = NetworkUtils.getResponseFromHttpUrl(videosURL);
JSONObject jsonObjectVideos = new JSONObject(videosJSON);
JSONArray jsonArrayVideos = jsonObjectVideos.getJSONArray(Constants.JSON_KEY_VIDEO_RESULTS);
if(jsonArrayVideos.length()==0){
mVideos = null;
} else {
for(int v = 0; v < jsonArrayVideos.length(); v++){
JSONObject Jvideo = (JSONObject) jsonArrayVideos.get(v);
String mVideoName;
String mVideoUrlString;
mVideoName = Jvideo.getString(Constants.JSON_KEY_VIDEO_NAME);
mVideoUrlString = "https://www.youtube.com/watch?v="+Jvideo.getString(Constants.JSON_KEY_VIDEO_KEY);
Video video = new Video(mVideoName, mVideoUrlString);
mVideos.add(video);
}
}
//GetReviews
ArrayList<Review> mReviews = new ArrayList<Review>();
URL reviewsURL = NetworkUtils.buildUrlReviews(String.valueOf(mId));
String reviewsJSON = NetworkUtils.getResponseFromHttpUrl(reviewsURL);
JSONObject jsonObjectReviews = new JSONObject(reviewsJSON);
JSONArray jsonArrayReviews = jsonObjectReviews.getJSONArray(Constants.JSON_KEY_REVIEW_RESULTS);
if(jsonArrayReviews.length()!=0) {
for(int r = 0; r < jsonArrayReviews.length(); r++){
JSONObject Jreview = (JSONObject) jsonArrayReviews.get(r);
String mReviewName;
String mReviewText;
mReviewName = Jreview.getString(Constants.JSON_KEY_REVIEW_AUTHOR);
mReviewText = Jreview.getString(Constants.JSON_KEY_REVIEW_CONTENT);
Review review = new Review(mReviewName, mReviewText);
mReviews.add(review);
}
}
Movie movie = new Movie(mTitle, mId, mPosterUrl, mPlot, mUserRating, mReleaseDate, mVideos, mReviews);
mMoviesCollection.add(movie);
}
} catch (JSONException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}
}
return null;
}
};
}
#Override
public void onLoadFinished(Loader<String> loader, String data) {
progressBar.setVisibility(View.GONE);
mAdapter.notifyDataSetChanged();
}
#Override
public void onLoaderReset(Loader<String> loader) {
}
}
Because you are new to Android there is a lot wrong. So, many people probably won't want to chime in. Regardless, I'm new as well and in the same class as you are right now, so I'll give it a shot.
First, your loader is not returning the correct data type. Your loader should be of Loader<List<Movie>> and it should return a new AsyncTaskLoader<List<Movie>>. The reason you want this is to make use of everything the AsyncTaskLoader has to offer. I'll explain further.
Second, we'll cache the data inside the loader by moving the initial reference from the Activity into the loader.
So move private ArrayList<Movie> mMoviesCollection; as an instance variable of your AsyncTaskLoader. Remove the line mMoviesCollection = new ArrayList<Movie>(); from both your onCreate and initialize methods.
In your AsyncTaskLoader, you need to check if your data exists already in your onStartLoading before forceLoad and implement deliverResult.
So, your onStartLoading() should look like this:
#Override
protected void onStartLoading() {
super.onStartLoading();
if(mMoviesCollection.isEmpty()){
forceLoad();
progressBar.setVisibility(View.VISIBLE);
errorTextView.setVisibility(View.INVISIBLE);
} else {
deliverResult(mMoviesCollection)
}
}
And your deliverResult should look like this:
#Override
public void deliverResult(List<Movie> data) {
mMoviesCollection = data;
super.deliverResult(data);
}
Now you need to implement a setData(List<Movie> movies) method that sets your adapter's data instance variable and calls notifyDataSetChanged() in your Adapter. Like so:
public void setData(List<Movie> movies){
mMovies = movies;
notifyDataSetChanged();
}
Get rid of the List<Movie> from your adapter's constructor. This way you can construct the adapter without any data. The adapter's getItemCount() should return 0 if the data is null and the recyclerView will not try to build the view.
With that done you can then call onLoadFinished like this:
#Override
public void onLoadFinished(Loader<List<Movie>> loader, List<Movie> data) {
progressBar.setVisibility(View.GONE);
mAdapter.setData(data);
}
EDIT: Made a correction to account for the ArrayList instantiating as an Instance variable. You can either not instantiate the mMoviesCollection there and then do so later or just check if its empty with mMoviesCollection.isEmpty() as I changed above in onStartLoading.:
EDIT:
You need to get your libraries straight, you are using android.app in some places and android.support in others.
So in your imports change these:
import android.app.LoaderManager;
import android.content.AsyncTaskLoader;
import android.content.Loader;
all to:
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
Now the TMDB.org API has a request limit of 40 requests per 10 seconds.
https://developers.themoviedb.org/3/getting-started/request-rate-limiting
Because of this, your Loader is not even completing everything and is throwing an exception. I would suggest breaking up when you call the videos and reviews into the MovieActivity by creating another AsyncTaskLoader there and calling each when the details screen loads.
You could also technically add a Thread.sleep(300) or less to your AsyncTaskLoader but it makes it seriously slow. In other words, you would have to push the data beyond the 10-second mark to load completely.
Now, with that and the changes we have made, everything does survive config changes such as screen rotation.
If you want the data to survive any further you will have to persist the data somehow. Like saving the json response as a string in onSaveInstanceState or saving the JSon String to the database you created.
I use Volley in the onCreate of my Activity which gets a string on my server, then I convert this string to an arraylist,checkedContactsAsArrayList, and I pass it over to my custom adapter using sharedpreferences, which does stuff with the arraylist in the listview.
But the custom adapter keeps getting the previous arraylist in sharedpreferences, not the one I've just got from the server. The Volley call is too late or something - I can see in logcat the latest values are put after they are got, if you know what I mean.
For example:
VolleyCall 1 putString: 1,2,3
VolleyCall 2 putString: 4,5,6
VolleyCall 3 putString: 7,8,9
Custom Adapter 1 getString: gets values of the last time app was used
Custom Adapter 2 getString: 1,2,3
Custom Adapter 3 getString: 4,5,6
Any idea how to fix this? I could try doing the Volley call in the getView of my custom adapter but I've read on Stackoverflow that's bad practice.
Here are the relvant parts of my code - I've slimmed it down a bit, as there's a lot of stuff in there irrelevant to this issue.
Here's the code of my activity, ViewContact:
public class ViewContact extends AppCompatActivity implements android.widget.CompoundButton.OnCheckedChangeListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(activity_view_contact);
//selectPhoneContacts is an empty array list that will hold our SelectPhoneContact info
selectPhoneContacts = new ArrayList<SelectPhoneContact>();
listView = (ListView) findViewById(R.id.listviewPhoneContacts);
StringRequest stringRequest = new StringRequest(Request.Method.POST, ViewContact_URL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
//toast the response of ViewContact.php, which has been converted to a
//JSON object by the Php file with JSON encode
Toast.makeText(ViewContact.this, "OnResponse is" + response, Toast.LENGTH_LONG).show();
System.out.println("ViewContact: And the response is " + response);
try {
//checkedContacts is a String
String checkedContacts = responseObject.getString("checkedcontacts");
//convert the checkedContacts string to an arraylist
checkedContactsAsArrayList = new ArrayList<String>(Arrays.asList(checkedcontacts.split(",")));
System.out.println("ViewContact: checkedContactsAsArrayList is " + checkedContactsAsArrayList);
//we want to bring the checkedContactsAsArrayList array list to our SelectPhoneContactAdapter.
// It looks like Shared Preferences
//only works easily with strings so best way to bring the array list in Shared Preferences is with
//Gson.
//Here, we PUT the arraylist into the sharedPreferences
SharedPreferences sharedPreferencescheckedContactsAsArrayList = PreferenceManager.getDefaultSharedPreferences(getApplication());
SharedPreferences.Editor editorcheckedContactsAsArrayList = sharedPreferencescheckedContactsAsArrayList.edit();
Gson gsoncheckedContactsAsArrayList = new Gson();
String jsoncheckedContactsAsArrayList = gsoncheckedContactsAsArrayList.toJson(checkedContactsAsArrayList);
editorcheckedContactsAsArrayList.putString("checkedContactsAsArrayList", jsoncheckedContactsAsArrayList);
editorcheckedContactsAsArrayList.commit();
System.out.println("ViewContact: jsoncheckedContactsAsArrayList is " + jsoncheckedContactsAsArrayList);
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(ViewContact.this, error.toString(), Toast.LENGTH_LONG).show();
}
}) {
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
//we are posting review_id into our ViewContact.php file, which
//we get when a row is clicked in populistolistview
//to get matching details
params.put("review_id", review_id);
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(stringRequest);
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//checkBoxforContact.setChecked(true);
}
//******for the phone contacts in the listview
// Load data in background
class LoadContact extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... voids) {
//we want to delete the old selectContacts from the listview when the Activity loads
//because it may need to be updated and we want the user to see the updated listview,
//like if the user adds new names and numbers to their phone contacts.
selectPhoneContacts.clear();
SelectPhoneContact selectContact = new SelectPhoneContact();
selectContact.setName(phoneNameofContact);
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
adapter = new SelectPhoneContactAdapter(selectPhoneContacts, ViewContact.this,0);
listView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
#Override
protected void onResume() {
super.onResume();
// getPrefs();
ViewContact.LoadContact loadContact = new ViewContact.LoadContact();
loadContact.execute();
Toast.makeText(ViewContact.this, "resuming!", Toast.LENGTH_SHORT).show();
}
}
And my custom adapter, SelectPhoneContactAdapter :
public class SelectPhoneContactAdapter extends BaseAdapter {
//define a list made out of SelectPhoneContacts and call it theContactsList
public List<SelectPhoneContact> theContactsList;
//define an array list made out of SelectContacts and call it arraylist
private ArrayList<SelectPhoneContact> arraylist;
Context _c;
ArrayList<String> MatchingContactsAsArrayList;
ArrayList<String> checkedContactsAsArrayList;
ArrayList <String> allNamesofContacts;
String contactToCheck;
//we will run through different logic in this custom adapter based on the activity that is passed to it
private int whichactivity;
String phoneNumberofContact;
String[] phoneNumberofContactStringArray;
String ContactsString;
Intent intent;
public SelectPhoneContactAdapter(final List<SelectPhoneContact> selectPhoneContacts, Context context, int activity) {
theContactsList = selectPhoneContacts;
_c = context;
this.arraylist = new ArrayList<SelectPhoneContact>();
this.arraylist.addAll(theContactsList);
whichactivity = activity;
//we are fetching the array list checkedContactsAsArrayList, created in ViewContact.
//with this we will put a tick in the checkboxes of contacts the review is being shared with
SharedPreferences sharedPreferencescheckedContactsAsArrayList = PreferenceManager.getDefaultSharedPreferences(_c);
Gson gsoncheckedContactsAsArrayList = new Gson();
String jsoncheckedContactsAsArrayList = sharedPreferencescheckedContactsAsArrayList.getString("checkedContactsAsArrayList", "");
Type type2 = new TypeToken<ArrayList<String>>() {
}.getType();
checkedContactsAsArrayList = gsoncheckedContactsAsArrayList.fromJson(jsoncheckedContactsAsArrayList, type2);
System.out.println("SelectPhoneContactAdapter checkedContactsAsArrayList :" + checkedContactsAsArrayList);
}
}
#Override
public int getCount() {
return arraylist.size();
}
#Override
public Object getItem(int i) {
return arraylist.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
static class ViewHolder {
//In each cell in the listview show the items you want to have
//Having a ViewHolder caches our ids, instead of having to call and load each one again and again
TextView title, phone;
CheckBox check;
Button invite;
}
#Override
public View getView(final int i, View convertView, ViewGroup viewGroup) {
//this is the SelectPhoneContact object; consists of textboxes, buttons, checkbox
final SelectPhoneContact data = (SelectPhoneContact) arraylist.get(i);
ViewHolder holder = null;
if (convertView == null) {
//if there is nothing there (if it's null) inflate the view with the layout
LayoutInflater li = (LayoutInflater) _c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = li.inflate(R.layout.phone_inflate_listview, null);
holder = new ViewHolder();
//So, for example, title is cast to the name id, in phone_inflate_listview,
//phone is cast to the id called no etc
holder.title = (TextView) convertView.findViewById(R.id.name);
holder.phone = (TextView) convertView.findViewById(R.id.no);
holder.invite = (Button) convertView.findViewById(R.id.btnInvite);
holder.check = (CheckBox) convertView.findViewById(R.id.checkBoxContact);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
//in the listview for contacts, set the name
holder.title.setText(data.getName());
//in the listview for contacts, set the number
holder.phone.setText(data.getPhone());
holder.check.setTag(data);
return convertView;
}
}
Call this: loadContact.execute();
After you call .commit();
ViewContact.LoadContact loadContact = new ViewContact.LoadContact();
loadContact.execute();
I am trying to populate fragment listview using async task,
But listvew is not populating. I am getting data in logs, And there is no error and exception in logs.
I am following this example
dynamic listview adding "Load more items" at the end of scroll
Here is code:-
public class HindiFragment extends Fragment {
// XML node keys
static final String KEY_SONG = "song"; // parent node
static final String KEY_ID = "id";
static final String KEY_TITLE = "title";
static final String KEY_ARTIST = "artist";
static final String KEY_DURATION = "duration";
static final String KEY_THUMB_URL = "thumb_url";
static final String KEY_VIDEO_URL = "video";
static final String KEY_UPLOAD_BY = "upload_by";
Context abc=null;
static int startIndex = 0;
private WeakReference<MyAsyncTask> asyncTaskWeakRef;
ListView list;
static LazyAdapter adapter;
JSONObject json;
static int offset = 10;
static ArrayList<HashMap<String, String>> songsList = new ArrayList<HashMap<String, String>>();
public static Context hindiFragment=null;
private static int catId=0;
static View rootView ;
public HindiFragment(){}
public HindiFragment(int position) {
// TODO Auto-generated constructor stub
catId=position;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
//StrictMode.setThreadPolicy(policy);
rootView = inflater.inflate(R.layout.main, container, false);
// TextView tvLabel = (TextView)rootView.findViewById(R.id.txtLabel);
// tvLabel.setText("Hello"); try
hindiFragment=rootView.getContext();
try{
//Toast.makeText(hindiFragment, "catid is "+catId,
// Toast.LENGTH_LONG).show();
UserFunctions userFunction = new UserFunctions();
json=userFunction.getAndroidVersion();
JSONArray android_version_array = json.getJSONArray("version");
TextView tv = (TextView) rootView.findViewById(R.id.android_version);
//getting android version
for (int i = 0; i < android_version_array.length(); i++) {
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
JSONObject myObj = android_version_array.getJSONObject(i);
if(! myObj.getString("version").equalsIgnoreCase(String.valueOf(getString(R.string.android_version)))){
tv.setText( Html.fromHtml(myObj.getString("text")));
tv.setMovementMethod(LinkMovementMethod.getInstance());
}else
{
tv.setVisibility(View.GONE);
}
// adding each child node to HashMap key => value
}
startNewAsyncTask(this.getActivity());
return rootView;
}catch(Exception e){
e.printStackTrace();
}
return rootView;
}
public static void loadMore(int startIndex,int page,Activity myActivity){
try{
UserFunctions userFunction = new UserFunctions();
Log.e("page ",""+page);
int status=0;
JSONObject json;
json = userFunction.getChannelData(String.valueOf(catId),page);
if(json.has("video")){
JSONArray deletedtrs_array = json.getJSONArray("video");
for (int i = 0; i < deletedtrs_array.length(); i++) {
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
JSONObject myObj = deletedtrs_array.getJSONObject(i);
// adding each child node to HashMap key => value
map.put(KEY_ID, myObj.getString("uid"));
map.put(KEY_TITLE, myObj.getString("uid"));
map.put(KEY_ARTIST,myObj.getString("video"));
map.put(KEY_DURATION, myObj.getString("duration"));
map.put(KEY_THUMB_URL,myObj.getString("thumb_url"));
map.put(KEY_VIDEO_URL, myObj.getString("url"));
map.put(KEY_UPLOAD_BY,"By: "+ myObj.getString("upload_by"));
// adding HashList to ArrayList
//if(!songsList.contains(map))
{
songsList.add(map);
status=1;
}
}
}
//if(status==1)
{
//]list=(ListView)rootView.findViewById(R.id.list);
// Getting adapter by passing xml data ArrayList
// adapter=new LazyAdapter(myActivity, songsList);
// list.setAdapter(adapter);
// adapter.notifyDataSetChanged();
}
}catch(Exception e){
e.printStackTrace();
}
}
private void startNewAsyncTask(Activity act) {
MyAsyncTask asyncTask = new MyAsyncTask(act);
this.asyncTaskWeakRef = new WeakReference<MyAsyncTask >(asyncTask );
asyncTask.execute();
}
private static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
private WeakReference<HindiFragment> fragmentWeakRef;
HindiFragment uindiFragment;
Activity myActivity;
private MyAsyncTask (Activity activity) {
this.fragmentWeakRef = new WeakReference<HindiFragment>(uindiFragment);
myActivity=activity;
}
#Override
protected Void doInBackground(Void... params) {
//Toast.makeText(hindiFragment, "helllo",
// Toast.LENGTH_LONG).show();
//TODO: your background code
Log.e("Now in background",offset+"");
loadMore(startIndex, offset,myActivity);
return null;
}
#Override
protected void onPostExecute(Void response) {
super.onPostExecute(response);
ListView list=(ListView)rootView.findViewById(R.id.list);
// Getting adapter by passing xml data ArrayList
adapter=new LazyAdapter(myActivity, songsList);
list.setAdapter(adapter);
adapter.notifyDataSetChanged();
Log.e("Ended here11 ","now endeded11");
if (this.fragmentWeakRef.get() != null) {
//TODO: treat the result
adapter.notifyDataSetChanged();
}
}
}
}
You are over-using weak reference. My guess is your async task or fragment is being garbage collected since you use them cyclically: you can verify this by seeing if weakReference.get() returns null.
In fact, you don't need WeakReference at all: just implement appropriate cancel logic that you can call from onPause onStop or onDestroy depending on how you want to handle repeated calls.
Also you shouldn't pass the context to your Async class: instead create an observer such as:
public interface Callback {
public void onAsyncDone(Arraylist<DataItem> listItems);
}
and if not cancelled,
#Override public void onPostExecute(Void v) {
if (!isCancelled()) {
Callback c = callbackReference.get();
if (c != null) c.onAsyncDone(getListItems());
}
}
where getListItems() returns whatever work is done in doInBackground. Here I use a weak reference for the callback (which you implement in your activity) since you seem to want to use one. But again, as long as you release the reference to the context if cancelled, you don't actually need one. The reason the activity is wrapped as the Callback is that the async task should only have one job: process the items and pass them along. Let your activity or controller change the UI with the new items.
I suspect the loadMore() method does not load up any data to object songsList into the adapter. Simply trace the reason why it is not. There's no way I can debug this without using debugger, the code flow is rather complicated with unusually tight references and, more so, with static access.
The suspected code for review:
protected void onPostExecute(Void response) {
super.onPostExecute(response);
ListView list=(ListView)rootView.findViewById(R.id.list);
// Getting adapter by passing xml data ArrayList
adapter=new LazyAdapter(myActivity, songsList);
list.setAdapter(adapter);
adapter.notifyDataSetChanged();
...
}
Note: You can put some good logging in LazyAdapter code and see if data is populated there.
When I run my app, onPostExecute doesn't seem to be called. It is not populated the UI like it should be. Also, on DoInBackground, any log messages past the for loop:
for (int i = 0; i < businesses.length(); i++) { }
excluding the log messages in that particular for loop are not shown. So for example, the log message in the 2nd for loop for(int j = 0; j < businessNames.size(); j++) { } are not shown for some reason. Is this a timing issue or am I missing something?
But just to sum up, the UI in my onPostExecute is not being hit (as I know of).
Here is my code
public class CoffeeResultActivity extends Activity{
ExpandableListAdapter listAdapter;
ExpandableListView expListView;
List<String> businessNames = new ArrayList<String>();
List<String> businessInfo = new ArrayList<String>();
HashMap<String, List<String>> listDataChild = new HashMap<String, List<String>>();
private int lastExpandedPosition = -1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
expListView = (ExpandableListView) findViewById(R.id.lvExp);
//Calling AsyncTask
new RetreiveSearchResults().execute("coffee");
// Listview Group click listener
expListView.setOnGroupClickListener(new OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
return false;
}
});
expListView.setOnGroupExpandListener(new OnGroupExpandListener() {
#Override
public void onGroupExpand(int groupPosition) {
if (lastExpandedPosition != -1 && groupPosition != lastExpandedPosition) {
expListView.collapseGroup(lastExpandedPosition);
}
lastExpandedPosition = groupPosition;
}
});
// Listview Group collasped listener
expListView.setOnGroupCollapseListener(new OnGroupCollapseListener() {
#Override
public void onGroupCollapse(int groupPosition) {
Toast.makeText(getApplicationContext(),
businessNames.get(groupPosition) + " Collapsed",
Toast.LENGTH_SHORT).show();
}
});
// Listview on child click listener
expListView.setOnChildClickListener(new OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
// TODO Auto-generated method stub
Toast.makeText(
getApplicationContext(),
businessNames.get(groupPosition)
+ " : "
+ listDataChild.get(
businessNames.get(groupPosition)).get(
childPosition), Toast.LENGTH_SHORT)
.show();
return false;
}
});
}
class RetreiveSearchResults extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... terms) {
// Some example values to pass into the Yelp search service.
String category = "coffee";
// Execute a signed call to the Yelp service.
OAuthService service = new ServiceBuilder().provider(YelpApi2.class).apiKey("key").apiSecret("key").build();
Token accessToken = new Token("key", "key");
OAuthRequest request = new OAuthRequest(Verb.GET, "http://api.yelp.com/v2/search");
request.addQuerystringParameter("location", "Waterfront, Boston, MA");
request.addQuerystringParameter("category", category);
service.signRequest(accessToken, request);
Response response = request.send();
String rawData = response.getBody();
try {
JSONObject json = new JSONObject(rawData);
JSONArray businesses;
businesses = json.getJSONArray("businesses");
for (int i = 0; i < businesses.length(); i++) {
JSONObject business = businesses.getJSONObject(i);
//Log.d("FOO FOO", "FOO FOO FOO" + business.toString());
businessNames.add(business.get("name").toString());
//The following log message gets displayed
Log.d("FOO FOO", "FOO FOO " + businessNames.get(i));
businessInfo.add(business.get("rating").toString());
//The following log message gets displayed
Log.d("FOO FOO", "FOO FOO " + businessInfo.get(i));
}
//The following log message gets displayed
Log.d("FOO FOO", "SIZE" + businessNames.size());
for(int j = 0; j < businessNames.size(); j++) {
//The following log message DOES NOT GET DISPLAYED. But it does run through this for loop in debugger.
Log.d("FOO FOO", "FOO FOO ##### Get Here?);
//In Debugger, listDataChild does get populated.
listDataChild.put(businessNames.get(j), businessInfo);
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
protected void onPostExecute() {
//Does not enter onPostExecute in Debugger nor on a Regular run.
//Log message does NOT get printed
Log.d("FOO FOO", "FOO FOO Get in POST?");
listAdapter = new ExpandableListAdapter(CoffeeResultActivity.this, businessNames, listDataChild);
listAdapter.notifyDataSetChanged();
// setting list adapter
expListView.setAdapter(listAdapter);
}
}
}
The signature of onPostExecute is wrong. It should be like
protected void onPostExecute(Void result) {
}
Your onPostExecute does not match the AsyncTasks signature.
Try adding a Void parameter to the method like so:
protected void onPostExecute(Void result){}
You seem to have forgot to add your #Override tag to your onPostExecute