I'm building an app for my school. I use Android Studio's default Navigation Drawer Fragment and Main Activity for it, and I populate it with fragments according to what the user selects in the drawer.
The problem is that one of my fragments fetches data from the internet, and sets up a List View with it. The List View does not get updated though, and the fragment stays blank. I think it is a matter of updating the UI and I'm not doing it right.
There's the fragment code:
public class NewsFragment extends Fragment {
// ASYNC TASK VARIABLES
NewsAsyncTask crackerTask = new NewsAsyncTask();
String NEWSURL = "http://---.--/H--e.aspx";
String ALERTSURL = "http://---.--/H--e.aspx";
String EVENTSURL = "http://---.--/H--e.aspx";
String string1 = "";
String FINALSTRING = "";
public List<NewsItem> myNews = new ArrayList<NewsItem>();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Inflate the layout for this fragment
return inflater.inflate(R.layout.news_fragment, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
// INSTANTIATING AND INFLATING THE TABBED LAYOUT
super.onCreate(savedInstanceState);
View container = (View) getActivity().findViewById(R.id.news_layout_container) ;
// ASYNC TASK METHOD EXECUTION UNDER IF STATEMENT
if (this.isNetworkAvailable()) {
crackerTask.execute(NEWSURL);
populateListView();
registerClickOnListItem();
// getView().invalidate();
}
else{
Toast.makeText(getActivity(), "No internet connection.",
Toast.LENGTH_SHORT).show();
}
}
// CUSTOM METHODS ////////////////////////////////////////////////////
private void actionButtonRefreshPressed() {
if (this.isNetworkAvailable()) {
new NewsAsyncTask().execute(NEWSURL); // calling NEW asynctask
populateListView();
registerClickOnListItem();
// because an asynctask
// can be executed only
// once.
}
}
private void populateNewsList(String title, String summary, String date,
String link) {
myNews.add(new NewsItem(title, summary, date, link));
}
private void populateListView() {
ArrayAdapter<NewsItem> adapter = new MyListAdapter();
ListView newslist = (ListView) getView().findViewById(R.id.newsListView);
newslist.setAdapter(adapter);
}
private void registerClickOnListItem() {
ListView list = (ListView) getView().findViewById(R.id.newsListView);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View viewClicked,
int position, long id) {
// shows toast with info
NewsItem clickedNewsItem = myNews.get(position);
String message = "You clicked position " + position
+ " Which is " + clickedNewsItem.title;
Toast.makeText(getActivity(), message,
Toast.LENGTH_SHORT).show(); // .show is important!
// otherwise it won't show.
}
});
}
private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager
.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
// CUSTOM MINI CLASSES /////////////////////////////////////////////////
private class NewsAsyncTask extends AsyncTask<String, String, String> {
// Genetics of an AsyncTask:
// 1. Type of reference(s) passed to doInBackground()
// 2. Type of reference passed to onProgressUpdate()
// 3. Type of reference returned by doInBackground(). Value passed to
// onPostExecute()
ProgressDialog dialog1;
@Override
protected void onPreExecute() {
super.onPreExecute();
dialog1 = ProgressDialog.show(getActivity(), "Loading",
"Fetching data from web...");
}
@Override
protected String doInBackground(String... arguments) {
// extract arguments
String newsurl = arguments[0];
//
Document root = null;
try {
root = Jsoup.connect(newsurl).get();
} catch (IOException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
if (root != null) {
Elements myElements = root.getElementsByClass("news_list")
.first().getElementsByTag("table");
for (Element el : myElements) {
Element title = el.getElementsByClass("home_title").first();
Element date = el.getElementsByClass("home_date").first();
Element link = el.getElementsByClass("news_list_image")
.first();
Element summary = el.getElementsByClass("summary").first();
populateNewsList(title.text(), summary.text(), date.text(),
link.child(0).attr("href"));
}
Log.i("ELEMENTS HTML", string1);
} else {
string1 = "FAILED TO LOAD";
}
return string1;
}
@Override
protected void onPostExecute(String string1) {
// super.onPostExecute(result);
if (string1.equals("FAILED TO LOAD")) {
// tv2.setText("Failed to load. Check your internet connection.");
if (dialog1 != null) {
if (dialog1.isShowing()) {
dialog1.dismiss();
}
}
Toast.makeText(getActivity(),
"No web connectivity. Try again later.",
Toast.LENGTH_LONG).show();
}else{
//presumably the download worked so update adapter
ListView newslist = (ListView) getView().findViewById(R.id.newsListView);
((ArrayAdapter)newsList.getAdapter()).notifyDataSetChanged();
}
FINALSTRING = string1;
// tv2.setText(FINALSTRING);
if (dialog1 != null) {
if (dialog1.isShowing()) {
dialog1.dismiss();
}
}
}
}
private class MyListAdapter extends ArrayAdapter<NewsItem> {
public MyListAdapter() {
super(getActivity(), R.layout.news_item, myNews);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// make sure we have a view to work with in the lines below, may be
// given null
View newsItem = convertView;
if (newsItem == null) {
newsItem = getActivity().getLayoutInflater().inflate(R.layout.news_item,
parent, false);
}
// find the NewsItem we have to work with.
NewsItem currentNews = myNews.get(position);
// fill the view.
ImageView imageView = (ImageView) newsItem
.findViewById(R.id.newsitem_icon);
imageView.setImageResource(R.drawable.test_icon); // THIS IS GOING
// TO BE CHANGED
// SO IT DOESN'T
// USE THE
// DRAWABLE
// Summary
TextView summaryText = (TextView) newsItem
.findViewById(R.id.newsitem_summary);
summaryText.setText(currentNews.getSummary());
// Date
TextView dateText = (TextView) newsItem
.findViewById(R.id.newsitem_date);
dateText.setText(currentNews.getDate());
// Title
TextView titleText = (TextView) newsItem
.findViewById(R.id.newsitem_title);
titleText.setText(currentNews.getTitle());
return newsItem;
}
}
}
There are some stuff left from when I was debugging the code, sorry (it was originally in an activity and it worked, the problem occurred when I transferred everything in a fragment).
EDIT: Since I tried so many variants, I suppose the error is that the list view I'm trying to show is empty. I tried putting Log.i("TAG", myNews.get(0).title);
in the place of the invalidate();
and it returns an index out of bounds exception. I cannot find the source of the mistake though.
You should be probably be calling notifyDataSetChanged on your adapter (not the listview). Call this in your AsyncTask in post execute.