android - 如何在 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 这样的支持库。运行此应用程序后,屏幕没有显示。
解决方案
经过 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
.
}
推荐阅读
- python - 从 Python 导入 MySQLdb(mysqlclient 模块)会在 Mac OS Catalina 中引发与 openssl 相关的错误
- html - 如何使 blob 具有变化的颜色以及如何使较小的轨道圆圈变成图标?
- asp.net-core - 带有区域和参数的重定向页面
- sql - ORA-01427单行子查询返回多于 1 行
- jenkins - 无法通过 windows 上的本地主机访问 Jenkins
- javascript - 图片未在 Javascript 中显示
- python-3.x - 提高最近邻算法的准确性 - 无监督学习问题
- c++ - 我的头文件应该能够自己编译吗?
- python-3.x - Raspberry Pi Stretch Visual Studio 代码 Python ImportError 无法导入名称
- pycharm - 在 PyCharm 中导航到 def