Android AsyncTaskLoader не работает в основном с ArrayList - PullRequest
0 голосов
/ 31 октября 2019

Я создаю приложение новостей для Android, чтобы получать данные из газеты новостей Gurdian и показывать его в моем приложении. У меня проблема с работой приложения по AyncTaskLoader Я создаю класс данных

{
/**
 * Class to make and define objects of news.
 */

public class NewsClass {

    // Define String of News(title,author,description,publishDate).
    private String news_title;
    private String author_name;
    private String description;
    private String date;

    /**
     * Constructor to make objects from News .
     *
     * @param news_title  it takes news title  string.
     * @param author_name it takes news author name string.
     * @param description it takes news description string.
     * @param date        it takes news publish date string.
     */
    NewsClass(String news_title, String author_name, String description, String date) {
        this.news_title = news_title;
        this.author_name = author_name;
        this.description = description;
        this.date = date;
    }

    /**
     * @return news title.
     */
    String getNews_title() {
        return news_title;
    }

    /**
     * @return news author name.
     */
    String getAuthor_name() {
        return author_name;
    }

    /**
     * @return news description.
     */
    String getDescription() {
        return description;
    }

    /**
     * @return news publish date.
     */
    String getDate() {
        return date;
    }
}

и класс адаптера

/**
 * Custom Adapter to arrange news items in List View.
 */
public class NewsAdapter extends ArrayAdapter<NewsClass> {

    private List<NewsClass> newsList = new ArrayList<NewsClass>();

    /**
     * Constructor.
     *
     * @param context  it takes context.
     * @param resource it takes resource id.
     * @param news     it takes array of data.
     */
    NewsAdapter(@NonNull Context context, int resource, ArrayList<NewsClass> news) {
        super(context, resource, news);
    }

    /**
     * define view to take list_item elements and put it in layout.
     *
     * @param position    it takes every news element position from the arraylist.
     * @param convertView it takes view and inflates list_item in parent.
     * @param parent      it takes parent.
     * @return it returns View of each News Element with its data according to list_item.
     */
    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        // Define new View and attach give it convertview.
        View view = convertView;

        //Check if convertview is null and inflate list_item layout into it.
        if (view == null) {
            view = LayoutInflater.from(getContext()).inflate(R.layout.list_item,
                    parent,
                    false);
        }

        // create object from NewsClass and get its position.
        NewsClass newsClass = getItem(position);

        // declare and define news title TextView.
        TextView news_title = view.findViewById(R.id.news_title);
        // declare and define news Author TextView.
        TextView news_author_name = view.findViewById(R.id.news_author_name);
        // put element title and attach it to its TextView.
        news_title.setText(newsClass.getNews_title());
        // put element author and attach it to its TextView.
        news_author_name.setText(newsClass.getAuthor_name());


        return view;
    }
    public void setNews(List<NewsClass> data) {
        newsList.addAll(data);
        notifyDataSetChanged();
    }
}

и класс Utils для выполнения HTTP-запроса и выборки данных JSON

/**
 * Class to handle HTTP Requests and JSON parsing.
 */
public class Utils {

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


    /**
     * Fetching data from url and storing it in ArrayList of type NewsClass.
     *
     * @param requestUrl function requires url.
     * @return it return an ArrayList of type NewsClass.
     */
    static ArrayList<NewsClass> fetchNewsData(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, "Error closing input stream", e);
        }

        // Extract relevant fields from the JSON response and create an  object.
        // Return the {@link NewsClass}
        return extractFeatureFromJson(jsonResponse);
    }

    /**
     * Function to create URL object from given String URL.
     *
     * @param stringUrl it takes String of URL
     * @return Returns new URL object from the given string URL.
     */
    private static URL createUrl(String stringUrl) {
        // declare new URL and initailizing it
        URL url = null;

        // surround with try and catch
        try {
            // initialize URL and set param to string to create URL
            url = new URL(stringUrl);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        // return URL
        return url;
    }

    /**
     * Make an HTTP request to the given URL and return a String as the response.
     *
     * @param url it takes URL which we get from previos function.
     * @return it return JSON Response.
     * @throws IOException url may make exception of this type
     */
    private static String makeHttpRequest(URL url) throws IOException {
        // declare new empty String.
        String jsonResponse = "";

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

        // declare new HttpURLConnection.
        HttpURLConnection urlConnection = null;
        // declare new InputStream.
        InputStream inputStream = null;
        // surround with try and catch
        try {
            // create HTTP request.
            urlConnection = (HttpURLConnection) url.openConnection();
            // set request method.
            urlConnection.setRequestMethod("GET");
            // connect to server.
            urlConnection.connect();

            // If the request was successful (response code 200),
            // then read the input stream and parse the response.
            if (urlConnection.getResponseCode() == 200) {
                // get InputStream with data to read it.
                inputStream = urlConnection.getInputStream();
                // read from stream and return string then saved it in jsonResponse.
                jsonResponse = readFromStream(inputStream);
            } else {
                Log.e(LOG_TAG, "Error response code: " + urlConnection.getResponseCode());
            }
        } catch (IOException e) {
            Log.e(LOG_TAG, "Problem retrieving the News JSON results.", e);
        } finally {
            // if urlConnection return with data
            if (urlConnection != null) {
                // then disconnect .
                urlConnection.disconnect();
            }
            // if inputStream return with data.
            if (inputStream != null) {
                //  close the inputStream.
                inputStream.close();
            }
        }
        // return jsonResponse with data.
        return jsonResponse;
    }

    /**
     * readFromStream to the given InputStream then return String (JSON).
     *
     * @param inputStream it takes inputStream.
     * @return return String of JSON Response.
     * @throws IOException inputStream may make exception.
     */
    private static String readFromStream(InputStream inputStream) throws IOException {
        // initialize StringBuilder.
        StringBuilder stringBuilder = new StringBuilder();
        // if inputStream return with data.
        if (inputStream != null) {
            // create and initialize InputStreamReader with two params (inputStream, Symbol rate utf-8).
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
            // create and initialize BufferedReader with one param (InputStreamReader).
            BufferedReader reader = new BufferedReader(inputStreamReader);
            // new String to save data from BufferedReader line by line.
            String line = reader.readLine();
            // loop to update String line by line and append this lines to stringBuilder.
            while (line != null) {
                stringBuilder.append(line);
                line = reader.readLine();
            }
        }
        // return String.
        return stringBuilder.toString();
    }

    /**
     * extractFeatureFromJson to the given String then return ArrayList<NewsClass>.
     *
     * @param newsJSON it takes json objects.
     * @return ArrayList of data From JSON.
     */
    private static ArrayList<NewsClass> extractFeatureFromJson(String newsJSON) {
        // If the JSON string is empty or null, then return early.
        if (TextUtils.isEmpty(newsJSON)) {
            return null;
        }

        // Create an empty ArrayList that we can start adding news to.
        ArrayList<NewsClass> news = new ArrayList<>();
        // surround with try and catch.
        try {
            // initialize baseJSONObject.
            JSONObject baseJsonResponse = new JSONObject(newsJSON);
            // initialize and get response from baseJSONObject.
            JSONObject response = baseJsonResponse.getJSONObject("response");
            // initialize JSONArray results to get items array.
            JSONArray itemsArray = response.getJSONArray("results");
            // loop to get all items in itemsArray.
            for (int i = 0; i < itemsArray.length(); i++) {
                // JSONObject to get data from each item.
                JSONObject firstitem = itemsArray.getJSONObject(i);

                // Get News Title.
                // String to get news webTitle.
                String title;
                if (firstitem.has("webTitle")) {

                    title = firstitem.getString("webTitle");
                } else {
                    title = "Title not Found";
                }

                //Get News Author.
                // String to get news author.
                String author;
                if (firstitem.has("pillarId")) {

                    author = firstitem.getString("pillarId");
                } else {
                    author = "Author not Found";
                }


                //Get News Publishing Date.
                // String to get news webPublicationDate.
                String date;
                if (firstitem.has("webPublicationDate")) {

                    date = firstitem.getString("webPublicationDate");
                } else {
                    date = "Published Date not Found";
                }

                // Get News Description Link.
                // String to get news webUrl.
                String description;
                if (firstitem.has("webUrl")) {

                    description = firstitem.getString("webUrl");
                } else {
                    description = "Description not Found";
                }


                // add every object from JSON Response to News ArrayList.
                news.add(new NewsClass(title, author, description, date));
            }
        } catch (JSONException e) {
            Log.e(LOG_TAG, "Problem parsing the News JSON results", e);
        }
        // return Arraylist news.
        return news;
    }


}

и это основное задание

public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<ArrayList<NewsClass>> {
    // Define news title EditText to search for.
    EditText news_title;
    // Define news search Button to search for.
    Button search;
    // Define progressBar.
    ProgressBar progressBar;
    // Define news listView .
    ListView listView;
    // Define news news Adapter Object.
    NewsAdapter newsAdapter;
    // Define news API String.
    String NEWS_API;
    // Define news image ImageView .
    ImageView news;
    // Define news search string to search for.
    String s;


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


        // define views in activity_main_layout.
        news_title = findViewById(R.id.edit_txt_news);
        search = findViewById(R.id.search_btn);
        listView = findViewById(R.id.listview);
        news = findViewById(R.id.news);
        progressBar = findViewById(R.id.progeress_bar);

        //set progressBar visibility to INVISIBLE .
        progressBar.setVisibility(View.INVISIBLE);

        // create object from newsAdapter and give it context and resource and ArrayList.
        newsAdapter = new NewsAdapter(getApplicationContext(), 0, new ArrayList<NewsClass>());

        // Attach our Adapter to ListView.
        listView.setAdapter(newsAdapter);

        // handle listview items clicks to open NewsDetails Activity to show element details.
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                NewsClass currentnews = newsAdapter.getItem(position);

                // get every news element data and store it in variables.
                String title = currentnews.getNews_title();
                String author = currentnews.getAuthor_name();
                String Date = currentnews.getDate();
                String description = currentnews.getDescription();

                // Make new Intent to open NewsDetails Activity.
                Intent intent = new Intent(getApplicationContext(), NewsDetail.class);
                // send every news element data and store it in variables with the Intent.
                intent.putExtra("title", title);
                intent.putExtra("author", author);
                intent.putExtra("date", Date);
                intent.putExtra("desc", description);


                startActivity(intent);
            }
        });

        // Check Internet Connectivity.
        if (isNetworkConnected()) {


            // initiate Loader Manager.
            getSupportLoaderManager().initLoader(1, null, this).forceLoad();
            // handle search box searches when we click search Button.
            search.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // get text entered by user and save it in String s.
                    s = news_title.getText().toString();

                    // check if EditText don't have anything "user didn't write anything to search for.
                    if (s.length() == 0) {
                        //make a toast message to the user.
                        Toast.makeText(getApplicationContext(), "Please Enter News to search for ", Toast.LENGTH_LONG).show();
                    } else {

                        // hide progressBar
                        news.setVisibility(View.GONE);

                        // Enter News Api and store it and give it user search word.
                        NEWS_API =
                                "https://content.guardianapis.com/search?q=" + s + "&api-key=fb2fab34-e55f-411f-9892-af1c207c759c";

                        InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(
                                Activity.INPUT_METHOD_SERVICE);
                        if (inputMethodManager != null) {
                            inputMethodManager.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
                        }

                        // empty search Box after making search.
                        news_title.setText("");


                    }
                }

            });
            // hide progress bar.
            news.setVisibility(View.GONE);
            // Enter News Api and store it to show all news if user did not search anything.
            NEWS_API =
                    "https://content.guardianapis.com/search?api-key=fb2fab34-e55f-411f-9892-af1c207c759c";

        } else
            // Make Toast to Ask User to Open Internet Connection
            Toast.makeText(this, "Please Connect to Internet to fetch Data", Toast.LENGTH_LONG).show();
    }

    @NonNull
    @Override
    public Loader<ArrayList<NewsClass>> onCreateLoader(int id, @Nullable Bundle bundle) {

        return new NewsAsyncLoader(MainActivity.this, bundle.getString(NEWS_API));

    }

    @Override
    public void onLoadFinished(@NonNull Loader<ArrayList<NewsClass>> loader, ArrayList<NewsClass> data) {

        newsAdapter.setNews(data);
    }

    @Override
    public void onLoaderReset(@NonNull Loader<ArrayList<NewsClass>> loader) {
        newsAdapter.setNews(new ArrayList<NewsClass>());

    }

    // Function To check Internet Connectivity
    private boolean isNetworkConnected() {
        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

        return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected();
    }

    // Class To Load In background by AsyncTaskLoader
    class NewsAsyncLoader extends AsyncTaskLoader<ArrayList<NewsClass>> {

        public NewsAsyncLoader(Context context, String Url) {

            super(context);
            Url = NEWS_API;
        }

        @Override
        public ArrayList<NewsClass> loadInBackground() {
            if (NEWS_API == null) {
                return null;
            }


            ArrayList<NewsClass> Newslist = Utils.fetchNewsData(NEWS_API);

            return Newslist;
        }
    }


}

, но оно не работает и не извлекает dataTask, но при преобразовании его в AsyncTaskLoader оно запирает

...