-1

How I can fix SearchView in my app, I have already add SearchView in my app, but it doesn't work.

Book Activity :

public class BookActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<List<Book>> {

    public static final String LOG_TAG = BookActivity.class.getName();

    /**
     * Constant value for the earthquake loader ID. We can choose any integer.
     * This really only comes into play if you're using multiple loader.
     */
    private static final int BOOK_LOADER_ID = 1;

    /**
     * URL for books data from the Google Books API
     */
    public static final String GOOGLE_REQUEST_URL = "https://www.googleapis.com/books/v1/volumes?q=war";

    private BookAdapter mAdapter;
    private TextView mEmptyStateTextView;
    ListView bookListView;
    SearchView bookSearchView;
    ArrayList<Book> list;

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

        // Find a reference to the {@link ListView} in the layout
        bookListView = (ListView) findViewById(R.id.list);

        // Create a new adapter that takes the list of books as input
        mAdapter = new BookAdapter(this, new ArrayList<>());

        // Set the adapter on the {@link ListView}
        // so the list can be populated in the user interface
        bookListView.setAdapter(mAdapter);


        ImageView mEmptyStateImageView = findViewById(R.id.empty_view_image);
        bookListView.setEmptyView(mEmptyStateImageView);

        mEmptyStateTextView = findViewById(R.id.empty_view);
        bookListView.setEmptyView(mEmptyStateTextView);

        // Set an item click listener on the ListView, which sends an intent to a web browser
        // to open a website with more information about the selected book.
        bookListView.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 = mAdapter.getItem(position);

                // Convert the String URL into a URI object (to pass into the Intent constructor)
                assert currentBook != null;
                Uri buyBookUri = Uri.parse(currentBook.getUrlBook());

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

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



        bookSearchView = (SearchView) findViewById(R.id.search_view);

        bookSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                Log.i(LOG_TAG, "Problem with onQueryTextSubmit in SearchView");
                Toast.makeText(BookActivity.this,"No Book Found", Toast.LENGTH_LONG).show();
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                Log.i(LOG_TAG, "Problem with onQueryTextChange in SearchView");
                mAdapter.getFilter().filter(newText);
                return false;
            }
        });

        // Get a reference to the ConnectivityManager to check state of network connectivity
        ConnectivityManager connMgr = (ConnectivityManager)
                getSystemService(Context.CONNECTIVITY_SERVICE);

        // Get details on the currently active default data network
        NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();

        // If there is a network connection, fetch data
        if (networkInfo != null && networkInfo.isConnected()) {
            // Get a reference to the LoaderManager, in order to interact with loaders.
            LoaderManager loaderManager = LoaderManager.getInstance(this);

            // Initialize the loader. Pass in the int ID constant defined above and pass in null for
            // the bundle. Pass in this activity for the LoaderCallbacks parameter (which is valid
            // because this activity implements the LoaderCallbacks interface).
            loaderManager.initLoader(BOOK_LOADER_ID, null, this);
        } else {
            // Otherwise, display error
            // First, hide loading indicator so error message will be visible
            View loadingIndicator = findViewById(R.id.loading_indicator);
            loadingIndicator.setVisibility(View.GONE);

            // Update empty state with no connection error message
            mEmptyStateImageView.setImageResource(R.drawable.wifi_off);
            mEmptyStateTextView.setText(R.string.no_internet_connection);
        }
    }


    @Override
    public Loader<List<Book>> onCreateLoader(int i, Bundle args) {
        Log.i(LOG_TAG, "Problem with onCreateLoader");
        return new BookLoader(this, GOOGLE_REQUEST_URL);
    }

    @Override
    public void onLoadFinished(Loader<List<Book>> loader, List<Book> books) {
        Log.i(LOG_TAG, "Problem in onLoadFinished");
        View loadingIndicator = findViewById(R.id.loading_indicator);
        loadingIndicator.setVisibility(View.GONE);

        mEmptyStateTextView.setText(R.string.no_books);

        mAdapter.clear();

        if (books != null && !books.isEmpty()) {
            mAdapter.addAll(books);
        }
    }

    @Override
    public void onLoaderReset(Loader<List<Book>> loader) {
        Log.i(LOG_TAG, "Problem in onLoaderReset");
        mAdapter.clear();
    }
}

Book Adapter :

public class BookAdapter extends ArrayAdapter<Book> {

    public BookAdapter (Activity context, ArrayList<Book> books) {
        // Here, we initialize the ArrayAdapter's internal storage for the context and the list.
        // the second argument is used when the ArrayAdapter is populating a single TextView.
        // Because this is a custom adapter for two TextViews and an ImageView, the adapter is not
        // going to use this second argument, so it can be any value. Here, we used 0.
        super(context, 0, books);
    }

