0

I'm coding my first app and can't make the Listview update properly from Async class. I can fill the custom adapter with info when it's initially created but when I try to update the content it the listview only goes blank. If I rotate the phone, the new content apears for a second but then disappears again.

Main activity:

public class SearchBooksActivity extends AppCompatActivity
    implements NavigationView.OnNavigationItemSelectedListener, OnItemSelectedListener {

ListView listView;
TextView pageNumbers;
private Spinner dropdown;
private String[] items = new String[]{"- Select the genre -", "Adventure", "Children", "Comedy",
        "Fairy tales", "Fantasy", "Fiction", "Historical Fiction", "History", "Humor",
        "Literature", "Mystery", "Non-fiction", "Philosophy", "Poetry", "Romance", "Religion",
        "Science fiction", "Short stories", "Teen/Young adult"};

//ArrayLists used to store links to book names, their thumbnails to be passed
//into CustomAdapterListView
private List<BookListView> books = new ArrayList<>();
public ArrayList<String> pageNumber= new ArrayList<String>();

CustomAdapterListView mAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_search_books);

    dropdown = (Spinner) findViewById(R.id.spinner1);
    ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
            android.R.layout.simple_spinner_dropdown_item, items);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    dropdown.setAdapter(adapter);
    dropdown.setOnItemSelectedListener(this);

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
            this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.addDrawerListener(toggle);
    toggle.syncState();

    NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
    navigationView.setNavigationItemSelectedListener(this);

    listView = (ListView) findViewById(R.id.listView);
    pageNumbers = (TextView) findViewById(R.id.pageView);

}

public void RunAsyncPageParser(String url) {
    Toast.makeText(this, "Loading...Wait...", Toast.LENGTH_SHORT).show();
    FillListViev2 fillListViev = new FillListViev2(url);
    fillListViev.execute();

}
public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {

    switch (position) {
        case 0:
            RunAsyncPageParser("http://www.loyalbooks.com/Top_100");
            break;
        case 1:
            RunAsyncPageParser("http://www.loyalbooks.com/genre/Adventure");
            break;
        case 2:
            RunAsyncPageParser("http://www.loyalbooks.com/genre/Children");
            break;
        case 3:
            RunAsyncPageParser("http://www.loyalbooks.com/genre/Comedy");
            break;
        ...
}

public void onNothingSelected(AdapterView<?> parent) {

}

@Override
public void onBackPressed() {
    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    if (drawer.isDrawerOpen(GravityCompat.START)) {
        drawer.closeDrawer(GravityCompat.START);
    } else {
        super.onBackPressed();
    }
}


@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
    // Handle navigation view item clicks here.
    int id = item.getItemId();

    if (id == R.id.browse_books) {
        Toast.makeText(this, "TEST", Toast.LENGTH_SHORT).show();
    } else if (id == R.id.offline_books) {

    } else if (id == R.id.settings) {

    }

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    drawer.closeDrawer(GravityCompat.START);
    return true;
}

@Override
protected void onDestroy() {
    super.onDestroy();

}

public class FillListViev2 extends AsyncTask<Void, Void, List<BookListView>> {

    //site url to be passed into consructor
    private String site;


    public FillListViev2(String title) {

        this.site = title;
    }

    @Override
    protected List<BookListView> doInBackground(Void... params) {

        //parsed doc will be stored in this field
        Document doc = null;

        //fields to store raw html lines used to extract book names, their thumbnails
        // as well as number of total pages of the books category
        Elements mLines;
        Elements mLines2;

        try {
            //connect to the site
            doc = Jsoup.connect(site).get();

        } catch (IOException | RuntimeException e) {
            e.printStackTrace();
        }
        if (doc != null) {

            // getting all elements with classname "layout"
            mLines = doc.getElementsByClass("layout");

            //searching for book names and their thumbnails and adding them to ArrayLists
            for (Element mLine : mLines) {
                String mPic = mLine.attr("src");
                String mName = mLine.attr("alt");
                books.add(new BookListView(mName,"http://www.loyalbooks.com" + mPic));


            }
            // getting all elements with tag "ul"
            mLines2 = doc.getElementsByTag("ul");

            //searching for total number of pages in category and adding it to ArrayList
            for (Element mLine2 : mLines2) {
                String mPages = mLine2.text();
                pageNumber.add(mPages);
            }
        }else
            System.out.println("ERROR");

        return books;
    }

