I have used listview with entries attribute like below :
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:entries="#array/fi"/>
Now i am converting it to RecyclerView
<android.support.v7.widget.RecyclerView
android:id="#+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
I want to know whether we have android:entries attribute in RecyclerView? Or any other attribute instead of entries?
As correctly explained in the other answers there isn't an attribute to fill the RecyclerView from xml. However using the Android Databinding you can create a similar attribute quite easily:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:entries="#{#stringArray/fi}"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"/>
</layout>
Here the binding adapter definition:
import android.databinding.BindingAdapter;
public class RecyclerViewBindings {
#BindingAdapter("entries")
public static void entries(RecyclerView recyclerView, String[] array) {
recyclerView.setAdapter(new SimpleArrayAdapter(array));
}
static class SimpleArrayAdapter extends RecyclerView.Adapter<SimpleHolder> {
private final String[] mArray;
public SimpleArrayAdapter(String[] array) {
mArray = array;
}
#Override
public SimpleHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
final View view = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
return new SimpleHolder(view);
}
#Override
public void onBindViewHolder(SimpleHolder holder, int position) {
holder.mTextView.setText(mArray[position]);
}
#Override
public int getItemCount() {
return mArray.length;
}
}
static class SimpleHolder extends RecyclerView.ViewHolder {
private final TextView mTextView;
public SimpleHolder(View itemView) {
super(itemView);
mTextView = (TextView) itemView.findViewById(android.R.id.text1);
}
}
}
Then you have to use the DataBindingUtil methods for inflate the layout.
Inflate inside an Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DataBindingUtil.setContentView(this, R.layout.content_main);
}
Inflate inside a Fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ContentMainBinding bindings = DataBindingUtil.inflate(inflater, R.layout.content_main, container, false);
return bindings.getRoot();
}
No. There is no such directly available attribute in RecyclerView. You have to do it from java code programatically using LayoutManager and RecyclerView.Adapter. Refer this answer.
REASON:
As we know, RecyclerView won't inflate until we set a LayoutManager to it. Also, LayoutManager is necessary to inflate individual item views of RecyclerView. These individual item views are retrieved from the RecyclerView.Adapter. So, until you set both the LayoutManager and RecyclerView.Adapter to RecyclerView, you can't use RecyclerView.
I hope this answer helps you.
I'm afraid this is not possible out of the box, you can extend the RecyclerView and define your own custom attribute which accepts a string array, then you would populate your RecyclerView Adapter with these values.
Check this link:
http://developer.android.com/training/custom-views/create-view.html#customattr
No,In android, Recyclerview doesn't hold android:entries or like attributes.
RecyclerView is successor of listview but still missing entries attribute and onclicklistener
here is android official documentation link
https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html
This site also describes about the android:entries attribute.
http://androidride.com/easiest-way-make-listview-android/
Related
i have lots of adapters and views, viewsmodels and so on. Since its hard to maintain those i would like to use databinding and mvvm for that case. Now i tried to forward the item clicks into the viewmodel. Since its a recycleview i would lovely not loose the functionality to have less memory usage.
Currently i have a view (Activity) which sets the ViewModel. The ViewModel itself has an Adapter. The adapter has a Constructor which receives the viewModel and set this into the item.
The Item uses this to send the events back to the ViewModel. How does it affect the memory? Is there a better way doing this? I used RXJava before but this looks like the same concept, doesnt it? Here's my sample code (truncated).
View
public class ScenesFragment extends BaseFragment implements Observer {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
this.scenesFragmentBinding = DataBindingUtil.inflate(inflater, R.layout.scenes_fragment, container, false);
this.scenesListViewModel = new ScenesListViewModel(getContext());
this.scenesFragmentBinding.setViewModel(this.scenesListViewModel);
View view = this.scenesFragmentBinding.getRoot();
return view;
}
}
BaseLayout
<layout ... >
<data><variable name="viewModel" type=".viewmodel.ScenesListViewModel"/></data>
<android.support.v7.widget.RecyclerView
app:adapter="#{viewModel.adapter}"
app:layoutManager="#{viewModel.layoutManager}" />
</layout>
ViewModel
public class ScenesListViewModel extends Observable implements IViewModel {
public final SceneAdapter adapter;
private List<Scene> scenes = new ArrayList<>();
public ScenesListViewModel(#NonNull Context context) {
this.adapter = new SceneAdapter(context, scenes, this);
}
public void onRemoveClick(Scene scene) {
Timber.d("Clicked remove in the scene:" + scene);
}
}
Item Layout
<layout>
<data>
<variable name="scene"type=".model.Scene"/>
<variable name="viewModel" type=".viewmodel.ScenesListViewModel"/>
</data>
<ImageButton
android:id="#+id/sceneDelete"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_margin="15dp"
android:layout_weight="1"
android:background="#null"
android:onClick="#{() -> viewModel.onRemoveClick(scene)}"
android:src="#drawable/ic_delete_forever_white_48px"/>
</LinearLayout>
</layout>
and finally the adapter which set the viewModel into the item.
Adapter
public class SceneAdapter extends RecyclerView.Adapter<SceneAdapter.BindingHolder> {
private Context context;
private List<Scene> scenes;
private ScenesListViewModel scenesListViewModel;
public SceneAdapter(Context context, List<Scene> list, ScenesListViewModel scenesListViewModel) {
this.context = context;
this.scenes = list;
this.scenesListViewModel = scenesListViewModel;
}
#Override public void onBindViewHolder(SceneAdapter.BindingHolder holder, int position) {
final Scene scene = scenes.get(position);
holder.binding.setScene(scene);
holder.binding.setViewModel(scenesListViewModel);
holder.binding.executePendingBindings();
}
Another way doing it is to set a Listener in the ViewModel, but this is more likely mvp then mvvm. I could also use RXJava again and create a Subject within the adapter, but i would like to solve it with the android on-board tools.
in your BindingHolder subclass implement onClickListener
class BindingHolder extends RecyclerView.ViewHolder
implements OnClickListener {
// code code code
}
#Override
public void onClick(View v) {
//code code code, use getAdapterPosition() to get the... adapter position
}
}
You can get the same ViewModel in the ViewHolder by using "by activityViewModels".
I am just an Android beginner & trying to work out RecyclerView with ViewHolder pattern
with the sample at : https://guides.codepath.com/android/using-the-recyclerview#create-the-recyclerview-within-layout
While implementing the code:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v7.widget.RecyclerView
android:id="#+id/rvContacts"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
it is asked to implement in res/layout/activity_users.xml
I have created the project with Basic Activity & has the files
activity_main.xml & content_main.xml
Is activity_users.xml another custom file? or a default file?
Can you tell me where it is supposed to implement the above code?
Once you defined your RecyclerView you have to define the single row layout.
Then, you reference it in your adapter. Something like it:
public class ContactAdapter extends
RecyclerView.Adapter<ContactAdapter.ContactViewHolder> {
private List<ContactInfo> contactList; // your item list
public ContactAdapter(List<ContactInfo> contactList) {
this.contactList = contactList;
}
#Override
public int getItemCount() {
return contactList.size();
}
#Override
public void onBindViewHolder(ContactViewHolder contactViewHolder, int i) {
// binding
}
#Override
public ContactViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.from(viewGroup.getContext()).
inflate(**your_row_layout**, viewGroup, false);
return new ContactViewHolder(itemView);
}
public static class ContactViewHolder extends RecyclerView.ViewHolder {
...
}
}
Hope it helps you.
You can read at here. i see it is so clear.
http://www.androidhive.info/2016/01/android-working-with-recycler-view/
Thanks.
You can add the recycler view in the content_main layout. Or if you dont want to complicate, remove the reference for content_main in your activity_main and add the recycler view in in the activity_main itself.
Use activity_main in your BaseActivity.
I have created a basic app using RecyclerView and CardView from get tutorials from websites.
App is working fine and I have some confusion.(I am showing my whole code here)
confusion is that how code works step by step. So please clear my concept on it.
Basic Structure of my App :
I have created a row_data_layout xml file to bind on recycler_view.
Created an Data class file (Here I have defined my variable that I used in App).
Created an Adapter file (here I want to clear how it works step by step first which class gets called and why?).
Bind Data to RecyclerView on MainActivity file.
row_data_layout.xml file:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/CardView"
android:paddingBottom="16dp"
android:layout_marginBottom="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/txt_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
</android.support.v7.widget.CardView>
Data Class File:
public class Data {
public String Name;
Data(String Name)
{
this.Name=Name;
}
}
Data_Adapter Class file:
public class Data_Adapter extends RecyclerView.Adapter<Data_Adapter.View_holder> {
List<Data> list = Collections.emptyList();
Context context;
public Data_Adapter(List<Data> list, Context context) {
this.list = list;
this.context = context;
}
#Override
public Data_Adapter.View_holder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_data_layout,parent,false);
View_holder holder=new View_holder(v);
return holder;
}
#Override
public void onBindViewHolder(Data_Adapter.View_holder holder, int position) {
holder.name.setText(list.get(position).Name);
}
#Override
public int getItemCount() {
return list.size();
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
public class View_holder extends RecyclerView.ViewHolder{
CardView cv;
TextView name;
public View_holder(View itemView) {
super(itemView);
cv = (CardView) itemView.findViewById(R.id.CardView);
name = (TextView) itemView.findViewById(R.id.txt_name);
}
}
}
MainActivity File:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<Data> data = fill_data();
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
Data_Adapter adapter = new Data_Adapter(data,getApplicationContext());
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
public List<Data> fill_data()
{
List<Data> data = new ArrayList<>();
data.add(new Data("Bred Pit"));
data.add(new Data("Leonardo"));
return data;
}
}
Once you have a basic understanding of how a RecyclerView.Adapter works, it would make sense to take a deeper dive into the documentation.
What the adapter does is keep a pool of inflated views (this can be as many different types of ViewHolder as you would like) that it populates with the data you supply. When the adapter does not have an empty view in the pool it creates a new one.
When a view is attached to the RecyclerView, it is removed from the pool, and when it is detached (scrolls beyond view, to some distance), it is added back to the pool of empty views--this is why it is important to reset everything when you populate your ViewHolders.
The onCreateViewHolder() function is where a new, empty view (wrapped by a RecyclerView.ViewHolder) is created and added to the pool.
The onBindViewHolder() function gets a view from the empty pool and populates this view using the data you supplied to the adapter.\
You can use the onViewRecycled() method to perform specific actions like setting an ImageView's bitmap to null (on detach) in order to reduce memory usage.
I don't normally override onAttachedToRecyclerView(), but if you need to do something specific when your adapter is associated with the RecyclerView, you would do it here.
Is it possible to change the "style" of a list view once it's displayed? What I want to do is to start with a list view using simple_list_item_1 but switch to simple_list_item_multiple_choice after the list has been populated.
If this isn't possible, can someone please show me how to populate a list view with a text view and checkbox as I'm finding this very difficult to understand.
As always, thanks in advance.
if the two view "simple_list_item_multiple_choice" and "simple_list_item_1" are just different based on the checkbox, then you can just use the "simple_list_item_multiple_choice" where you can make the checkbox hidden on very startup and when the data is loaded you can make the checkbox visible. Or you can show a activity-indicator when the data is loading and after loading the data you can directly port the custom ListView, think this one is better. Some sample code is provided with explanation.
First of all a custom adapter for the listView. This adapter is for each item of the ListView.
//Custom Adapter
private class DataAdapter extends BaseAdapter {
#Override
public int getCount() {
if (channelListTitles.size()>0){
return dataArrayList.size(); //dataArrayList is a ArrayList<String>
}
else {
return 0;
}
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView==null){
convertView = getActivity().getLayoutInflater().inflate(R.layout.item_view,null); //item_view is the custom view for the items of the ListView
}
if (convertView != null) {
((TextView)convertView.findViewById(R.id.item_view_title)).setText(channelListTitles.get(position)); //item_view_title is the TextView
if(isDataLoaded){ //isDataLoaded is a bool value to indicate if data is loaded
CheckBox checkBox = (CheckBox)convertView.findViewById(R.id.checkbox);
checkBox.setVisibility(View.VISIBLE);
}
}
return convertView;
}
}
Now the item_view for each list-item:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/checkbox"
android:visibility="invisible"/>
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="#+id/item_view_title"
android:layout_gravity="center_vertical"/>
</LinearLayout>
Now finally declare a listView on which the upper custom view will be ported. Posting the whole code of the OnCreateView() for better understanding. Here I am using Fragment, you need to change the corresponding methods if you are using Activity:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
if (rootView != null) {
ListView listView = (ListView) rootView.findViewById(R.id.item_list);
DataAdapter itemDataAdapter = new DataAdapter();
listView.setAdapter(itemDataAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// OnItemClickListener goes here
}
});
}
return rootView;
}
Now the fragment_main:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity$PlaceholderFragment">
<ListView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="#+id/item_list"/>
</RelativeLayout>
The Adapter is an important factor when you want to load data on dynamically. Basically Adapter is the bridge between data and view. Once you have the data you can call the adapter to update the view by using itemDataAdapter.notifyDataSetChanged();.
Yes you can do that, You need to make a xml for the row. And make an adapter class and overwrite getView() and inflate the view here. I always extend BaseAdapter.
# adelphia, i thing you want to use custom listview. Follow this tutorials for custom list view (follow 72 - 84 tutorials).
I've searched through a lot of other answer for the same problem, but didn't found any solution that works for me. The problem, as the title says, is that the getView method from my custom adapter doesn't get called.
Here's the code (first the fragment):
public class CategoryListFragment extends ListFragment
implements NewCategoryDialogListener {
private GestoreAttivitaDbHelper mDbHelper;
private CategoryListAdapter mAdapter;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
mAdapter = new CategoryListAdapter(getActivity());
setListAdapter(mAdapter);
CategoryLoader categoryLoader = new CategoryLoader();
if (mDbHelper == null) {
mDbHelper = new GestoreAttivitaDbHelper(getActivity().getApplicationContext());
}
SQLiteDatabase db = mDbHelper.getReadableDatabase();
mAdapter.addAll(categoryLoader.getAllCategories(db));
mAdapter.notifyDataSetChanged();
mAdapter.getCount();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.category_list, container);
}
Here's the adapter:
public class CategoryListAdapter extends ArrayAdapter<CategoryElement> {
private LayoutInflater mInflater;
public CategoryListAdapter(Context ctx) {
super(ctx, R.layout.category_element);
mInflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
Log.d("Adapter", "Restituisco la view per l'elemento");
if (convertView == null) {
view = mInflater.inflate(R.layout.category_element, null);
} else {
view = convertView;
}
//((TextView) view.findViewById(R.id.category_element_text)).setText(getItem(position).getName());
TextView textView = (TextView) view.findViewById(R.id.category_element_text);
textView.setText(getItem(position).getName());
return view;
}
}
And here's my two layout files:
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/category_list"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
and:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/category_element"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/category_element_text"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
</LinearLayout>
I thought that setting the adapter in the onCreate could be a problem, since it is called before onCreateView, and at that time the fragment isn't already associated with the ListView. So I moved the code from the onCreate to the onStart method, but nothing changed.
Also, the getCount() correctly returns me 6, the precise number of element red from the database.
Any help would be really appreciated!!
Thanks.
Edit:
Solved!
Problem was in the activity, I had the following code:
fragmentTransaction.add(0, categoryListFragment);
that I changed in
fragmentTransaction.add(R.id.activity_main, categoryListFragment);
Without specifying the View id to which the fragment should be attached it never draws it!
In addition, I had to change from this
view = mInflater.inflate(R.layout.category_element, parent);
to this:
view = mInflater.inflate(R.layout.category_element, null);
in the getView method.
PS. I'm editing this cause I can't answer my own question until 8 hours have passed..
I think in your R.layout.category_list file you need to give the ListView the following attribute:
android:id="#android:id/list"
ListFragment (and ListActivity) look for this id to find the ListView when you call methods like setListAdapter().
Also, if all you want is a ListView, you don't have to supply a layout file. Simply do not override onCreateView() and the system will provide a ListView for you automatically. Only if you want a custom layout do you need to inflate one, and if you do, the ListView should have the id stated above.