首页 > 解决方案 > 如何在 API 超过 23 的 Android 中通过 Loader Manager 显示数组列表?

问题描述

我在屏幕上显示我的数组列表项时遇到问题。谷歌搜索所有可能的错误,但没有任何帮助。因为这些答案是针对较低的 API 23。这是我的全部代码,所以请帮助我,我该怎么办?

MainActivity 

package com.example.earthquake6;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
//import android.support.v7.app.AppCompatActivity;

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 java.util.ArrayList;
import java.util.List;

//import android.app.LoaderManager;//OK
//import androidx.loader.app.LoaderManager;

import android.content.Loader;//Ok
//import androidx.loader.content.Loader;
import android.app.LoaderManager.LoaderCallbacks;//OK
//import androidx.loader.app.LoaderManager.LoaderCallbacks;

public class MainActivity extends AppCompatActivity implements LoaderCallbacks<List<CustomWord>> {
    // @@@@@@@@@@ States
    //region
    private static final String LOG_TAG = MainActivity.class.getName();
    /**
     * URL for earthquake data from the USGS dataset
     */
    private static final String USGS_REQUEST_URL =
            "http://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&orderby=time&minmag=6&limit=10";

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

    /**
     * Adapter for the list of earthquakes
     */
    private CustomArrayAdapter mCustomArrayAdapter;
    //endregion

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i("*********************", "*********************");
        Log.i(LOG_TAG, "Test: EarthQuacke Activity  onCreate  called");
        setContentView(R.layout.share_activity);

        // Create a new adapter that takes an empty list of earthquakes as input
        mCustomArrayAdapter = new CustomArrayAdapter(MainActivity.this, new ArrayList<CustomWord>());
        // Create list view to set our customArrayAdapter  on it
        ListView listView = (ListView) findViewById(R.id.share_view_id);
        listView.setAdapter(mCustomArrayAdapter);

        // to set OnclickListener on each roe of listviews
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                // get rows of each elements in listview
                // each row is a "CustomWord.class", so when get elemnts from
                // a listview by below
                CustomWord customWord1 = mCustomArrayAdapter.getItem(position);
                // now get url elemnt
                // uri use to convert ulr string to a legal encoding format and acceptable to ulr object
                // To make these characters legal they need to be encoded before passing them to the URL constructor.
                Uri uri = Uri.parse(customWord1.getmUrl());
                // define an intent to open related website
                // for send an intent to another app use Intent.ACTION_VIEW
                // for more inf
                // https://developer.android.com/training/basics/intents/sending
                Intent urlIntent = new Intent(Intent.ACTION_VIEW, uri);
                startActivity(urlIntent);
            }
        });

        // Get a reference to the LoaderManager, in order to interact with loaders.
//        LoaderManager loaderManager = getLoaderManager();
        android.app.LoaderManager loaderManager1 = getLoaderManager();
        // 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).


        //The third argument(here: this) is what object should receive the LoaderCallbacks (and therefore,
        // the data when the load is complete!) - which will be this activity. This code goes
        // inside the onCreate() method of the EarthquakeActivity, so that the loader
        // can be initialized as soon as the app opens.
        loaderManager1.initLoader(EARTHQUAKE_LOADER_ID, null, this);
        Log.i(LOG_TAG, "Test: EarthQuacke Activity  LoaderManager.initLoader  called");
    }
    @Override
    public  Loader<List<CustomWord>> onCreateLoader(int id, Bundle args) {
        // Create a new loader for the given URL
        Log.i(LOG_TAG,"Test: EarthQuacke Activity  onCreateLoader  called");
        return new EarthQuakeLoader(this,USGS_REQUEST_URL);
    }

    @Override
    public void onLoadFinished(Loader<List<CustomWord>> loader, List<CustomWord> customWordList) {
        // Clear the adapter of previous earthquake data
        Log.i(LOG_TAG,"Test: EarthQuacke Activity  onLoadFinished  called");
        mCustomArrayAdapter.clear();

        // If there is a valid list of {@link Earthquake}s, then add them to the adapter's
        // data set. This will trigger the ListView to update.
        if (customWordList != null && !customWordList.isEmpty()) {
            mCustomArrayAdapter.addAll(customWordList);
        }
    }

    @Override
    public void onLoaderReset(Loader<List<CustomWord>> loader) {
        Log.i(LOG_TAG,"Test: EarthQuacke Activity  onLoaderReset  called");
        // Loader reset, so we can clear out our existing data.
        mCustomArrayAdapter.clear();

    }
}

