Пользовательский загрузчик в Android Studio - PullRequest
0 голосов
/ 03 февраля 2020

В разделе "У меня возникли проблемы" выясните, почему пользовательский загрузчик не работает в основной активности. Может кто-то помочь мне с этим? Я понимаю, что BookLoader не правильно. Но какое значение я могу передать с ним?

Нужно ли что-то возвращать в файле BookLoader in BooKloader.java?



MainActivity. java

package com.example.findbooks;

import androidx.appcompat.app.AppCompatActivity;

import android.app.LoaderManager;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

import static android.view.View.GONE;

public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<List<Books>> {

    /**
     * Tag for the log messages
     */
    public static final String LOG_TAG = MainActivity.class.getSimpleName();
    private WordAdapter wordAdapter;
    private static final int BOOK_LOADER_ID = 1;
    Boolean isConnected;
    private View circleProgressBar;
    private String mUrlRequestGoogleBooks = "";//URL for books data from the Google Books API
    private TextView mEmptyStateTextView;//TextView that is displayed when the list is empty
    private SearchView mSearchViewField;//Search field

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

        final ConnectivityManager cm = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);

        /**
         * At the beginning check the connection with internet and save result to (boolean) variable isConnected
         * Checking if network is available
         * If TRUE - work with LoaderManager
         * If FALSE - hide loading spinner and show emptyStateTextView
         */
        checkConnection(cm);
        // Find a reference to the {@link ListView} in the layout
        ListView listView = findViewById(R.id.list);
        // Create a new adapter that takes an empty list of books as input
        wordAdapter = new WordAdapter(this,new ArrayList<Books>());
        // Set the adapter on the {@link ListView}
        // so the list can be populated in the user interface
        listView.setAdapter(wordAdapter);

        // Find a reference to the empty view
        mEmptyStateTextView = findViewById(R.id.empty_view);
        listView.setEmptyView(mEmptyStateTextView);
        // Circle progress
        circleProgressBar = findViewById(R.id.loading_spinner);
        // Search button
        Button mSearchButton = findViewById(R.id.search_button);
        // Search field
        mSearchViewField = findViewById(R.id.search_view_field);
        mSearchViewField.onActionViewExpanded();
        mSearchViewField.setIconified(true);
        mSearchViewField.setQueryHint("Enter a book title");

        if(isConnected){
            LoaderManager loaderManager = getLoaderManager();
            // Initialize the loader.
            loaderManager.initLoader(BOOK_LOADER_ID, null, this);
        }else {
            Log.i(LOG_TAG, "INTERNET connection status: " + false + ". Sorry dude, no internet - no data :(");
            circleProgressBar.setVisibility(GONE);
            mEmptyStateTextView.setText("No Internet");
        }

        // Set an item click listener on the Search Button, which sends a request to
        // Google Books API based on value from Search View
        mSearchButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                checkConnection(cm);
                if (isConnected){
                    updateQueryUrl(mSearchViewField.getQuery().toString());
                    restartLoader();
                    Log.i(LOG_TAG,"Search value: " + mSearchViewField.getQuery().toString());
                }else {
                    wordAdapter.clear();
                    mEmptyStateTextView.setVisibility(View.VISIBLE);
                    mEmptyStateTextView.setText("No Internet connection.");// ...and display message: "No internet connection."
                }
            }
        });
        // 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.
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                // Find the current book that was clicked on
                Books currentBook = wordAdapter.getItem(position);
                // Convert the String URL into a URI object (to pass into the Intent constructor)
                assert currentBook != null;
                Uri bookUri = Uri.parse(currentBook.getURI());
                // Create a new intent to view the earthquake URI
                Intent websiteIntent = new Intent(Intent.ACTION_VIEW, bookUri);
                // Send the intent to launch a new activity
                startActivity(websiteIntent);
            }
        });
    }
    private String updateQueryUrl(String searchValue) {
        if (searchValue.contains(" ")) {
            searchValue = searchValue.replace(" ", "+");
        }
        StringBuilder sb = new StringBuilder();
        sb.append("https://www.googleapis.com/books/v1/volumes?q=").append(searchValue).append("&filter=paid-ebooks&maxResults=40");
        mUrlRequestGoogleBooks = sb.toString();
        return mUrlRequestGoogleBooks;
    }
    @Override
    public Loader<List<Books>> onCreateLoader(int id, Bundle args) {
        Log.i("There is no instance", ": Created new one loader at the beginning!");
        // Create a new loader for the given URL
        updateQueryUrl(mSearchViewField.getQuery().toString());
        return new BookLoader(this, mUrlRequestGoogleBooks);

    }
    @Override
    public void onLoadFinished(android.content.Loader<List<Books>> loader, List<Books> data) {
        View circleProgressBar = findViewById(R.id.loading_spinner);
        circleProgressBar.setVisibility(GONE);

        mEmptyStateTextView.setText("No Books");
        Log.i(LOG_TAG, ": Books has been moved to adapter's data set. This will trigger the ListView to update!");

        wordAdapter.clear();

        if(data != null && !data.isEmpty()){
            wordAdapter.addAll(data);
        }
    }
    @Override
    public void onLoaderReset(android.content.Loader<List<Books>> loader) {
        // Loader reset, so we can clear out our existing data.
        wordAdapter.clear();
        Log.i(LOG_TAG, ": Loader reset, so we can clear out our existing data!");
    }
    public void restartLoader() {
        mEmptyStateTextView.setVisibility(GONE);
        circleProgressBar.setVisibility(View.VISIBLE);
        getLoaderManager().restartLoader(BOOK_LOADER_ID, null, MainActivity.this);
    }
    public void checkConnection(ConnectivityManager connectivityManager) {
        // Status of internet connection
        NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
        if (activeNetwork != null && activeNetwork.isConnectedOrConnecting()) {
            isConnected = true;
            Log.i(LOG_TAG, "INTERNET connection status: " + (true) + ". It's time to play with LoaderManager :)");
        } else {
            isConnected = false;
        }
    }
}

Запрос. java

package com.example.findbooks;

import android.text.TextUtils;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class Query {
    private static final String LOG_TAG = Query.class.getSimpleName();

    private Query() {
    }

    private static List<Books> getFromJson(String booksJSON){
        if (TextUtils.isEmpty(booksJSON)) {
            return null;
        }
        List<Books> books = new ArrayList<>();
        try {
            // Create a JSONObject from the JSON response string
            JSONObject baseJsonResponse = new JSONObject(booksJSON);
            Log.println(Log.INFO,LOG_TAG,booksJSON);
            // Extract the JSONArray associated with the key called "features",
            // which represents a list of features (or earthquakes).
            JSONArray booksArray = baseJsonResponse.getJSONArray("items");
            Log.println(Log.INFO,LOG_TAG,String.valueOf(booksArray));
            // For each earthquake in the earthquakeArray, create an {@link Earthquake} object
            for (int i = 0; i < booksArray.length(); i++) {
                // Get a single earthquake at position i within the list of earthquakes
                JSONObject currentbook = booksArray.getJSONObject(i);
                Log.println(Log.INFO,LOG_TAG,String.valueOf(currentbook));

                // For a given earthquake, extract the JSONObject associated with the
                // key called "properties", which represents a list of all properties
                // for that earthquake.
                JSONObject volumeInfo = currentbook.getJSONObject("volumeInfo");

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

                    // Check JSONArray Returns true if this object has no mapping for name or if it has a mapping whose value is NULL
                    if (!volumeInfo.isNull("authors")) {
                        // Get 1st element
                        author = (String) authors.get(0);
                    } else {
                        // assign info about missing info about author
                        author = "*** unknown author ***";
                    }
                }else {
                    author = "*** missing info of authors ***";
                }

                // For a given book, extract the JSONObject associated with the
                // key called "imageLinks", which represents a list of all cover
                // images in a different size
                JSONObject imageLinks = volumeInfo.getJSONObject("imageLinks");
                Log.println(Log.INFO, LOG_TAG, String.valueOf(imageLinks));

                // Extract the value for the key called "title"
                String title = volumeInfo.getString("title");

                // Extract the value for the key called "time"
                String publishedDate = volumeInfo.getString("publishedDate");
                String maturityRating = volumeInfo.getString("maturityRating");

                // Extract the value for the key called "url"
                String url = volumeInfo.getString("infoLink");

                // Extract String URL of specific cover
                String coverImageUrl = imageLinks.getString("smallThumbnail");
                // Extract the value for the key called "smallThumbnail"
                // Using REGEX and StringBuilder
                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, "Issue with cover");
                }

                // Create a new {@link Earthquake} object with the magnitude, location, time,
                // and url from the JSON response.
                Books booksItem = new Books(title, author, publishedDate,maturityRating, url,coverImageUrl);

                // Add the new {@link Earthquake} to the list of earthquakes.
                books.add(booksItem);
            }
        } 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("QueryUtils", "Problem parsing the BOOKS JSON results", e);
        }
        // Return the list of earthquakes
        return books;
    }
    public 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;
    }
    private static String readFromStream(InputStream inputStream) throws IOException {
        StringBuilder output = new StringBuilder();
        if (inputStream != null) {
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
            BufferedReader reader = new BufferedReader(inputStreamReader);
            String line = reader.readLine();
            while (line != null) {
                output.append(line);
                line = reader.readLine();
            }
        }
        return output.toString();
    }
    public static List<Books> fetchBooksData(String requestUrl){
        final int SLEEP_TIME_MILLIS = 2000;
        // This action with sleeping is required for displaying circle progress bar
        try {
            Thread.sleep(SLEEP_TIME_MILLIS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 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);
            Log.i(LOG_TAG, "HTTP request: OK");
        } 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 Book}s
        List<Books> listBooks = getFromJson(jsonResponse);
        // Return the list of {@link Book}s
        return listBooks;
    }
}

