简体   繁体   中英

How can I populate a ListView on a SecondActivity with data from FirstActivity in Android?

I'm working on a book-searching app project. The user enters a title, and the app searches Google Books for it.
I initially had one activity and layout. I decided to use two layouts (one for user to enter title, and the other displays results); had to create another activity because the results layout was throwing an exception about 'null' object reference .
After creating the second activity, I used an intent to transfer List data between the two activities; no sooner did I find out that I had to use a Serialize or Parcelable object for the purpose.
Following instructions at Pass list of objects from one activity to other activity in android & https://www.vogella.com/tutorials/AndroidParcelable/article.html , I failed at implementing both, because Serialize sent an empty ArrayList (thus, an empty results page, even though there're book hits) and Parcelable was throwing out different exceptions everytime I used it , probably because I'm using an ArrayAdapter to populate the ListView with books.
I don't think I'm ready to implement the API at https://www.vogella.com/tutorials/AutoValue/article.html and can't use Fragments as well. A better structure would be to use a single activity, View.GONE the background image I so much cherish, and display list of book objects under the search field. But it would be good to make a follow-up on Serialize & Parcelable -- for future projects. So, fellow developers, what's the solution to this?

FirstActivity screenshot SecondActivity screeenshot

Here's my code: MainActivity:

package project.android.gbookslisting;

import android.app.LoaderManager;
import android.content.Intent;
import android.content.Loader;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import androidx.appcompat.app.AppCompatActivity;

import static project.android.gbookslisting.ResultsActivity.adapter;

//import android.support.v4.content.AsyncTaskLoader;
//import android.support.v7.app.AppCompatActivity;

public class ParamsActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<List<Book>>, Serializable {

    private static final int LOADER_ID = 0;
    private static String LOG_TAG = ParamsActivity.class.getName();
    EditText text;
    String query;
    private LoaderManager loaderManager = getLoaderManager();

    @Override
    protected void onCreate (Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.parameters);


        Button query = findViewById(R.id.search_button);
        text = findViewById(R.id.deets_field);


        query.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick (View view) {
                if (text.getText().toString().length() > 0) {                    loaderManager.initLoader(LOADER_ID, null, ParamsActivity.this);
                } else if (text.getText().length() < 1) {
                    text.setHint("Please enter book title/details");
                    text.setHintTextColor(Color.RED);
                }
            }
        });

    }

    @Override
    public Loader<List<Book>> onCreateLoader (int i, Bundle bundle) {
        query = text.getText().toString();
        return new BookLoader(this, query);
    }

    @Override
    public void onLoadFinished (Loader<List<Book>> loader, List<Book> data) {
        // If there is a valid list of {@link Book}s, then add them to the adapter's dataset. This will trigger the ListView to update.
        if (data != null && !data.isEmpty()) {

            data = new ArrayList<Book>();

            Intent i = new Intent(getApplicationContext(), ResultsActivity.class);
            i.putExtra("data", (Serializable) data);
            startActivity(i);
        }
    }

    @Override
    public void onLoaderReset (Loader loader) {
        adapter = new Adapt(this, new ArrayList<Book>());
        adapter.clear();
    }

}

SecondActivity:

package project.android.gbookslisting;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;

import java.io.Serializable;
import java.util.ArrayList;

import androidx.appcompat.app.AppCompatActivity;

public class ResultsActivity extends AppCompatActivity implements Serializable {

    static Adapt adapter;
    static TextView emptyResult;
    ListView bookEntries;
    String LOG_TAG = ResultsActivity.class.getName();

    @Override
    protected void onCreate (Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.hits_page);

        Intent i = getIntent();
        ArrayList<Book> books = (ArrayList<Book>) i.getSerializableExtra("data");

        emptyResult = findViewById(R.id.matches_nill);
        emptyResult.setText(R.string.matches0);

        if (!books.isEmpty()) {
            emptyResult.setVisibility(View.GONE);

            // Create a new adapter that takes a rich (or otherwise empty) list of books as input
            adapter = new Adapt(this, new ArrayList<Book>());

            // Get the list of books from {@link Search}
            bookEntries = findViewById(R.id.catalog);           

            bookEntries.setAdapter(adapter);
            bookEntries.setEmptyView(emptyResult);

            bookEntries.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick (AdapterView<?> adapterView, View view, int position, long l) {
                    // Find the current book that was clicked on
                    Book currentBook = adapter.getItem(position);

                    // Convert the String URL into a URI object (to pass into the Intent constructor)
                    Uri bookUri = Uri.parse(currentBook.getPage());

                    // Create a new intent to view the book URI
                    Intent websiteIntent = new Intent(Intent.ACTION_VIEW, bookUri);

                    // Send the intent to launch a new activity
                    startActivity(websiteIntent);
                }
            });

