-
Notifications
You must be signed in to change notification settings - Fork 1
Android Recycler View
See also my Wiki notes from Java-d6 Lecture, from October and Nov 2019.
The following are notes created while working on GFTastyNoms in March, 2020
Extremely common thing to put in an Android App
For when you have many individual rows, versus a block of text (which is ScrollView).
You can set it up to show, say, 12 things, in the recycler view. Then, when the user reaches near the bottom, you make an API call or a DB call to fetch the next 12 things in the data set.
The View Adapter has the job of telling the Recycler View what to display at each row.
The View Adapter needs to know these things, at each index i, to determine what that row's view should look like:
- The contents/data at each index
- The total length
- How to create a single row.
Like in Spring and Thymeleaf, they are for small pieces of UI that you want to reuse in various activities. In android, you can have Java files backing those bits of logic.
This example uses my work from the Android App I'm working on called GFTastyNoms. The Recycler View displays each location. Each location is whimsically named a GFTastyNomPlace, and so there is a class called GFTastyNomPlace.java, which has all the expected instance variables, such as name, address, etc.
Drag a RecyclerView from the Palette over to the screen of the xml file you want it on. Let it add dependencies and sync, if you haven't done that manually already.
Add constraints to the RecyclerView on all four sides of 16dps. In Attributes, give it a layout_height of match_constraint, which makes it as tall as it needs to be to be between whatever you'd like it to be between.
This recycler view does nothing at this point. Next, must set up view adapter and follow the docs.
Open up the Recycler View docs
In the project directory, next to your other classes (like Main Activity), make a new Fragment (List).
- When prompted - fill in "Object Kind," (ie, GFNomsPlaces) then click
finish. - It will generate many files, including two classes.
Note that this RecyclerViewAdapter is trying to identify what is the list of objects to display. We need to create brand new rows in the RecyclerView, which is what the onCreateViewHolder is doing.
Change the instance value of a List called mValues to take in an object of your choice (ie, GFTastyNomPlace), instead of DummyItem.
GFTastyNomPlace will be red; do an option-return (on a mac) and Create class.
Continue going through RecyclerViewAdapter and replacing DummyItem with GFTastyNomPlace.
Make instance variables and a constructor, and generate getters and setters.
In the component tree, there are two things - item_number and content.
Highlight item_number, and in Attributes, change the id of item_number to nomPlaceName.
- Change instance variables for TextViews from mIDView and mContentView to something more applicable... like mNomPlaceNameView and mAddressView. This is for mental sanity.
- Change R.id.___ to appropriate id values for what's in the xml file.
- Change the angry .id to .getNomplacename, which comes from the getter in GFTastyNomPlace class.
- Change the angry .content to .getAddress(), also from the GFTastyNomPlace class.
- Delete the content within the onClick(View v) and just add a Log.i to check if it was clicked.
Delete the recycler view from the view, and drag in a . Click on the fragment name that appears in the box, and hit OK.
- Remember to, in Declared Attribures, to put "layout_height" and "layout_width" as
match_constraint.
On the upper right, there will be a bright red exclamation mark warning symbol. It'll say something like "unknown fragments." It'll provide an option to choose what xml fragment to use with the recycler view.
At about line 74, within the public View onCreateView(...), there will be a squiggly red line under "DummyContent.ITEMS...)
- It's actually trying to create the view adapter (to display things within the recycler view). It's currently passing in stuff from Dummy Content, to populate the recycler view.
- Replace DummyContent.ITEMS with
listOfGFTastyNomPlaces, and one line above, make a new list.
List<GFTastyNomPlace> listOfGFTastyNomPlaces = new LinkedList<>();
Add a GFTastyNomPlace to the list.
listOfGFTastyNomPlaces.add(newGFTastyNomPlace(...));
Plus, change listener at the end of the recyclerView.setAdapter(new MyGFNomPlacesREcyclerViewAdapter(listOfGFTastyNomPlaces, ____ )); to null.
comment out the two lines that start with "throw new RuntimeException(...)..."
Cross your fingers... it should show content inside the recycler view...
This is where we define the individual views.
Drag and drop a TextView from the Palette into the Component Tree under Linear Layout. Give it a reasonable ID, and remove the "TextView" that is in the "text" within Declared Attributes.
public final TextView mGFFriendlyRange;
Within public ViewHolder(View view) {} grab the id for the data we want to add to the recycler view:
mGFFriendlyRange = (TextView) view.findViewById(R.id.gfFriendlyRange);
When filling in a particular row of the recycler view with data, we have to make sure to set the text of the desired view.
holder.mGFFriendlyRange.setText(mValues.get(position).getGffriendlyrange());
You may need to go to the fragment_gfnomplaces.xml and adjust the Attributes and Layout and such to match the first two components, if the new textview content is floating and light grey....
Go to my Wiki on setting up an API and DynamoDB with AWS if this hasn't been done yet.
Amplify docs discuss how to query](https://aws-amplify.github.io/docs/sdk/android/start) the data - do a search for "Next, query the data" to get taken to the right spot in the page.
This is the file that gets the data for displaying.
Add the instance variable for the client within the public class.
private AWSAppSyncClient mAWSAppSyncClient;
Add a .responseFetcher(...) and .enqueue with its callback.
Within the public void onREsponse(...), add:
recyclerView.setAdapter(new MyGFNomPlacesREcyclerVIewAdapter(resopnse.data().listGFTastyNomss().items(), null));
It will have squiggly red lines under the response.data().listGFTa... so do option-return (Mac user), and choose:
Change 1st parameter of method 'MyGFNomPlacesRecyclerViewAdapter' from 'List<GFTastyNomPlace>' to 'List<Item>'
This will give us a list of items.
Need to fix the red squiggly lines that appear in various places due to the change immediately above.
Update the instance variable private final List<GFTastyNomPlace> mValues with:
<ListGfTastyNomssQuery.Item>
In public classViewHolder extends RecyclerView.ViewHolder {}, update the instance variable for mItem to:
public ListGfTastyNomssQuery.Item mItem;
In public void onBindVIewHolder(...) {}, update the .getNomplacename() and .getAddress() with:
...get(position).nomplacename());
...get(position).address();
https://frontrowviews.com/Home/Event/Play/5e1929feeee6d91a1854408c <----------- 02:56:48
By default, AWS can't make network requests on the UI thread, b/c these requests will stop the UI from displaying anything. When we call .enqueue, it is enqueing that request on a separate thread for us; it's handling the work of the threading for us. However, when our callback occurs, that callback isn't running on the UI thread; it's running on a different thread. We need to post that data to the UI thread in a reasonable way... aka handling asynchronous calls.
The part of the code that will break is within public void onResume() {}
recyclerView.setAdapter(new...)
The error...
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
This allows us to query data and send it to the main UI thread.
See Android doc on communicating with the UI thread
Add in a handler within the public void onResponse(@Nonnull Response<...> response {}, just one line above the recyclerView.setAdapter(...).
- Android Docs on Recycler View
- Android Studio Guide
- Wiki notes from Java-d6 Lecture, from October and Nov 2019.
- Javad9 Github repo, class 28 on Feb 12, 2020, lecture on Recycler Views, with demo app repo called Pokeman here
- FrontRow recording of Javad9 cohort's lecture on Feb 12, 2020 on Recycler Views
- Android doc on communicating with the UI thread