WordAdapter

package com.example.findbooks;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.media.Image;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.squareup.picasso.Picasso;

import java.util.ArrayList;


public class WordAdapter extends ArrayAdapter<Books> {

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

    public WordAdapter(Activity context, ArrayList<Books> books){

        super(context,0, books);
    }
    @SuppressLint("ViewHolder")
    public View getView(int position, View convertView, ViewGroup parent){
        View listItemView = convertView;
        if (listItemView == null) {
            listItemView = LayoutInflater.from(getContext()).inflate(
                    R.layout.list, parent, false);
        }
        final Books currentBook = getItem(position);
        Log.i(LOG_TAG, "Item position: " + position);

        //This is to get name of the book.
        TextView bookNameTextView = listItemView.findViewById(R.id.bookName);
        assert currentBook != null;
        bookNameTextView.setText(currentBook.getBookName());

        TextView authorNameTextView = listItemView.findViewById(R.id.authorName);
        authorNameTextView.setText(currentBook.getAuthorName());

        TextView pubYearTextView = listItemView.findViewById(R.id.pubYear);
        pubYearTextView.setText(currentBook.getPubYear());

        TextView maturityRatingTextView = listItemView.findViewById(R.id.maturityRating);
        maturityRatingTextView.setText(currentBook.getMatureRating());

        ImageView imageView = listItemView.findViewById(R.id.imageView);
        Picasso.with(getContext()).load(currentBook.getImageURL()).into(imageView);


        return listItemView;
    }
}

Книги. java

package com.example.findbooks;

import android.media.Image;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;

public class Books implements Parcelable {

    public static final Parcelable.Creator<Books> CREATOR = new Parcelable.Creator<Books>(){
        @Override
        public Books createFromParcel(Parcel source) {
            return new Books(source);
        }

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

    private String bookName;
    private String authorName;
    private String pubYear;
    private String matureRating;
    private String URI;
    private String urlImageCover;

    public Books(String bookName,String authorName, String pubYear,String matureRating,String URI,String urlImageCover){
        this.authorName=authorName;
        this.bookName=bookName;
        this.pubYear=pubYear;
        this.matureRating=matureRating;
        this.URI=URI;
        this.urlImageCover=urlImageCover;
    }

    protected Books(Parcel in) {
        this.authorName = in.readString();
        this.bookName = in.readString();
        this.pubYear = in.readString();
        this.matureRating = in.readString();
        this.URI = in.readString();
        this.urlImageCover = in.readString();
    }

    public String getBookName(){
        return bookName;
    }
    public String getAuthorName(){
        return authorName;
    }
    public String getPubYear(){
        return pubYear;
    }
    public String getMatureRating(){
        return matureRating;
    }
    public String getURI(){
        return URI;
    }
    public String getImageURL(){
        return urlImageCover;
    }

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

    public void writeToParcel(Parcel dest, int flags){
        dest.writeString(this.authorName);
        dest.writeString(this.bookName);
        dest.writeString(this.pubYear);
        dest.writeString(this.matureRating);
        dest.writeString(this.urlImageCover);
    }
}

BookLoader. java

package com.example.findbooks;

import android.content.Context;
import android.util.Log;
import androidx.loader.content.AsyncTaskLoader;

import java.util.List;

public class BookLoader extends AsyncTaskLoader<List<Books>> {

    private static final String LOG_TAG = BookLoader.class.getName();//Tag for log messages

    private String mUrl;//Query URL

    public BookLoader(Context context, String url) {
        super(context);
        mUrl = url;
        Log.i(LOG_TAG, ": Loaded!");
    }

    @Override
    protected void onStartLoading() {
        forceLoad();
        Log.i("On start loading", ": Force loaded!");
    }
    /**
     * This is on a background thread.
     */
    @Override
    public List<Books> loadInBackground() {
        if (mUrl == null) {
            return null;
        }
        // Perform the network request, parse the response, and extract a list of books.
        List<Books> books = Query.fetchBooksData(mUrl);
        Log.i(LOG_TAG, ": Loaded in background!");
        return books;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...