//            adapter.clear();

            adapter.addAll(books);
        } else {
            emptyResult.setVisibility(View.VISIBLE);
            emptyResult.setText(R.string.matches0);
        }

    }
}

Book obj.:

package project.android.gbookslisting;

import java.io.Serializable;
import java.util.Date;

public class Book {

    private String book_title;
    private String author;
    private String publishing_year;
    private String page;


    public Book (String theTitle, String theAuthor, String theYear, String thePage) {
        this.book_title = theTitle;
        this.author = theAuthor;
        this.publishing_year = theYear;
        this.page = thePage;
    }


    public Book setBook_title (String book_title) {
        this.book_title = book_title;
        return this;
    }

    public Book setAuthor (String author) {
        this.author = author;
        return this;
    }

    public Book setPublishing_year (String publishing_year) {
        this.publishing_year = publishing_year;
        return this;
    }

    public Book setPage (String page) {
        this.page = page;
        return this;
    }

    protected String getAuthor () {
        return author;
    }

    protected String getPublishing_year () { return publishing_year; }

    protected String getPage () {
        return page;
    }

    protected String getBook_title () {
        return book_title;
    }
}

You can declare the a variable that will handle your data = new ArrayList<Book>(); as public static .. However it's not recommended for high level codebase but for the structures of yours, you can implement it.

just declare a variable like this above protected void onCreate() in FirstActivity ..

public static List<Book> book_data = new ArrayList<>();

and transfer the data from public void onLoadFinished (Loader<List<Book>> loader, List<Book> data) to book_data

@Override
public void onLoadFinished (Loader<List<Book>> loader, List<Book> data) {
    // If there is a valid list of {@link Book}s, then add them to the adapter's dataset. This will trigger the ListView to update.
    if (data != null && !data.isEmpty()) {

        //data = new ArrayList<Book>();
        book_data = data;

        Intent i = new Intent(getApplicationContext(), ResultsActivity.class);
        startActivity(i);
    }
}`

You can also try to debug it if it contains a value Log.d(TAG, String.valueOf(data.size()));

and in SecondActivity

@Override
protected void onCreate (Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.hits_page);

    List<Book> books = new ArrayList<>();
    books = FirstActivity.book_data; //Get the data from the First Activity

    ....
    ....
}

All right, so I was able to correct my implementation of the Parcelable interface and the FirstActivity now passes data to SecondActivity . This is it:

package project.android.gbookslisting;

import android.os.Parcel;
import android.os.Parcelable;

public class Book implements Parcelable {

    private String book_title;
    private String author;
    private String publishing_year;
    private String page;


    public Book (String theTitle, String theAuthor, String theYear, String thePage) {
        this.book_title = theTitle;
        this.author = theAuthor;
        this.publishing_year = theYear;
        this.page = thePage;
    }

    public Book(Parcel in) {
        this.book_title = in.readString();
        this.author = in.readString();
        this.publishing_year = in.readString();
        this.page = in.readString();
    }

    public static final Creator<Book> CREATOR = new Creator<Book>() {
        @Override
        public Book createFromParcel (Parcel in) {
            return new Book(in);
        }

        @Override
        public Book[] newArray (int size) {
            return new Book[size];
        }
    };

    protected String getAuthor () { return author; }

    protected String getPublishing_year () { return publishing_year; }

    protected String getPage () {
        return page;
    }

    protected String getBook_title () {
        return book_title;
    }

    @Override
    public int describeContents () {
        return 0;
    }

    @Override
    public void writeToParcel (Parcel parcel, int flags) {
        parcel.writeString(book_title);
        parcel.writeString(author);
        parcel.writeString(publishing_year);
        parcel.writeString(page);
    }

}

I've shared the repository on GitHub @ GBooks Listing , pending more features/updates.

ResultsActivity Sure looks lame, but I'll improve the theming & whatever affects appearance. Thanks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM