Элементы кликабельны, но невидимы на экране: загружаются через AsyncTaskLoader - PullRequest
0 голосов
/ 14 января 2019

Я храню список наиболее часто используемых транзитных линий в контент-провайдере и адаптере RecyclerView, которые будут доступны для просмотра онлайн и офлайн. Они загружаются в активность через AsyncTaskLoader. Они доступны из пункта меню в упражнении ниже. Я отладил, и это показывает, что элементы добавляются к поставщику контента в другом действии. Затем, когда я нажимаю «наиболее часто посещаемые» в пункте меню, на экране ничего не отображается, но элементы доступны для нажатия (как в автономном режиме, так и в автономном режиме). Я пытался отладить, но он не показывает никаких ошибок.

Я нашел похожую тему: Элементы RecyclerView кликабельны, но невидимы

В моем случае все шрифты и цвета правильные. Я знаю, что загрузчик устарел начиная с SDK 28. Однако он не работает даже в 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();
        }
    }
...