    protected void onPostExecute(List<BookListView> books) {

        super.onPostExecute(books);


        if (books.size() > 0) {
            try {

                if (listView.getAdapter() != null){

                    mAdapter.clear();
                    mAdapter.addAll(books);
                    Toast.makeText(SearchBooksActivity.this, "TEST", Toast.LENGTH_SHORT).show();
                } else {
                    mAdapter = new CustomAdapterListView(SearchBooksActivity.this,
                            R.layout.search_books_listview_item, books);
                    listView.setAdapter(mAdapter);
                }
                pageNumbers.setText(pageNumber.get(0).substring(10, pageNumber.get(0).length() -2));
            } catch(RuntimeException e) {
                e.printStackTrace();
            }
        } else Toast.makeText(SearchBooksActivity.this, "NETWORK ERROR", Toast.LENGTH_LONG).show();

    }
}

Pojo class:

public class BookListView {
private String title;
private String imageUrl;

public BookListView(String title, String imageUrl) {
    this.title = title;
    this.imageUrl = imageUrl;
}

public String getTitle() {
    return title;
}

public void setTitle(String title) {
    this.title = title;
}

public String getImageUrl() {
    return imageUrl;
}

public void setImageUrl(String imageUrl) {
    this.imageUrl = imageUrl;
}

Adapter class:

public class CustomAdapterListView extends ArrayAdapter<BookListView> {
private Context mContext;
private List<BookListView> books;
private int resource;

public CustomAdapterListView(Context context, int resource, List<BookListView> objects) {
    super(context, resource, objects);
    this.mContext = context;
    this.resource = resource;
    this.books = objects;

}

public int getCount() {

    return books.size();
}

public BookListView getItem(int arg0) {
    return books.get(arg0);
}

public long getItemId(int position) {
    return position;
}

public View getView(int position, View convertView, ViewGroup parent) {

    ViewHolder holder;

    if (convertView == null) {
        convertView = LayoutInflater.from(mContext).inflate(resource, parent, false);
        holder = new ViewHolder();
        holder.title = convertView.findViewById(R.id.title);
        holder.i1 = convertView.findViewById(R.id.imageViewLstRow);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    BookListView item = getItem(position);

    Picasso.get().load(item.getImageUrl()).resize(80, 80).centerCrop().into(holder.i1);
    holder.title.setText(item.getTitle());

    return convertView;
}

class ViewHolder {
    public TextView title;
    public ImageView i1;
}

I don't think that the problem is in adapter itself, since it kinda works and this line in the onPostExecute method does not update the Textview untill I rotate the device.

pageNumbers.setText(pageNumber.get(0).substring(10, pageNumber.get(0).length() -2));

3 Answers3

0

Try this code to change..

          else {
                if (adapter!=null){
                mAdapter = new CustomAdapterListView(SearchBooksActivity.this,
                        titleList, imgList);

                 listView.setAdapter(mAdapter);
                }else{
                    adapter.notifyDataSetChanged();
                   }

            }
  • 2
    C'mon, Android Team. By now, you should at least be able to format your code correctly. An explanation would be nice, too. – Mike M. Nov 29 '18 at 10:35
0

Are you sure that mAdapter is indeed the adapter that is attached to your listView ? maybe you could check that :

 if (listView.getAdapter() != null && listView.getAdapter() == mAdapter){
ezzou
  • 2,348
  • 1
  • 15
  • 16
  • Tnx, tried that, but result is the same. As you see I made this "TEST" Toast message in the "if" block. When I choose the item in the spinner, the message appears, so the condition is followed, but the listview is again only updating when I flip the screen. – Alex Medentsov Nov 29 '18 at 10:47
  • Did you try to call invalidateViews on the listview after calling the notifySetDataChanged ? – ezzou Nov 29 '18 at 11:11
0

first create a pojo class like this,

public class Book {
private String title;
private String imageUrl;

public Book(String title, String imageUrl) {
    this.title = title;
    this.imageUrl = imageUrl;
}

public String getTitle() {
    return title;
}

public void setTitle(String title) {
    this.title = title;
}

public String getImageUrl() {
    return imageUrl;
}

public void setImageUrl(String imageUrl) {
    this.imageUrl = imageUrl;
}
}

then remove these from your activity

public ArrayList<String> titleList = new ArrayList<String>();
public ArrayList<String> imgList = new ArrayList<String>();

change you asynctask to,

public class FillListViev2 extends AsyncTask<Void, Void, List<Book>> {
    //site url to be passed into consructor
    private String site;
    private List<Book> books = new ArrayList<>();
    private ArrayList<String> pageNumber = new ArrayList<>();


    public FillListViev2(String title) {
        this.site = title;
    }

    @Override
    protected List<Book> doInBackground(Void... params) {
        //parsed doc will be stored in this field
        Document doc = null;

        //fields to store raw html lines used to extract book names, their thumbnails
        // as well as number of total pages of the books category
        Elements mLines;
        Elements mLines2;

        try {
            //connect to the site
            doc = Jsoup.connect(site).get();

        } catch (IOException | RuntimeException e) {
            e.printStackTrace();
        }
        if (doc != null) {

            // getting all elements with classname "layout"
            mLines = doc.getElementsByClass("layout");

            //searching for book names and their thumbnails and adding them to ArrayLists
            for (Element mLine : mLines) {
                String mPic = mLine.attr("src");
                String mName = mLine.attr("alt");
                books.add(new Book(mName, mPic));
            }
            // getting all elements with tag "ul"
            mLines2 = doc.getElementsByTag("ul");

            //searching for total number of pages in category and adding it to ArrayList
            for (Element mLine2 : mLines2) {
                String mPages = mLine2.text();
                pageNumber.add(mPages);
            }
        } else
            System.out.println("ERROR");

        return books;
    }

    @Override
    protected void onPostExecute(List<Book> books) {
        super.onPostExecute(books);
        if (books.size() > 0) {
            try {
                if (listView.getAdapter() != null) {
                    mAdapter.clear();
                    mAdapter.addAll(books);
                    Toast.makeText(SearchBooksActivity.this, "TEST", Toast.LENGTH_SHORT).show();
                } else {
                    mAdapter = new CustomAdapterListView(SearchBooksActivity.this, R.layout.search_books_listview_item, books);
                    listView.setAdapter(mAdapter);
                }
                pageNumbers.setText(pageNumber.get(0).substring(10, pageNumber.get(0).length() - 2));
            } catch (RuntimeException e) {
                e.printStackTrace();
            }
        } else
            Toast.makeText(SearchBooksActivity.this, "NETWORK ERROR", Toast.LENGTH_LONG).show();
    }
}

and your adapter to,

 public class CustomAdapterListView extends ArrayAdapter<Book> {
    private Context mContext;
    private List<Book> books;
    private int resource;

    public CustomAdapterListView(Context context, int resource, List<Book> objects) {
        super(context, resource, objects);
        this.mContext = context;
        this.resource = resource;
        this.books = objects;
    }

    public int getCount() {
        return books.size();
    }

    public Book getItem(int arg0) {
        return books.get(arg0);
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(resource, parent, false);
            holder = new ViewHolder();
            holder.title = (TextView) convertView.findViewById(R.id.title);
            holder.i1 = (ImageView) convertView.findViewById(R.id.imageViewLstRow);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        Book item = getItem(position);

        Picasso.get().load(item.getImageUrl()).resize(80, 80).centerCrop().into(holder.i1);
        holder.title.setText(item.getTitle());

        return convertView;
    }

    class ViewHolder {
        private TextView title;
        private ImageView i1;
    }
}
shinilms
  • 1,494
  • 3
  • 22
  • 35
  • Tnx, I'll give it a try. – Alex Medentsov Nov 29 '18 at 11:37
  • I tried your code, it seems to work. Well, sort of... But now things got even more wierd. Refreshing works every other time! I mean the activity starts, and Listview is populated with default content, then I choose an item in the spinner and Listview goes blank, but when I choose an item once again it refreshes! Black magic... – Alex Medentsov Nov 29 '18 at 13:40
  • I've made a small change in `onPostExecute` method. Try that – shinilms Nov 29 '18 at 14:36
  • No, no use. I think, that the problem is not in adapter itself. This line pageNumbers.setText(pageNumber.get(0).substring(10, pageNumber.get(0).length() - 2)); which is just setting the value of the seperate textview does not update either. The mistake is somewere in setting the views... but I can't find it - I have to little experience. – Alex Medentsov Nov 29 '18 at 14:46
  • I'll try it a bit later, I need a break. – Alex Medentsov Nov 29 '18 at 16:05
  • Bingo! It's working :) Thank you so much for your time! – Alex Medentsov Nov 29 '18 at 18:49