然后

 In my Loader : EarthQuakeLoader

package com.example.earthquake6;

//import androidx.loader.content.AsyncTaskLoader; -----
//import android.content.AsyncTaskLoader;++++

import android.content.AsyncTaskLoader;//Ok
//import androidx.loader.content.AsyncTaskLoader;//xxxxxxxxxxxxxxxxxx


import android.content.Context;
import androidx.core.content.ContextCompat;
import android.util.Log;

// we should use  import android.content.AsyncTaskLoader;  or import androidx.loader.content.AsyncTaskLoader;
// rather than import androidx.loader.content.AsyncTaskLoader;
// because if we do not use import android.content.AsyncTaskLoader;, we got error  on  MainActivity class
// at the code related to:
//@Override
//public Loader<List<CustomWord>> onCreateLoader(int id, Bundle args) {
//        // Create a new loader for the given URL
//        return new EarthQuakeLoader(this,USGS_REQUEST_URL);
//        }
// this library is This class was deprecated in API level 28. by android developer ref:
// https://developer.android.com/reference/android/content/AsyncTaskLoader
//we could Use the : Support Library AsyncTaskLoader



    import java.util.List;


   

    public class EarthQuakeLoader extends AsyncTaskLoader<List<CustomWord>> {
        // @@@@@@@@@@ States
        //region
        /** Tag for log messages */
        private static final String LOG_TAG = EarthQuakeLoader.class.getName();
    
        /** Query URL */
        private String mUrl;
        //endregion
    
        /**
         * Constructs a new {@link EarthQuakeLoader}.
         *
         * @param context of the activity
         * @param url to load data from
         */
        public EarthQuakeLoader(Context context, String url) {
            super(context);
            mUrl = url;
        }
    
        @Override
        protected void onStartLoading() {
            Log.i(LOG_TAG,"Test: EarthQuakeLoader Class  onStartLoading  called");
            forceLoad();
        }
    
        @Override
        public List<CustomWord> loadInBackground() {
            if(mUrl!=null){
                return null;
            }
            // Perform the network request, parse the response, and extract a list of earthquakes.
            List<CustomWord> customWordList = FetchDataFromInternet.customArrayListFetchDataFromInternet(mUrl);
            Log.i(LOG_TAG,"Test: EarthQuakeLoader Class  loadInBackground  called");
            return customWordList;
        }
    
        @Override
        public void deliverResult(List<CustomWord> data) {
            Log.i(LOG_TAG,"Test: EarthQuakeLoader Class  deliverResult  called");
            super.deliverResult(data);
        }
    }

在另一个班级:

CustomWord :

package com.example.earthquake6;

public class CustomWord {
    // States
    private double mMagnitude;
    private String mPlace;
    private long mTime;
    private String mUrl;
    // Constructor
    public CustomWord(double magnitude,String place,long time,String url){
        this.mMagnitude = magnitude;
        this.mPlace = place;
        this.mTime = time;
        this.mUrl = url;
    }

    public double getmMagnitude() {
        return mMagnitude;
    }

    public String getmPlace() {
        return mPlace;
    }

    public long getmTime() {
        return mTime;
    }

    public String getmUrl() {
        return mUrl;
    }
}

和另一个类:

FetchDataFromInternet  :



package com.example.earthquake6;


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.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;

/**
 * Helper methods related to requesting and receiving earthquake data from USGS.
 */
public final class FetchDataFromInternet  {
    // AsyncTask<Params,Progress,Result >      :
    // if one elemnt do not use, then we use "Void" replace with it
    // in this app we use:  AsyncTask<URL, Void, String>,becuase we dont use progress
    //
    // any element in this < , , >, is an object, even its be a primitive data type like int,long,
    // or else. so long changed to Long, either void change to Void with capital v
    // as there are multiple variable for Params(so saved in array), There are multiple variable
    // for Progress(so saved in array),ans either for Result(so saved in array)
    // Params    :
    // its method to use is :   doInBackground
    // data type in parameters sent to background task, here data type is URL,that means that background
    // in doInBackground(URL... urls)    task will accept the list of URLs
    // Progress :
    // its method to use is :   onProgressUpdate
    // data type used for, measuring progress of the work  being down on the
    // background thread,to do this, we specify Progress as "Integer" data type,as
    // progress parameter,so we can call "publish prgress with integer value in the background,
    // then in method,"onProgressUpdate(Integer progress)", which is called by main thread, we
    // receive that integer progress and update UI
    // Result  :
    // its method to use is :   onPostExecute
    // is data type of return value from "doInBackground" method
    // this is data type of result of background work
    // in this app, return data type from "doInBackground" method is string,so we have String data type in
    //  AsyncTask<URL, Void, String>
    // @@@@@@@@@@         States
    //region
    // use to set up log messages
    public static final String LOG_TAG = FetchDataFromInternet.class.getSimpleName();
    //endregion
    // Constructor
    //region
    /**
     * Create a private constructor because no one should ever create a {@link FetchDataFromInternet} 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 FetchDataFromInternet() {
    }
    //endregion

    public static ArrayList<CustomWord> customArrayListFetchDataFromInternet(String stringURL) {
        //   Step 1: Create Url object from nput string url
        Log.i(LOG_TAG,"Test: FetchDataFromInternet Class  customArrayListFetchDataFromInternet  called");

        // Don't perform the request if there are no URLs, or the first URL is null.
        if (stringURL == null) {
            return null;
        }
        URL urlObject = creatURL(stringURL);
        /*        // Perform HTTP request to the URL and receive a JSON response back
        //  2-   Obtain a URLConnection object from the URL
        //  3-   Configure the URLConnection
        //  4-   Read the header fields  ::::  Not used Here
        //  5-   Get an input stream and read data
        // steps above are in below method*/
        String jasonStringUrlSourceResponse = "";//set to null
        try{
            // if jasonStringUrlSourceResponse url is null then jasonStringUrlSourceResponse is null
            jasonStringUrlSourceResponse = httpConectionReadStreamedData(urlObject);// if  httpConectionReadStreamedData method,
            // has no throw exception,this try/catch got error
        }catch (IOException ioException){
            // handler
            Log.e(LOG_TAG, "Problem making the HTTP request.", ioException);
        }
        // Extract relevant fields from the JSON response and create an {@link Event} object
        ArrayList arrayListQueryFromJAson = QueryFromJAson(jasonStringUrlSourceResponse);

        return arrayListQueryFromJAson;
    }

    ///////////////////////  1-   Create URL object from given String
    private  static URL creatURL(String urlString) {
        URL myURL = null;
        try {
            // prepare url for creating a URL object,because url maybe has special characters example:
            //  http://example.com/hello world/     -------URI----->  http://example.com/hello%20world
            // the space between hello and world occupy by %20 automatically by uri
            // this do by
            URI uri = new URI(urlString);
            // Convert uri to url
            myURL = uri.toURL();
        } catch (MalformedURLException | URISyntaxException exception) {  //MalformedURLException is for URL URISyntaxException exception is for URI
            Log.v("LOG_TAG","Error with creating URL",exception);
            exception.printStackTrace();
            return null;
        }
        return myURL;// URL myURL = null; must be declared for return
    }// End creatURL
    private  static String httpConectionReadStreamedData(URL myURL) throws IOException{// need throws ioexception
        String jsonResponse = "";
        // to make sure that url is not null
        if(myURL==null){
            return jsonResponse;// by return jsonResponse we get out the method httpConectionReadStreamedData
        }
        HttpURLConnection urlConnection = null;
        InputStream inputStream = null;
        try {
            //  2-   Obtain a URLConnection object from the URL
            //       A URLConnection instance is obtained by invoking the openConnection() method on the URL object:
            //       URLConnection urlCon = url.openConnection();
            //       If the protocol is http://, you can cast the returned object to an HttpURLConnection object:
            HttpURLConnection httpURLConnection = (HttpURLConnection) myURL.openConnection();
            //  3-   Configure the URLConnection
            httpURLConnection.setRequestMethod("GET");
            // Timeout for reading InputStream arbitrarily set to 10000 mili second
            httpURLConnection.setReadTimeout(10000 /* milliseconds */);
            // Timeout for connection.connect() arbitrarily set to 15000 ms
            httpURLConnection.setConnectTimeout(15000 /* milliseconds */);
            // Open communications link (network traffic occurs here).
            httpURLConnection.connect();
            //   After the connection has been established, then its need to check the response code by
            // calling below code
            // if the request " httpURLConnection.connect();" is successful (response code is 200)
            // so we could do 4 & 5 steps(read the input stream and then parse the response
            if(httpURLConnection.getResponseCode()==200){
                //  4-   Read the header fields  ::::  Not used Here
                //  5-   Get an input stream and read data
                inputStream = httpURLConnection.getInputStream();
                // The InputStream’s read() is a low-level method that reads data to an array of bytes.
                // So it is more convenient to wrap the InputStream in an InputStreamReader for reading data to characters;
                // Here we use  readFromStream method to read data
                //An InputStream is a readable source of bytes. Once you get an InputStream, it's common
                // to decode or convert it into a target data type. For example, if you were downloading
                // image data, you might decode and display it
                jsonResponse = readFromInputStream(inputStream);// maybe "inputStream", be null becuase "httpURLConnection" method maybe
                // return null string, so need to check handling null string url in the method
            }else{
                Log.e(LOG_TAG,"Error response code: "+urlConnection.getResponseCode());
            }
        } catch (IOException e) {
            Log.e(LOG_TAG,"Problem to making HttpURLConnection httpURLConnection = " +
                    "(HttpURLConnection) myURL.openConnection();",e);
//                e.printStackTrace();
        }finally {
            if (inputStream != null) {//// Close Stream and disconnect HTTPS connection.
                // function must handle java.io.IOException here
                inputStream.close();
            }
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
        }
        return jsonResponse;
    }// End httpConectionReadStreamedData  method
    //  After read data from url(streamming data), its need to form data to readable String data
    // The InputStream’s read() is a low-level method that reads stream data to an array of bytes.
    //An InputStream is a readable source of bytes. Once you get an InputStream, it's common
    // to decode or convert it into a target data type. For example, if you were downloading
    // image data, you might decode and display it
    private static String readFromInputStream(InputStream inputStream) throws IOException {// this exception is due to   bufferedReader.readLine();
        StringBuilder stringBuilder = new StringBuilder();// to concatinate streams of char data
        if(inputStream!=null){
            // for read streams of byte char data from inputstream url
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
            // To increase performance. Data to be read will be buffered in to memory for quick access
            // for more info :   http://www.javalearningacademy.com/streams-in-java-concepts-and-usage/
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            String line = bufferedReader.readLine();// read data from buffer
            while(line!=null){  // while there is data, line of data appent to each other
                stringBuilder.append(line);
                line = bufferedReader.readLine();
            }
        }
        return  stringBuilder.toString();
    }
    /**
     * Return an {@link CustomWord} object by parsing out information
     * about the first earthquake from the input earthquakeJSON string.
     */
    private static ArrayList QueryFromJAson(String jasonInputString){
//            final ArrayList<CustomWord> customArrayList = nnull;
        // if we define line below as above   we get error
        final ArrayList<CustomWord> customArrayList = new ArrayList<>();
        // If the JSON string is empty or null, then return early.
        if (TextUtils.isEmpty(jasonInputString)) {
            return null;
        }
        // use try/catch to pass out from class if there is a error
        try {
            JSONObject root = new JSONObject(jasonInputString);
            // Get "features" path to get next path and route to place,time,magnitude,...,etc
            JSONArray root_features = root.getJSONArray("features");
            // Create Custom list array to add "mag,place,time,url

            for (int root_features_Elements_counter=0;root_features_Elements_counter<root_features.length();
                 root_features_Elements_counter++){
                JSONObject root_features_Elements = root_features.getJSONObject(root_features_Elements_counter);
                JSONObject root_features_Elements_properties = root_features_Elements.getJSONObject("properties");
                double magnitude = root_features_Elements_properties.getDouble("mag");
                String place = root_features_Elements_properties.getString("place");
                long time = root_features_Elements_properties.getLong("time");
                String url = root_features_Elements_properties.getString("url");
                // Add "mag,place,time,url to CustomArrayList
                customArrayList.add(new CustomWord(magnitude,place,time,url));
            }//End for

        } catch (JSONException e) {
            e.printStackTrace();
            Log.e(LOG_TAG, "Problem parsing the earthquake JSON results", e);
        }
        return customArrayList;
    }

}// End Class  FetchDataFromInteret