    /**
     *
     * @param position    The position in the list of data that should be displayed in the
     *                    list item view.
     * @param convertView The recycled view to populate.
     * @param parent      The parent ViewGroup that is used for inflation.
     * @return The View for the position in the AdapterView.
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // Check if there is an existing list item view (Called convertView) that we can reuse,
        // otherwise, if convertView is null, then inflate a new list item layout.
        View listItemView = convertView;
        if (listItemView == null) {
            listItemView = LayoutInflater.from(getContext()).inflate(
                    R.layout.book_list_item, parent, false);
        }

        // Find the book at the given position in the list of books
        final Book currentBook = getItem(position);

        // Find the TextView with view ID bookName
        TextView bookNameView =  listItemView.findViewById(R.id.title);
        // Display the bookName of the current book in that TextView
        bookNameView.setText(currentBook.getTitle());

        // Find the TextView with view ID bookAuthor
        TextView bookAuthorView = listItemView.findViewById(R.id.author);
        // Display the bookAuthor of the current book in that TextView
        bookAuthorView.setText(currentBook.getAuthor());

        // Find the TextView with view ID numberPage
        TextView numberPageOfBookView =  listItemView.findViewById(R.id.pageCount);
        // Display the numberPage of the current book in that TextView
        numberPageOfBookView.setText(currentBook.getPageCount());

        // Find the TextView with view ID bookLanguage
        TextView bookLanguageView =  listItemView.findViewById(R.id.language);
        // Display the bookLanguage of the current book in that TextView
        bookLanguageView.setText(currentBook.getLanguage());

        // Find the ImageView with view ID bookCover
        ImageView bookImageCover = listItemView.findViewById(R.id.cover_image);
        // Display the book cover of the current book in that book
        Picasso.get().load(currentBook.getImageUrl()).into(bookImageCover);

        return listItemView;
    }
}

Book Utils :

public final class BookUtils {

    private static final String LOG_TAG = BookUtils.class.getSimpleName();


    /**
     * Create a private constructor because no one should ever create a {@link BookUtils} object.
     * This class is only meant to hold static variables and methods, which can be accessed
     * directly from the class name QueryUtils (and an object instance of QueryUtils is not needed).
     */
    private BookUtils() {
    }

    /** Sample JSON response for a USGS query */
    public static List<Book> fetchBookData(String requestUrl) {
        // Create URL object
        URL url = createUrl(requestUrl);

        // Perform HTTP request to the URL and receive a JSON response back
        String jsonResponse = null;
        try {
            jsonResponse = makeHttpRequest(url);
        } catch (IOException e) {
            Log.e(LOG_TAG, "Problem making the HTTP request.", e);
        }

        // Extract relevant fields from the JSON response and create a list of {@link Earthquake}s
        List<Book> books = extractBookFromJson(jsonResponse);

        // Return the list of {@link Earthquake}s
        return books;
    }

    /**
     * Returns new URL object from the given string URL.
     */
    private static URL createUrl(String stringUrl) {
        URL url = null;
        try {
            url = new URL(stringUrl);
        } catch (MalformedURLException e) {
            Log.e(LOG_TAG, "Problem building the URL ", e);
        }
        return url;
    }

    private static String makeHttpRequest(URL url) throws IOException {
        String jsonResponse = "";

        // If the URL is null, then return early.
        if (url == null) {
            return jsonResponse;
        }

        HttpURLConnection urlConnection = null;
        InputStream inputStream = null;
        try {
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setReadTimeout(10000 /* milliseconds */);
            urlConnection.setConnectTimeout(15000 /* milliseconds */);
            urlConnection.setRequestMethod("GET");
            urlConnection.connect();

            // If the request was successful (response code 200),
            // then read the input stream and parse the response.
            if (urlConnection.getResponseCode() == 200) {
                inputStream = urlConnection.getInputStream();
                jsonResponse = readFromStream(inputStream);
            } else {
                Log.e(LOG_TAG, "Error response code: " + urlConnection.getResponseCode());
            }
        } catch (IOException e) {
            Log.e(LOG_TAG, "Problem retrieving the book JSON results.", e);
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            if (inputStream != null) {
                // Closing the input stream could throw an IOException, which is why
                // the makeHttpRequest(URL url) method signature specifies than an IOException
                // could be thrown.
                inputStream.close();
            }
        }
        return jsonResponse;
    }

    /**
     * Convert the {@link InputStream} into a String which contains the
     * whole JSON response from the server.
     */
    private static String readFromStream(InputStream inputStream) throws IOException {
        StringBuilder output = new StringBuilder();
        if (inputStream != null) {
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
            BufferedReader reader = new BufferedReader(inputStreamReader);
            String line = reader.readLine();
            while (line != null) {
                output.append(line);
                line = reader.readLine();
            }
        }
        return output.toString();
    }

    /**
     * Return a list of {@link Book} objects that has been built up from
     * parsing a JSON response.
     */
    public static List<Book> extractBookFromJson(String bookJSON) {
        if (TextUtils.isEmpty(bookJSON)){
            return null;
        }

        // Create an empty ArrayList that we can start adding earthquakes to
        List<Book> books = new ArrayList<>();

        // Try to parse the SAMPLE_JSON_RESPONSE. If there's a problem with the way the JSON
        // is formatted, a JSONException exception object will be thrown.
        // Catch the exception so the app doesn't crash, and print the error message to the logs.
        try {

            JSONObject baseJsonResponse = new JSONObject(bookJSON);

            JSONArray bookArray = baseJsonResponse.getJSONArray("items");

            for( int i = 0; i < bookArray.length(); i++) {

                JSONObject currentBook = bookArray.getJSONObject(i);

                JSONObject volumeInfo = currentBook.getJSONObject("volumeInfo");

                String author;

                if (volumeInfo.has("authors")) {
                    JSONArray authors = volumeInfo.getJSONArray("authors");
                    Log.println(Log.INFO, LOG_TAG, String.valueOf(authors));

                    if (!volumeInfo.isNull("authors")) {
                        author = (String) authors.get(0);
                    } else {
                        author = "*** unknown author ***";
                    }
                } else {
                    author = "*** missing info of authors ***";
                }

                JSONObject imageLinks = volumeInfo.getJSONObject("imageLinks");
                Log.println(Log.INFO, LOG_TAG, String.valueOf(imageLinks));

                String title = volumeInfo.getString("title");

                String pageCount = volumeInfo.getString("pageCount");

                String language = volumeInfo.getString("language");

                String bookUrl = volumeInfo.getString("previewLink");

                String coverImageUrl = imageLinks.getString("smallThumbnail");

                StringBuilder stringBuilder = new StringBuilder();

                Pattern p = Pattern.compile("id=(.*?)&");
                Matcher m = p.matcher(coverImageUrl);
                if (m.matches()) {
                    String id = m.group(1);
                    coverImageUrl = String.valueOf(stringBuilder.append("https://books.google.com/books/content/images/frontcover/").append(id).append("?fife=w300"));
                } else {
                    Log.i(LOG_TAG, "Issues with cover");
                }

                Book book = new Book(title, author, pageCount, language, bookUrl, coverImageUrl);
                books.add(book);
            }

        } catch (JSONException e) {
            // If an error is thrown when executing any of the above statements in the "try" block,
            // catch the exception here, so the app doesn't crash. Print a log message
            // with the message from the exception.
            Log.e("BookUtils", "Problem parsing the book JSON results", e);
        }

        // Return the list of earthquakes
        return books;
    }
}
  • Simply you can use the local database here. Just store your data into the local database and fire query on text watcher to fetch data as per requirements. – maulik panchal Mar 16 '22 at 09:48
  • How can this be done? – zaid shaheen Mar 16 '22 at 10:15
  • What exactly about this code "doesn't work"? – Ryan M Mar 17 '22 at 09:51
  • @zaidshaheen Just add your data into the local database initially. Then when you type anything in edit text for search just fire query as below : **@Query("SELECT * FROM CategoryList WHERE name LIKE :name") fun getSeachData(name: String): List** And simply display data from this query result. – maulik panchal Mar 21 '22 at 06:09

1 Answers1

0

You have initialized your mAdapter using an empty ArrayList in the following line:

mAdapter = new BookAdapter(this, new ArrayList<>());

You should initialize ArrayList<Book> list and pass it as an ArrayList Of Book Objects into the mAdapter constructor: mAdapter = new BookAdapter(this, list);

Also when you initialize the mAdapter by an ArrayList of Book objects, you can not Filter the adapter by a String text, while you did it wrongly in mAdapter.getFilter().filter(newText);. If you want to use Filter method, you have to override the method in BookAdapter to filter the list using Book Objects.

But I think the easier way is like this:

1- Define two separate ArrayLists:

ArrayList<Book> list = fetchBookData( "URL" );
ArrayList<Book> searchList = new ArrayList<Book>();
mAdapter = new BookAdapter(this, searchList);
bookListView.setAdapter(mAdapter);

2- Use for loop in onQueryTextChange(String newText) { } to find the book (Be careful that you have to define a getTitle() method in the Book class):

@Override
public boolean onQueryTextChange(String newText) {

searchList.clear();

    for(Book book : list){
        if(book.getTitle().equals(newText)){
            searchList.add(book)
        }
    }

    mAdapter.notifyDataSetChanged();
    return false;
}
Amir
  • 1
  • 1
  • book.getTitle() == newText should be replace with book.getTitle().equals(newText). see [link](https://stackoverflow.com/questions/767372/string-equals-versus#:~:text=Generally%20.,the%20values%20of%20primitive%20types.) – Quraishi sazid Mar 18 '22 at 04:58
  • When I add ArrayList list = fetchBookData( "URL" ); this line, fetchBookData show in red color, and the app is crashing. what is the problem? – zaid shaheen Mar 18 '22 at 15:17