Update ListView Adapter input with radioButtons - java

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.

Related

How can I make sharedpreferences in Custom Adapter get the latest values of my ArrayList?

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();

How do I go about applying data I get from doInBackground() to apply to my RecyclerView?

I have viewed over 50 pages to find solution for my extremely simple app, but none seems to work for me. Please help.
Problem: I have a refresh button in the menu in MainActivity. When this is pressed, I want to execute my AsyncTask, then update ALL items in my RecyclerView.
Situation.
My app fetches data from API by OpenWeatherMap.org, then displays the data.
I have a MainActivity class (And my recyclerView resides in here.)
For recyclerView, I'm using RecyclerView.Adapter with GridViewManager.
I have a separate AsyncTask class.
So, what I have tried and did not work:
Method 1. Normal way. When refresh button selected, call my AsyncTask. In my PostExecute(), I am calling setter in the MainActivity
public void setWeatherData(String[] weatherData) {this.weatherData = weatherData;}
to assign the result array from doInBackGround method.
Then in MainActivity,
myAsyncTask.execute("43017,us");
recyclerView.recyclerView.getAdapter().notifyDataSetChanged();
But this causes notifyDataSetChanged(); to be called BEFORE member vairable array in MainActivity is updated from onPostExecute().
Method 2. Trying to update UI entirely from onPostExecute method in MyAsyncTask.class.
Well I know onPostExecute, even when it is written in different class, runs on the UI thread. So within the method, I did something like
MainActivity mainActivity = new MainActivity();
RecyclerView recyclerView = mainActivity.findViewById(R.id.recyclerView);
RecyclerView.Adapter adapter = recyclerView.getAdapter();
adapter.notifyDataSetChanged();
In this method, with logging, I've confirmed that onPostExecute successfully updates the member variable in the MainActivity, it's just that notifyDataSetChanged gets called TOO early, specifically before onPostExecute is complete in the background.
I hope to get an answer for this and was clear enough about my situation. I will post my MainActivity, Adapter and AsyncTask codes down below.
MainActivity.java:
public class MainActivity extends AppCompatActivity {
private String weatherData[] = {
"Today - Sunny",
"Tomorrow - Cloudy",
"Tuesday - Rainy",
"Wednesday - Sunny",
"Thursday - Sunny",
"Friday - Sunny",
"Saturday - Cloudy",
"Sunday - Rainy :/"
};
private RecyclerView recyclerView;
private mAdapter adapter;
private static final int SPAN_COUNT = 1;
private MyAsyncTask myAsyncTask = new MyAsyncTask();
private Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView)findViewById(R.id.recyclerview_weatherData);
setLayout(getApplicationContext());
adapter = new mAdapter(weatherData);
recyclerView.setAdapter(adapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id){
case R.id.action_refresh:
Log.v("Menu", "Refresh button selected.");
//for now, take some random ZIP code
myAsyncTask.execute("43017,us");
recyclerView.getAdapter().notifyDataSetChanged();
adapter.refreshContents(weatherData);
for (int i = 0; i<weatherData.length; i++) {
Log.v("Refresh button", weatherData[i].toString());
}
}
return true;
}
public void setLayout(Context context) {
int scrollPosition = 0;
//make a GridLayoutManager with 2 columns
LinearLayoutManager mLayoutManager = new LinearLayoutManager(context);
//set the mLayoutManager to the one that I just created
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.scrollToPosition(scrollPosition);
recyclerView.setLayoutManager(new GridLayoutManager(context, SPAN_COUNT));
//set the offset decoration definition to my layout
int middle_spacing = 30;
boolean includeEdge = true;
recyclerView.addItemDecoration(new ItemOffsetDecoration(SPAN_COUNT, middle_spacing, includeEdge));
}
public void setWeatherData(String[] weatherData) {
this.weatherData = weatherData;
}
public String[] getWeatherData() { return weatherData; }
}
MyAsyncTask.java:
public class MyAsyncTask extends AsyncTask<String,Void,String[]> {
public final static String OPEN_WEATHER_MAP_API_KEY = "bc607b72747aa672bf2ac9a5f3a5fc84";
String forecastJsonStr = null;
private String format = "json";
private String units = "metric";
private int numDays = 7;
private String data[] =null;
private RecyclerView recyclerView;
private MainActivity mainActivity;
private RecyclerView.Adapter adapter;
#Override
protected String[] doInBackground(String... params) {
if (params.length == 0) {
Log.v("AsyncTask", "No parameter is taken.");
return null;
}
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
try {
final String FORECAST_BASE_URL = "http://api.openweathermap.org/data/2.5/forecast/daily?";
final String QUERY_PARAM = "q";
final String FORMAT_PARAM = "mode";
final String UNITS_PARAM = "units";
final String DAYS_PARAM = "cnt";
final String APPID_PARAM = "APPID";
Uri builtUri = Uri.parse(FORECAST_BASE_URL).buildUpon()
.appendQueryParameter(QUERY_PARAM, params[0])
.appendQueryParameter(FORMAT_PARAM, format)
.appendQueryParameter(UNITS_PARAM, units)
.appendQueryParameter(DAYS_PARAM, Integer.toString(numDays))
.appendQueryParameter(APPID_PARAM, OPEN_WEATHER_MAP_API_KEY)
.build();
URL url = new URL(builtUri.toString());
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
return null;
}
//put the buffer in String var forecastJsonStr
forecastJsonStr = buffer.toString();
Log.v("AsyncTask", forecastJsonStr.toString());
} catch (IOException e) {
return null;
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("Async", "Reader is null, something wrong.");
}
}
}
//Then put the string contents into an array
try {
ParseWeatherData parser = new ParseWeatherData();
data = parser.getWeatherDataFromJson(forecastJsonStr, numDays);
return data;
} catch (JSONException e) {
e.printStackTrace();
}
return data;
}
#Override
protected void onPostExecute(final String data[]) {
super.onPostExecute(data);
if (data != null) {
//this log works fine: the fetched data is successfully stored...
for (int i = 0; i<data.length; i++) {
Log.v("onPostExecute", data[i].toString());
}
//how do I pass this data to the main thread?
mainActivity = new MainActivity();
mainActivity.setWeatherData(data);
}
}
}
Finally, mAdapter.java:
public class mAdapter extends RecyclerView.Adapter<mAdapter.ViewHolder> {
private String data[];
public mAdapter(String data[]) {
this.data = data;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View listView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_single_list, parent, false);
return new ViewHolder(listView);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.weather.setText(data[position]);
Log.v("BindView", "Item " + position + " set.");
}
#Override
public int getItemCount() {
if (data == null) {
Log.v("WeatherAdapter", "Oops, getting null in the adapter.");
return 0;
} else {
return data.length;
}
}
public void refreshContents(String data[]) {
this.data = null;
this.data = data;
notifyDataSetChanged();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView weather, day;
//currently ViewHolder is set as the TextView for logging
public ViewHolder(View v) {
super(v);
weather = (TextView) v.findViewById(R.id.test_text);
// Define click listener for the ViewHolder's View.
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "Element " + getAdapterPosition() + " clicked.");
}
});
}
}
}
Thank you in advance!
First don't create new object of MainActivity in MyAsyncTask. Actually what's happening is AsyncTask runs on a new Thread so when you do
myAsyncTask.execute("43017,us");
recyclerView.getAdapter().notifyDataSetChanged();
adapter.refreshContents(weatherData);
then myAsyncTask runs in a different thread and the next lines start executing right before .execute without waiting for asynctask to finish and even if it waits for the asynctask to finish, creating a new object to update the data in MainActivity is not gonna work. So what you can do to update your list from onPostExecute method is pass your Activity to myAsyncTask from parameters. Don't initialize your myAsyncTask in the beginning, just remove the = new MyAsyncTask() from private MyAsyncTask myAsyncTask = new MyAsyncTask(); in MainActivity and now replace the lines in MainActivity with this:
Instead of this in your MainActivity
myAsyncTask.execute("43017,us");
recyclerView.getAdapter().notifyDataSetChanged();
adapter.refreshContents(weatherData);
for (int i = 0; i<weatherData.length; i++) {
Log.v("Refresh button", weatherData[i].toString());
}
Write this
myAsyncTask = new MyAsyncTask(this);
myAsyncTask.execute("43017,us");
and to refresh the contents you can make your adapter public so that you could call notifydatasetchanged from myAsyncTask itself but if you want to follow your code written after .execute then you can move it to a new method something like below
public void refreshList(){
recyclerView.getAdapter().notifyDataSetChanged();
adapter.refreshContents(weatherData);
for (int i = 0; i<weatherData.length; i++) {
Log.v("Refresh button", weatherData[i].toString());
}
}
and now what's left is getting context of your MainActivity in MyAsyncTask and refreshing your list in onPostExecute. So make changes like following:
Create a constructor of your MyAsyncTask
public class MyAsyncTask extends AsyncTask<String,Void,String[]> {
MainActivity mainActivity;
public MyAsyncTask(MainActivity mainActivity){
this.mainActivity = mainActivity;
}
Replace this in MyAsyncTask
mainActivity = new MainActivity();
mainActivity.setWeatherData(data);
With this
mainActivity.setWeatherData(data);
mainActivity.refreshList();
I din't tested it myself but i think this should solve your problem. You can try debugging this and see how it is working. And if you face any problems please comment down below.
Edit
Based on the comment by #Ganesh Patil you can create an interface for this solution as well. For the reference of using interface in AsyncTask you can follow this link:
https://stackoverflow.com/a/28958913/7071039
But to keep it simple i didn't used interface and just passed the context of MainActivity in the MyAsyncTask
Editing based on the comment
Dear PC HUB, firstly thank you so much for your very detailed answer.
All of your explanations made sense and I applied the codes. My app
now doesn't crash and all the data is properly passed / retrieved but
somehow mainActivity.refreshList() and
recyclerView.getAdapter().notifyDataSetChanged() is still not working.
Hence, my recyclerView still doesn't change the contents at all... I
am not sure of what to do. – Rikuto Echigoya
change your refreshList into this
public void refreshList(){
/* Check your Weather Data size in this method to find out weather your data is changing or not */
Log.d("Tag","SIZE OF WEATHER DATA : "+weatherData.length);
/* You already have the adapter object so you don't need to
get it using recyclerview.getAdapter. Just do it directly like this */
adapter.notifyDataSetChanged();
// Not changing this as this will not stop your list from refreshing :P
for (int i = 0; i<weatherData.length; i++) {
Log.v("Refresh button", weatherData[i].toString());
}
}
Also make sure that you've called mainActivity.setWeatherData(data); before mainActivity.refreshList(); in your MyAsyncTask.
If it still doesn't solve your problem then share your updated code so that we could see why your list is not getting updated :)

Cannot update dynamic buttons from a Json populated Array

****Working code posted****
I am trying to update buttons where the text will be dynamically programmed from an ArrayList. The data is being retrieved from mySQL. I can get the data in and fill the array with what I need (familyMemberArray). However for some reason when the information is gathered, the program does not go on to implementing the "trending" array or the rest of the layout programming, after the array information has been produced.
I need to formulate the data first so I know how big the array is to create the amount of buttons necessary. If I call in a basic String array it populates the buttons just fine. I remember being stuck on this problem on a uni project and ended up giving up because I just could not get it to work and time was ticking. Please put me out of my misery
public class TrendingMealsFragment extends Fragment {
private TableRow tr;
//SQLite Database
private static final String SELECT_SQL = "SELECT * FROM family_account";
private SQLiteDatabase db;
private Cursor c;
private static final String DATABASE_NAME = "FamVsFam.db";
// Logging
private final String TAG = this.getClass().getName();
private static final String EXTRA_CHALLENGE_ID = "boo.famvsfam.challenge_id";
//Results
private JSONArray resultFamilyMember;
private String dbID;
public static final String JSON_ARRAY = "result";
private List<String> familyMemberArray;
ArrayAdapter<String> adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
openDatabase();
setHasOptionsMenu(true);
c = db.rawQuery(SELECT_SQL, null);
c.moveToFirst();
getRecords();
}
protected void openDatabase() {
db = getActivity().openOrCreateDatabase(DATABASE_NAME, android.content.Context.MODE_PRIVATE, null); // db = SQLiteDatabase.openOrCreateDatabase("FamVsFam", Context.MODE_PRIVATE, null);
}
protected void getRecords() {
dbID = c.getString(0);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getData();
/** Declaring an ArrayAdapter to set items to ListView */
familyMemberArray = new ArrayList<>();
//Menu
setHasOptionsMenu(true);
ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
View view = inflater.inflate(R.layout.activity_resturants, container, false);
AppCompatActivity activity = (AppCompatActivity) getActivity();
activity.getSupportActionBar();
/**
ArrayList<String> trending1 = new ArrayList<String>() {
{
add("one");
add("two");
add("three");
add("four");
add("five");
add("six");
add("seven");
add("eight");
add("nine");
add("ten");
add("eleven");
}
};*/
ArrayList<String> trending = new ArrayList<String>() {
{
for(int i = 0; i < familyMemberArray.size() ; i++){
add(familyMemberArray.get(i));
}}
};
// LAYOUT SETTING 1
RelativeLayout root = new RelativeLayout(getActivity());
// root.setId(Integer.parseInt(MEAL_SELECTION_ID));
LayoutParams param1 = new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
root.setFitsSystemWindows(true);
}
root.setLayoutParams(param1);
//LAYOUT SETTINGS 2 - TOP BANNER - WITH PAGE HEADING
RelativeLayout rLayout1 = new RelativeLayout(getActivity());
LayoutParams param2 = new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
float topBannerDim = getResources().getDimension(R.dimen.top_banner);
param2.height = (int) topBannerDim;
param2.addRule(RelativeLayout.BELOW, root.getId());
int ele = (int) getResources().getDimension(R.dimen.elevation);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
rLayout1.setElevation(ele);
}
rLayout1.setBackgroundColor(Color.parseColor("#EEEBAA"));
rLayout1.setLayoutParams(param2);
//TEXT VIEW
TextView text1 = new TextView(getActivity());
text1.setText(R.string.diet_req);
LayoutParams param3 = new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
param3.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
text1.setTextColor(Color.parseColor("#8A1F1D"));
text1.setTypeface(Typeface.DEFAULT_BOLD);
text1.setLayoutParams(param3);
//LAYOUT SETTINGS 4
RelativeLayout rLayout4 = new RelativeLayout(getActivity());
LayoutParams param5 = new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
topBannerDim = getResources().getDimension(R.dimen.top_banner);
param5.height = (int) topBannerDim;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
param5.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.ALIGN_START);
}
param5.addRule(RelativeLayout.BELOW, rLayout1.getId());
rLayout4.setId(R.id.id_relative_4);
rLayout4.setBackgroundColor(Color.parseColor("#EEEBAA"));
rLayout4.setLayoutParams(param5);
//LAYOUT SETTINGS 5
TableLayout rLayout5 = new TableLayout(getActivity());
rLayout5.setOrientation(TableLayout.VERTICAL);
LayoutParams param7 = new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
param7.addRule(RelativeLayout.BELOW, rLayout4.getId());
rLayout5.setBackgroundColor(Color.parseColor("#EEEBAA"));
rLayout5.setLayoutParams(param7);
// List<ToggleButton> togButtStore = new ArrayList<ToggleButton>();
int i = 0;
while (i < trending.size()) {
if (i % 3 == 0) {
tr = new TableRow(getActivity());
rLayout5.addView(tr);
}
ToggleButton toggleBtn = new ToggleButton(getActivity());
toggleBtn.setText(trending.get(i));
toggleBtn.setId(i);
toggleBtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
Context context = getActivity().getApplicationContext();
CharSequence text = "Hello toast!";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
} else {
// The toggle is disabled
}
}
});
tr.addView(toggleBtn);
i++;
}
//LAYOUT SETTINGS 6
FrameLayout youBeenFramed = new FrameLayout(getActivity());
LayoutParams param8 = new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
param8.addRule(RelativeLayout.BELOW, rLayout5.getId());
youBeenFramed.setBackgroundColor(Color.parseColor("#EEEBAA"));
root.addView(youBeenFramed);
root.addView(rLayout1);
rLayout1.addView(text1);
root.addView(rLayout4);
root.addView(rLayout5);
getActivity().setContentView(root);
return view;
}
public void getData() {
//// TODO: 03/08/2016 Progress Dialogs : on getting data
// final ProgressDialog loading = ProgressDialog.show(getActivity(), "Loading Data", "Please wait...", false, false);
StringRequest strReq = new StringRequest(Request.Method.POST,
PHPConfigURLS.URL_ALL_FAMILY_MEMBERS, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d(TAG, "Login Response: " + response.toString());
JSONObject j = null;
try {
// loading.dismiss();
//Parsing the fetched Json String to JSON Object
j = new JSONObject(response);
//Storing the Array of JSON String to our JSON Array
resultFamilyMember = j.getJSONArray(JSON_ARRAY);
//Calling method getStudents to get the students from the JSON Array
getDBFamilyName(resultFamilyMember);
} catch (JSONException e) {
// JSON error
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}) {
#Override
protected Map<String, String> getParams() {
String id = dbID;
// Posting params to register url
Map<String, String> params = new HashMap<String, String>();
params.put("id", id);
// params.put("email", email);
// params.put("password", password);
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(getActivity());
//Adding request to the queue
requestQueue.add(strReq);
}
private void getDBFamilyName(JSONArray j) {
//Traversing through all the items in the json array
for (int i = 0; i < j.length(); i++) {
FamilyAccount familyMember = new FamilyAccount();
try {
//Getting json object
JSONObject json = j.getJSONObject(i);
familyMember = new FamilyAccount();
familyMember.setName(json.getString("name"));
familyMember.setID(json.getInt("id"));
} catch (JSONException e) {
e.printStackTrace();
}
//Adding the title of the challenge to array list
familyMemberArray.add(familyMember.getName());
}
}
}
Thanks in advance
for some reason when the information is gathered, the program does not go on to implementing the "trending" array or the rest of the layout programming, after the array information has been produced.
That's because the layout doesn't "dynamically" update when you call this when the request finishes.
familyMemberArray.add(familyMember.getName());
You'll have to clear the view, and redo all the view adding again, or "extract" all the view generation code into it's own method that you can call with the parameter of your ArrayList.
Basically, everything between // LAYOUT SETTING 1 and return view (non-inclusive) needs to be moved into a public void generateView(ArrayList<String> familyMemberArray) method that can optionally return the root View that was generated, if necessary.
Then, at the end of getFamilyName(), outside the loop, call that method with your ArrayList.
I need to formulate the data first so I know how big the array is to create the amount of buttons necessary.
I'm not sure I see where you are doing that. Unless you mean here
while (i < trending.size()) {
Which, instead, trending is an entirely different list reference than familyMemberArray, so it won't update either. Though, it contains the exact same data?
ArrayList<String> trending = new ArrayList<String>() {
{
for(int i = 0; i < familyMemberArray.size() ; i++){
add(familyMemberArray.get(i));
}}
};
That block of code looks a bit odd, considering the ArrayList constructor already provides that functionality
ArrayList<String> trending = new ArrayList<String>(familyMemberArray);
*****WORKING CODE****** Credit to cricket_007
FIELDS
public class TrendingMealsFragment extends Fragment {
// Logging
private final String TAG = this.getClass().getName();
//Results
private JSONArray resultFamilyMember;
public static final String JSON_ARRAY = "result";
private ArrayList<String> familyMemberArray;
//Layout
private TableRow tr;
OnCreateView()
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_resturants, container, false);
generateView(familyMemberArray);
getData();
return view;
}
GetData()
public void getData() {
StringRequest strReq = new StringRequest(Request.Method.POST,
PHPConfigURLS.URL_ALL_FAMILY_MEMBERS, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d(TAG, "Login Response: " + response.toString());
JSONObject j = null;
try {
//Parsing the fetched Json String to JSON Object
j = new JSONObject(response);
//Storing the Array of JSON String to our JSON Array
resultFamilyMember = j.getJSONArray(JSON_ARRAY);
//Calling method getStudents to get the students from the JSON Array
getDBFamilyName(resultFamilyMember);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}) {
#Override
protected Map<String, String> getParams() {
String id = dbID;
Map<String, String> params = new HashMap<String, String>();
params.put("id", id);
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(getActivity());
//Adding request to the queue
requestQueue.add(strReq);
}
getDBFamilyName()
private void getDBFamilyName(JSONArray j) {
//Traversing through all the items in the json array
for (int i = 0; i < j.length(); i++) {
FamilyAccount familyMember = new FamilyAccount();
try {
//Getting json object
JSONObject json = j.getJSONObject(i);
familyMember = new FamilyAccount();
familyMember.setName(json.getString("name"));
familyMember.setID(json.getInt("id"));
} catch (JSONException e) {
e.printStackTrace();
}
//Adding the title of the challenge to array list
familyMemberArray.add(familyMember.getName());
generateView(familyMemberArray);
}
}
generateView()
public View generateView(ArrayList<String> familyMemberArray) {
...
rLayout5.setLayoutParams(param7);
//Create Buttons
int i = 0;
while (i < familyMemberArray.size()) {
if (i % 3 == 0) {
tr = new TableRow(getActivity());
rLayout5.addView(tr);
}
ToggleButton toggleBtn = new ToggleButton(getActivity());
toggleBtn.setText(familyMemberArray.get(i));
toggleBtn.setId(i);
toggleBtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
Context context = getActivity().getApplicationContext();
CharSequence text = "Hello toast!";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
} else {
// The toggle is disabled
}
}
});
tr.addView(toggleBtn);
i++;
}
...
root.addView(rLayout5);
getActivity().setContentView(root);
return root;
}
}

Data is not populating in list, Android

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.

ASyncTask and returning an ArrayList

Im trying to return an ArrayList from the AsyncTask class back to the MainAcitivity class and then use this arraylist to fill the gridview in MainActivity.
The parseURL takes a String paramater to parse the url. And parseURL is executed when the user clicks the button. The code i have compiles and run but the gridview is not populated after triggering the button event and pressing the button twice crashes the app.
EDIT: After adding loop callback, it stops crashing but it still wont populate the gridview. The ArrayList object that i want to populate the gridview is in this format 10,John,Smith
Here is my code for MainActivity (using Stanislav Bodnar suggestion)
private GridView grid1;
private ArrayAdapter<String> adapter;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//initalized the grid and adapter
grid1 = (GridView)findViewById(R.id.gridView1);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
grid1.setAdapter(adapter);
}
public void onButtonClick(View v) {
EditText textInput = (EditText) findViewById(R.id.editText1);
String code = textInput.getText().toString();
new parseURL() {
#Override
protected void onPostExecute(List<String> list) {
//use the list from parseURL to fill grid view
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
gridView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}.execute(code);
ParseURL class
public class parseURL extends AsyncTask<String, Void, List<String>> {
protected List<String> doInBackground(String... params) {
List<String> str = new ArrayList<String>();
try {
Document doc = Jsoup.connect("http://www.mywebsite.com/id/" + params).get();
Elements row1 = doc.select("table");
Elements row2 = doc.select("td");
Elements row3 = doc.select("td");
for (int i = 0; i < row1.size(); i++) {
str.add(row1.get(i).text() + "," + row2.get(i).text() + "," + row2.get(i).text());
}
return str;
} catch (Exception e) {
return new ArrayList<String>();
}
}
You can add loading callback.
public void onButtonClick(View v) {
EditText textInput = (EditText) findViewById(R.id.editText1);
String code = textInput.getText().toString();
new parseURL() {
#Override
protected void onPostExecute(List<String> list) {
//use the list from parseURL to fill grid view
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
gridView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}.execute(code);
}
Asynctask:
public class parseURL extends AsyncTask<String, Void, List<String>> {
protected List<String> doInBackground(String... params) {
List<String> str = new ArrayList<String>();
try {
Document doc = Jsoup.connect("http://www.mywebsite.com/id/" + params).get();
Elements row1 = doc.select("table");
Elements row2 = doc.select("td");
Elements row3 = doc.select("td");
for (int i = 0; i < row1.size(); i++) {
str.add(row1.get(i).text() + "," + row2.get(i).text() + "," + row2.get(i).text());
}
return str;
} catch (Exception e) {
return new ArrayList<String>();
}
}
}
Supplement
If array list that returns by onPostExecute is not empty your grid will be populated in the next way each cell will have string 10,John,Smith. Please check that method doInBackground does not catch some exception and fills array list correctly.
Next if you want to do a table view where 1 row will contain 3 columns 10 | John | Smith then parse data into object structure:
class Person {
private int id;
private String firstName;
private String lastName;
}
Then change method doInBackground to return array list of Person objects.
Create custom adapter (extend BaseAdapter) where init view using Person object.
View will be as LinearLayout with horizontal orientation which will contain 3 TextView with Layout Weight (android:layout_weight="0.3" - set in each TextView, you can change this value). Then use ListView instead of GridView. Each row of list view will contain 1 Person.
The AsyncTask is by definition asynchronous. Your code handles it like it was synchronous.
Move
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
gridView.setAdapter(adapter);
adapter.notifyDataSetChanged();
into the setList method.
Also, passing around the MainActivity feels a bit shaky. What happens if the Activity is destroyed during the async-task?
Instead, make the AsyncTask a private inner class or an anonymous class in MainActivity
And of course you will need to initialize your list before you populate it.
Don't do gridview.setAdapter() twice. There are a few problems with that code. As P-a Bäckström wrote:
Also, passing around the MainActivity feels a bit shaky. What happens if the Activity is destroyed during the async-task? Instead, make the AsyncTask a private inner class or an anonymous class in MainActivity
You need to fix that too. Now comes the updating part:
Declare a global Handler like this:
private final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if(msg.what == 1) {
List<String> list = (List) msg.obj;
adapter.insert(list);
adapter.notifyDataSetChanged();
}
}
};
Then in onPostExecute() send your data to the UI thread using the handler and update the gridview:
protected void onPostExecute(List<String> list) {
handler.obtainMessage(1, list);
}
try this:
Mainactivity.class
private GridView grid1;
private ArrayAdapter<String> adapter;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//initalized the grid and adapter
grid1 = (GridView)findViewById(R.id.gridView1);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
grid1.setAdapter(adapter);
}
public void onButtonClick(View v) {
EditText textInput = (EditText) findViewById(R.id.editText1);
String code = textInput.getText().toString();
new parseURL(this).execute(code);
}
public void onBackgroundTaskCompleted(List<String> result) {
// TODO Auto-generated method stub
Log.i(TAG, "onBackgroundTaskCompleted List: "+result);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
gridView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
Asynctask:
public class parseURL extends AsyncTask<String, Void, List<String>> {
MainActivity caller;
public Scheduler(MainActivity mainActivity) {
// TODO Auto-generated constructor stub
this.caller = mainActivity;
}
protected void onPostExecute(List<String> result) {
caller.onBackgroundTaskCompleted(result);
}
protected List<String> doInBackground(String... params) {
List<String> str = new ArrayList<String>();
try {
Document doc = Jsoup.connect("http://www.mywebsite.com/id/" + params).get();
Elements row1 = doc.select("table");
Elements row2 = doc.select("td");
Elements row3 = doc.select("td");
for (int i = 0; i < row1.size(); i++) {
str.add(row1.get(i).text() + "," + row2.get(i).text() + "," + row2.get(i).text());
}
return str;
} catch (Exception e) {
return new ArrayList<String>();
}
}
}

Categories