另一个:

QueryFromJAson :



package com.example.earthquake6;

import android.util.Log;

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

import java.util.ArrayList;

import static com.example.earthquake6.FetchDataFromInternet.LOG_TAG;

//import static com.example.earthquakerev4_staticclass.MainActivity.LOG_TAG;


public class QueryFromJAson {
    // States
private ArrayList<CustomWord> customArrayList = new ArrayList<>();
    // Constructor
    public QueryFromJAson(String jasonInputString){
 /*       // If the JSON string is empty or null, then return early.
        if (TextUtils.isEmpty(jasonInputString)) {
            return null;
        }*/
        // use try/catch to pass out from class if there is a error
        try {
            JSONObject root = new JSONObject(jasonInputString);
            // Get "features" path to get next path and route to place,time,magnitude,...,etc
            JSONArray root_features = root.getJSONArray("features");
            // Create Custom list array to add "mag,place,time,url

            for (int root_features_Elements_counter=0;root_features_Elements_counter<root_features.length();
                 root_features_Elements_counter++){
                JSONObject root_features_Elements = root_features.getJSONObject(root_features_Elements_counter);
                JSONObject root_features_Elements_properties = root_features_Elements.getJSONObject("properties");
                double magnitude = root_features_Elements_properties.getDouble("mag");
                String place = root_features_Elements_properties.getString("place");
                long time = root_features_Elements_properties.getLong("time");
                String url = root_features_Elements_properties.getString("url");
                // Add "mag,place,time,url to CustomArrayList
                customArrayList.add(new CustomWord(magnitude,place,time,url));
            }//End for

        } catch (JSONException e) {
            e.printStackTrace();
            Log.e(LOG_TAG, "Problem parsing the earthquake JSON results", e);
        }

    }// End Constructor

    public ArrayList<CustomWord> getCustomArrayList() {
        return customArrayList;
    }
} // End Class

我更喜欢使用 lbrary androidx 编写代码,而不是像 import android.support.v4 这样的支持库。运行此应用程序后,屏幕没有显示。

标签: androidarraylistloader

解决方案


经过 3 天的工作和谷歌搜索后,我从以下网站找到了一些提示:

https://stackoverflow.com/questions/51408098/what-is-the-appropriate-replacement-of-deprecated-getsupportloadermanager

所以我在“MainActivity.java”类文件中使用下面的代码:

 androidx.loader.app.LoaderManager loaderManager = null;
 loaderManager.getInstance(this).initLoader(EARTHQUAKE_LOADER_ID,null,this);

没有什么需要改变了。这些代码基于“androidx”库。顺便说一下在“MainActivity.java”中它需要使用“LoaderManager.LoaderCallbacks” select from “import androidx.loader.app.LoaderManager;” 不是从导入“import android.app.LoaderManager.LoaderCallbacks;”

public  class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<ArrayList<CustomWord>> {
.
codes
.
}

推荐阅读