我将在内容提供者和RecyclerView适配器中存储最常使用的运输线路的列表,以供联机和脱机查看。它们通过AsyncTaskLoader下载到活动中。可通过以下活动中的菜单选项访问它们。我进行了调试,它显示项目是在另一个活动中添加到内容提供程序的。然后,当我在菜单选项中单击“最常使用”时,屏幕为空白,但项目是可单击的(在线和离线)。我尝试调试,但未显示任何错误。
我发现了一个类似的线程: MulticastSocket
就我而言,所有字体和颜色都是正确的。我知道从sdk 28开始不推荐使用Loader。但是,在27中它甚至无法使用。谢谢。
将数据添加到内容提供者的活动:
public class StationListActivity extends AppCompatActivity implements StationsAdapter.StationsAdapterOnClickHandler, TubeStationAsyncTaskInterface,
LoaderManager.LoaderCallbacks<Cursor>
{
//Tag for the log messages
private static final String TAG = StationListActivity.class.getSimpleName();
@BindView(R.id.recyclerview_station)
RecyclerView mStationRecyclerView;
private StationsAdapter stationsAdapter;
private ArrayList<Stations> stationsArrayList = new ArrayList<>();
private static final String KEY_STATIONS_LIST = "stations_list";
private static final String KEY_LINE_NAME = "line_name";
Lines lines;
public String lineId;
private Context context;
private TextView lineNameStation;
private String lineNameToString;
@BindView(R.id.favorites_button)
Button favoritesButton;
/**
* Identifier for the favorites data loader
*/
private static final int FAVORITES_LOADER = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_station_list);
context = getApplicationContext();
// Bind the views
ButterKnife.bind(this);
stationsAdapter = new StationsAdapter(this, stationsArrayList, context);
mStationRecyclerView.setAdapter(stationsAdapter);
RecyclerView.LayoutManager mStationLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mStationRecyclerView.setLayoutManager(mStationLayoutManager);
lineNameStation = (TextView) findViewById(R.id.line_name_station);
//add to favorites
favoritesButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
ContentValues values = new ContentValues();
values.put(TubeLineContract.TubeLineEntry.COLUMN_LINES_ID, lines.getLineId());
values.put(TubeLineContract.TubeLineEntry.COLUMN_LINES_NAME, lines.getLineName());
Uri uri = getContentResolver().insert(TubeLineContract.TubeLineEntry.CONTENT_URI, values);
if (uri != null)
{
Toast.makeText(getBaseContext(), uri.toString(), Toast.LENGTH_LONG).show();
Toast.makeText(StationListActivity.this, R.string.favorites_added, Toast.LENGTH_SHORT).show();
favoritesButton.setVisibility(View.GONE);
}
}
});
/*
* Starting the asyncTask so that stations load when the activity opens.
*/
if (getIntent() != null && getIntent().getExtras() != null)
{
if (savedInstanceState == null)
{
lines = getIntent().getExtras().getParcelable("Lines");
lineId = lines.getLineId();
TubeStationAsyncTask myStationTask = new TubeStationAsyncTask(this);
myStationTask.execute(lineId);
lineNameStation.setText(lines.getLineName());
} else
{
stationsArrayList = savedInstanceState.getParcelableArrayList(KEY_STATIONS_LIST);
stationsAdapter.setStationsList(stationsArrayList);
}
}
// Kick off the loader
getLoaderManager().initLoader(FAVORITES_LOADER, null, this);
}
@Override
public void returnStationData(ArrayList<Stations> simpleJsonStationData) {
if (null != simpleJsonStationData) {
stationsAdapter = new StationsAdapter(this, simpleJsonStationData, StationListActivity.this);
stationsArrayList = simpleJsonStationData;
mStationRecyclerView.setAdapter(stationsAdapter);
stationsAdapter.setStationsList(stationsArrayList);
}
}
@Override
public void onClick(Stations stations) {
Intent intent = new Intent(StationListActivity.this, StationScheduleActivity.class);
intent.putExtra("Stations", stations);
intent.putExtra("Lines", lines);
startActivity(intent);
}
@Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle bundle)
{
String[] projection = {TubeLineContract.TubeLineEntry._ID, TubeLineContract.TubeLineEntry.COLUMN_LINES_ID,};
String[] selectionArgs = new String[]{lineId};
switch (loaderId)
{
case FAVORITES_LOADER:
return new CursorLoader(this, // Parent activity context
TubeLineContract.TubeLineEntry.CONTENT_URI, // Provider content URI to query
projection, // Columns to include in the resulting Cursor
TubeLineContract.TubeLineEntry.COLUMN_LINES_ID + "=?",
selectionArgs,
null); // Default sort order
default:
throw new RuntimeException("Loader Not Implemented: " + loaderId);
}
}
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor)
{
if ((cursor != null) && (cursor.getCount() > 0))
{
//"Add to Favorites" button is disabled in the StationList Activity when the user clicks on a line stored in Favorites
favoritesButton.setEnabled(false);
}
}
public void onLoaderReset(Loader<Cursor> cursorLoader)
{
}
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putParcelableArrayList(KEY_STATIONS_LIST, stationsArrayList);
super.onSaveInstanceState(outState);
}
}
具有菜单选项的活动:
public class MainActivity extends AppCompatActivity implements LinesAdapter.LinesAdapterOnClickHandler, TubeLineAsyncTaskInterface,
LoaderManager.LoaderCallbacks<Cursor> {
// Tag for logging
private static final String TAG = MainActivity.class.getSimpleName();
@BindView(R.id.recyclerview_main)
RecyclerView mLineRecyclerView;
private LinesAdapter linesAdapter;
private ArrayList<Lines> linesArrayList = new ArrayList<>();
private Context context;
private static final String KEY_LINES_LIST = "lines_list";
CoordinatorLayout mCoordinatorLayout;
@BindView(R.id.pb_loading_indicator)
ProgressBar mLoadingIndicator;
private AdView adView;
private FavoritesAdapter favoritesAdapter;
private static final int FAVORITES_LOADER_ID = 0;
private int mPosition = RecyclerView.NO_POSITION;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = getApplicationContext();
// Bind the views
ButterKnife.bind(this);
mCoordinatorLayout = findViewById(R.id.coordinatorLayout);
favoritesAdapter = new FavoritesAdapter(this, context);
linesAdapter = new LinesAdapter(this, linesArrayList, context);
mLineRecyclerView.setAdapter(linesAdapter);
RecyclerView.LayoutManager mLineLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mLineRecyclerView.setLayoutManager(mLineLayoutManager);
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof LinesAdapter.LinesAdapterViewHolder) return 0;
return super.getSwipeDirs(recyclerView, viewHolder);
}
// Called when a user swipes left or right on a ViewHolder
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
// Here is where you'll implement swipe to delete
//Construct the URI for the item to delete
//[Hint] Use getTag (from the adapter code) to get the id of the swiped item
// Retrieve the id of the task to delete
int id = (int) viewHolder.itemView.getTag();
// Build appropriate uri with String row id appended
String stringId = Integer.toString(id);
Uri uri = TubeLineContract.TubeLineEntry.CONTENT_URI;
uri = uri.buildUpon().appendPath(stringId).build();
// TODO (2) Delete a single row of data using a ContentResolver
int rowsDeleted = getContentResolver().delete(uri, null, null);
Log.v("CatalogActivity", rowsDeleted + " rows deleted from the movie database");
// TODO (3) Restart the loader to re-query for all tasks after a deletion
getSupportLoaderManager().restartLoader(FAVORITES_LOADER_ID, null, MainActivity.this);
}
}).attachToRecyclerView(mLineRecyclerView);
/*
* Starting the asyncTask so that lines load upon launching the app.
*/
if (savedInstanceState == null)
{
if (isNetworkStatusAvailable(this))
{
TubeLineAsyncTask myLineTask = new TubeLineAsyncTask(this);
myLineTask.execute(NetworkUtils.buildLineUrl());
} else {
Snackbar
.make(mCoordinatorLayout, "Please check your internet connection", Snackbar.LENGTH_INDEFINITE)
.setAction("Retry", new MyClickListener())
.show();
}
} else {
linesArrayList = savedInstanceState.getParcelableArrayList(KEY_LINES_LIST);
linesAdapter.setLinesList(linesArrayList);
}
getSupportLoaderManager().initLoader(FAVORITES_LOADER_ID, null, MainActivity.this);
mLineRecyclerView.setAdapter(favoritesAdapter);
}
public class MyClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
// Run the AsyncTask in response to the click
TubeLineAsyncTask myLineTask = new TubeLineAsyncTask(MainActivity.this);
myLineTask.execute();
}
}
@Override
public void returnLineData(ArrayList<Lines> simpleJsonLineData) {
mLoadingIndicator.setVisibility(View.INVISIBLE);
if (null != simpleJsonLineData) {
linesAdapter = new LinesAdapter(this, simpleJsonLineData, MainActivity.this);
linesArrayList = simpleJsonLineData;
mLineRecyclerView.setAdapter(linesAdapter);
linesAdapter.setLinesList(linesArrayList);
} else {
showErrorMessage();
}
}
@Override
public void onClick(Lines lines) {
Intent intent = new Intent(MainActivity.this, StationListActivity.class);
intent.putExtra("Lines", lines);
startActivity(intent);
}
//Display if there is no internet connection
public void showErrorMessage() {
Snackbar
.make(mCoordinatorLayout, "Please check your internet connection", Snackbar.LENGTH_INDEFINITE)
.setAction("Retry", new MyClickListener())
.show();
mLineRecyclerView.setVisibility(View.INVISIBLE);
mLoadingIndicator.setVisibility(View.VISIBLE);
}
public static boolean isNetworkStatusAvailable(Context context) {
ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null &&
activeNetwork.isConnectedOrConnecting();
}
@Override
public Loader<Cursor> onCreateLoader(int id, final Bundle loaderArgs)
{
return new AsyncTaskLoader<Cursor>(this)
{
// Initialize a Cursor, this will hold all the task data
Cursor mFavoritesData = null;
// onStartLoading() is called when a loader first starts loading data
@Override
protected void onStartLoading()
{
if (mFavoritesData != null)
{
// Delivers any previously loaded data immediately
deliverResult(mFavoritesData);
}
else
{
// Force a new load
forceLoad();
}
}
// loadInBackground() performs asynchronous loading of data
@Override
public Cursor loadInBackground()
{
// Will implement to load data
// Query and load all task data in the background; sort by priority
// [Hint] use a try/catch block to catch any errors in loading data
try
{
return getContentResolver().query(TubeLineContract.TubeLineEntry.CONTENT_URI,
null,
null,
null,
TubeLineContract.TubeLineEntry.COLUMN_LINES_ID);
}
catch (Exception e)
{
Log.e(LOG_TAG, "Failed to asynchronously load data.");
e.printStackTrace();
return null;
}
}
// deliverResult sends the result of the load, a Cursor, to the registered listener
public void deliverResult(Cursor data)
{
mFavoritesData = data;
super.deliverResult(data);
}
};
}
/**
* Called when a previously created loader has finished its load.
*
* @param loader The Loader that has finished.
* @param data The data generated by the Loader.
*/
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data)
{
favoritesAdapter.swapCursor(data);
if (mPosition == RecyclerView.NO_POSITION) mPosition = 0;
mLineRecyclerView.smoothScrollToPosition(mPosition);
}
/**
* Called when a previously created loader is being reset, and thus
* making its data unavailable.
* onLoaderReset removes any references this activity had to the loader's data.
*
* @param loader The Loader that is being reset.
*/
@Override
public void onLoaderReset(Loader<Cursor> loader)
{
favoritesAdapter.swapCursor(null);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
/* Use AppCompatActivity's method getMenuInflater to get a handle on the menu inflater */
MenuInflater inflater = getMenuInflater();
/* Use the inflater's inflate method to inflate our menu layout to this menu */
inflater.inflate(R.menu.main, menu);
/* Return true so that the menu is displayed in the Toolbar */
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
TubeLineAsyncTask myLineTask = new TubeLineAsyncTask(this);
switch (item.getItemId())
{
case R.id.most_frequented_favorites:
getSupportLoaderManager().restartLoader(FAVORITES_LOADER_ID, null, MainActivity.this);
favoritesAdapter = new FavoritesAdapter(this, MainActivity.this);
mLineRecyclerView.setAdapter(favoritesAdapter);
return true;
case R.id.line_list:
myLineTask.execute();
return true;
default:
return super.onOptionsItemSelected(item);
}}
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putParcelableArrayList(KEY_LINES_LIST, linesArrayList);
super.onSaveInstanceState(outState);
}
}
RecyclerViewAdapter类:
public class FavoritesAdapter extends RecyclerView.Adapter<FavoritesAdapter.FavoritesAdapterViewHolder>
{
private static final String TAG = FavoritesAdapter.class.getSimpleName();
private Context context;
private Cursor cursor;
private LinesAdapter.LinesAdapterOnClickHandler mClickHandler;
public FavoritesAdapter(LinesAdapter.LinesAdapterOnClickHandler clickHandler, Context context)
{
mClickHandler = clickHandler;
this.context = context;
}
public class FavoritesAdapterViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
@BindView(R.id.line_name)
TextView lineName;
public FavoritesAdapterViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
view.setOnClickListener(this);
}
@Override
public void onClick(View v) {
cursor.moveToPosition(getAdapterPosition());
String lineName = cursor.getString(cursor.getColumnIndexOrThrow(TubeLineContract.TubeLineEntry.COLUMN_LINES_NAME));
String lineId = cursor.getString(cursor.getColumnIndexOrThrow(TubeLineContract.TubeLineEntry.COLUMN_LINES_ID));
Lines line = new Lines(lineName, lineId);
mClickHandler.onClick(line);
}
}
@Override
public void onBindViewHolder(FavoritesAdapter.FavoritesAdapterViewHolder holder, int position)
{
// get to the right location in the cursor
cursor.moveToPosition(position);
// Determine the values of the wanted data
int lineIdIndex = cursor.getColumnIndexOrThrow(TubeLineContract.TubeLineEntry.COLUMN_LINES_ID);
final int id = cursor.getInt(lineIdIndex);
holder.itemView.setTag(id);
}
@Override
public FavoritesAdapter.FavoritesAdapterViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType)
{
Context context = viewGroup.getContext();
int layoutIdForListItem = R.layout.line_list_item;
LayoutInflater inflater = LayoutInflater.from(context);
boolean shouldAttachToParentImmediately = false;
View view = inflater.inflate(layoutIdForListItem, viewGroup, shouldAttachToParentImmediately);
return new FavoritesAdapter.FavoritesAdapterViewHolder(view);
}
public Cursor swapCursor(Cursor c)
{
// check if this cursor is the same as the previous cursor (mCursor)
if (cursor == c)
{
return null; // bc nothing has changed
}
Cursor temp = cursor;
this.cursor = c; // new cursor value assigned
//check if this is a valid cursor, then update the cursor
if (c != null)
{
this.notifyDataSetChanged();
}
return temp;
}
@Override
public int getItemCount()
{
if (null == cursor)
return 0;
return cursor.getCount();
}
}