I've got the following classes:
MatchActivity.java:
public void setDart1(int playerIndex, int points) {
getDart1().set(playerIndex, points);
}
public ArrayList<Integer> getDart1() {
return dart1;
}
public void setDart2(int playerIndex, int points) {
getDart2().set(playerIndex, points);
}
public ArrayList<Integer> getDart2() {
return dart2;
}
public void setDart3(int playerIndex, int points) {
getDart3().set(playerIndex, points);
}
public ArrayList<Integer> getDart3() {
return dart3;
}
MatchActivityPlayerAdapter.java:
package de.tkirchmann.myaveragev3;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.RecyclerView;
import java.io.Serializable;
import java.util.List;
public class MatchActivityPlayerAdapter extends RecyclerView.Adapter<MatchActivityPlayerAdapter.MatchActivityPlayerRowViewHolder> {
private final List<Player> playerList;
private final Match match;
private Context context;
MatchActivityPlayerAdapter(List<Player> playerList, Match match) {
this.playerList = playerList;
this.match = match;
}
#NonNull
#Override
public MatchActivityPlayerAdapter.MatchActivityPlayerRowViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.match_activity_row_layout, parent, false);
return new MatchActivityPlayerRowViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MatchActivityPlayerAdapter.MatchActivityPlayerRowViewHolder holder, int position) {
final Player player = playerList.get(position);
MatchActivity matchActivity = new MatchActivity();
holder.nameTextView.setText(player.getPlayerName());
holder.pointsTextView.setText(matchActivity.getRemainingPoints().get(position));
holder.dart1.setText(matchActivity.getDart1().get(position));
holder.dart2.setText(matchActivity.getDart2().get(position));
holder.dart3.setText(matchActivity.getDart3().get(position));
holder.dartsCombined.setText(matchActivity.getDartsCombined().get(position));
/*holder.averageTextView.setText(matchActivity.getAverage().get(position));*/
}
#Override
public int getItemCount() {
return playerList.size();
}
class MatchActivityPlayerRowViewHolder extends RecyclerView.ViewHolder {
public TextView nameTextView, pointsTextView, averageTextView, dart1, dart2, dart3, dartsCombined;
public MatchActivityPlayerRowViewHolder(View playerRowView) {
super(playerRowView);
final ConstraintLayout playerRowRootLayout = playerRowView.findViewById(R.id.match_player_row_root_layout);
nameTextView = playerRowView.findViewById(R.id.name);
pointsTextView = playerRowView.findViewById(R.id.points);
averageTextView = playerRowView.findViewById(R.id.average);
dart1 = playerRowView.findViewById(R.id.dart1);
dart2 = playerRowView.findViewById(R.id.dart2);
dart3 = playerRowView.findViewById(R.id.dart3);
dartsCombined = playerRowView.findViewById(R.id.last_darts_combined);
}
}
}
In the onBindViewHolder() method in the custom adapter I want to set the texts of my views by getting the values from the lists via getters from my activity. But I am getting a IndexOutOfBoundsException, so I propably don't have a correct reference/context when calling the getters.
How can I get the correct context/reference to my activity?
You can try this:
((YourActivityName) itemView.getContext()).getDart1();
and then so on for other getters. You can use any public method using this.
Related
I want to loop through all CardViews and change the text and color of a TextView within a single CardView item using a button click. The following code seems to produce the desired results but I'm not certain that it's the most effective code or even accurate (index).
CustomAdapter
import android.content.Context;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class CustomAdapter extends RecyclerView.Adapter<CustomViewHolder> {
private Context context;
private List<MyModel> list;
public CustomAdapter(Context context, List<MyModel> list) {
this.context = context;
this.list = list;
}
#NonNull
#Override
public CustomViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new CustomViewHolder(LayoutInflater.from(context).inflate(R.layout.single_items, parent, false));
}
#Override
public void onBindViewHolder(#NonNull CustomViewHolder holder, int position) {
holder.textName.setText(list.get(position).getName());
holder.textAge.setText(String.valueOf(list.get(position).getAge()));
}
#Override
public int getItemCount() {
return list.size();
}
}
CustomViewHolder
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class CustomViewHolder extends RecyclerView.ViewHolder {
public TextView textName, textAge;
public CustomViewHolder(#NonNull View itemView) {
super(itemView);
textName = itemView.findViewById(R.id.textName);
textAge = itemView.findViewById(R.id.textAge);
}
}
MainActivity
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
List<MyModel> myModelList;
CustomAdapter customAdapter;
private Button button1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadData();
}
private void loadData() {
recyclerView = findViewById(R.id.recycler_main);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new GridLayoutManager(this, 1));
myModelList = new ArrayList<>();
myModelList.add(new MyModel("Joe", 21));
myModelList.add(new MyModel("Jane", 26));
myModelList.add(new MyModel("Kyle", 19));
myModelList.add(new MyModel("Scott", 30));
customAdapter = new CustomAdapter(this, myModelList);
recyclerView.setAdapter(customAdapter);
}
public void onClickBtn(View v)
{
String searchString = "Kyle";
for (int x = recyclerView.getChildCount(), i = 0; i < x; ++i) {
RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(recyclerView.getChildAt(i));
TextView txtName = holder.itemView.findViewById(R.id.textName);
if (txtName.getText().toString().equals(searchString.toString())) {
txtName.setText("Found " + txtName.getText().toString());
txtName.setTextColor(Color.GREEN);
customAdapter.notifyItemChanged(x);
}
}
}
}
MyModel
public class MyModel {
String name = "";
int age = 0;
public MyModel(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
It's important that I iterate through the list in button click event. Functionality to be changed later. Really appreciate any advice and feedback. Thanks a lot.
I am creating a document arrangement activity with RecyclerView. I want to arrange the document with drag and drop. It was done by using ItemTouchHelper.Callbackbut after that I can't set the page number after the OnItemMove callback. what should I do?
EDIT: added code snippet
package adapters;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.pdf.PdfRenderer;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import com.mobilix.docscanner.R;
import java.util.ArrayList;
import java.util.Collections;
import helper.ItemTouchHelperAdapter;
import helper.ItemTouchHelperViewHolder;
import helper.OnStartDragListener;
import helper.SimpleItemTouchHelperCallback;
public class PageAjdustAdapter extends RecyclerView.Adapter<PageAjdustAdapter.PageAdjustHolder> implements ItemTouchHelperAdapter, OnStartDragListener {
private final String TAG = getClass().getName();
Context mContext;
ArrayList<PdfPage> pdfPages = new ArrayList<>();
private ItemTouchHelper itemTouchHelper;
public PageAjdustAdapter(Context context, ArrayList<PdfPage> pages) {
this.mContext = context;
pdfPages = pages;
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(this);
itemTouchHelper = new ItemTouchHelper(callback);
itemTouchHelper.attachToRecyclerView(((Activity) context).findViewById(R.id.rcvPageArrange));
}
#NonNull
#Override
public PageAdjustHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.item_page_adajustment, parent, false);
return new PageAdjustHolder(view);
}
#Override
public void onBindViewHolder(#NonNull PageAdjustHolder holder, int position) {
Log.d(TAG, "onBindViewHolder: ");
holder.ivPage.setImageBitmap(pdfPages.get(position).bitmap);
holder.cbPage.setChecked(pdfPages.get(position).isSelected);
holder.tvPageNo.setText(String.valueOf(position + 1));
holder.cbPage.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
pdfPages.get(holder.getAdapterPosition()).isSelected = isChecked;
}
});
holder.ivRotate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int pos = holder.getAdapterPosition();
pdfPages.get(pos).bitmap = Bitmap.createBitmap(//
pdfPages.get(pos).bitmap, 0, 0, pdfPages.get(pos).bitmap.getWidth(),//
pdfPages.get(pos).bitmap.getHeight(), pdfPages.get(pos).matrix, true);//
notifyItemChanged(pos);
}
});
}
#Override
public int getItemCount() {
return pdfPages.size();
}
#Override
public boolean onItemMove(int fromPosition, int toPosition) {
Log.d(TAG, "onItemMove: ->fp " + (fromPosition + 1) + " tp-> " + (toPosition + 1));
Collections.swap(pdfPages, fromPosition, toPosition);
notifyItemMoved(fromPosition, toPosition);
return false;
}
#Override
public void onItemDismiss(int position) {
pdfPages.remove(position);
notifyItemRemoved(position);
}
#Override
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
itemTouchHelper.startDrag(viewHolder);
}
public static class PageAdjustHolder extends RecyclerView.ViewHolder implements
ItemTouchHelperViewHolder {
ImageView ivPage, ivRotate;
CheckBox cbPage;
TextView tvPageNo;
public PageAdjustHolder(#NonNull View itemView) {
super(itemView);
ivPage = itemView.findViewById(R.id.ivPage);
ivRotate = itemView.findViewById(R.id.ivRotate);
cbPage = itemView.findViewById(R.id.cbPage);
tvPageNo = itemView.findViewById(R.id.tvPageNo);
}
#Override
public void onItemSelected() {
}
#Override
public void onItemClear() {
}
}
public static class PdfPage {
PdfRenderer.Page page;
Bitmap bitmap;
boolean isSelected;
Matrix matrix;
int rotate = 0;
public PdfPage(PdfRenderer.Page page, Bitmap bitmap) {
this.page = page;
this.bitmap = bitmap;
matrix = new Matrix();
rotate += 90;
matrix.postRotate(90);//martix work on +=90
}
}
}
You have to call notifyDataSetChanged() when an item position is changed. The easiest way it to used onItemClear(), it will be called when an item is de-selected. Add it like following.
#Override
public void onItemClear() {
notifyDataSetChanged();
}
One thing you have to add is check weather the position is actually changed after the drag operation or not other wise it will always update the whole dataset whenever an item is selected and than de-selected.
Edit
Create a local variable in view-holder class. Than you just have to set it in onItemSelected() and check it in onItemClear();
#Override
public void onItemSelected() {
lastpos = getAdapterPosition();
}
#Override
public void onItemClear() {
if(lastpos != getAdapterPosition())
notifyDataSetChanged();
}
So I've made a demo app to demonstrate my problem and have some pictures for my expected outcome. I'm using Room to create a database and a user is able to add an entry by pressing a button. There are only two fields: the id (primary key) and the row number. I set the row number by getting the number of entries through a query and adding one to that value. I then insert a new entry with the constructor requiring a row number.
I've added an option to where a user can swipe right to delete an entry, but I can't figure out how to update the row number and to change the row number displayed in the textview to be the proper row number. Here are some screenshots which might make what I'm asking easier to understand as I'm still pretty new.
I added 10 rows in the first picture, removed some rows in the second, and the third shows what I want the output to be, minus the paint writing:
Here is the code:
MainActivity.Java
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private TestViewModel testViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button addButton = findViewById(R.id.test_button);
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayout.VERTICAL));
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
final TestAdapter adapter = new TestAdapter();
recyclerView.setAdapter(adapter);
testViewModel = ViewModelProviders.of(this).get(TestViewModel.class);
testViewModel.getAllTests().observe(this, new Observer<List<Test>>() {
#Override
public void onChanged(List<Test> tests) {
adapter.submitList(tests);
}
});
testViewModel.getNumberOfEntries().observe(this, new Observer<Integer>() {
#Override
public void onChanged(Integer integer) {
}
});
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0,
ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
testViewModel.delete(adapter.getTestAt(viewHolder.getAdapterPosition()));
}
}).attachToRecyclerView(recyclerView);
addButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (testViewModel.getNumberOfEntries().getValue() != null) {
int rowNum = testViewModel.getNumberOfEntries().getValue() + 1;
testViewModel.insert(new Test(rowNum));
}else{
int rowNum = 1;
testViewModel.insert(new Test(rowNum));
}
}
});
}
}
Test.Java
import androidx.room.Entity;
import androidx.room.PrimaryKey;
#Entity(tableName = "test_table")
public class Test {
#PrimaryKey(autoGenerate = true)
private int id;
private int rowNumber;
public Test(int rowNumber){
this.rowNumber = rowNumber;
}
public int getId() {
return id;
}
public int getRowNumber() {
return rowNumber;
}
public void setId(int id) {
this.id = id;
}
}
TestAdapter.Java
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class TestAdapter extends ListAdapter <Test, TestAdapter.TestHolder> {
protected TestAdapter() { super(DIFF_CALLBACK); }
private static final DiffUtil.ItemCallback<Test> DIFF_CALLBACK = new DiffUtil.ItemCallback<Test>() {
#Override
public boolean areItemsTheSame(#NonNull Test oldItem, #NonNull Test newItem) {
return newItem.getId() == oldItem.getId();
}
#Override
public boolean areContentsTheSame(#NonNull Test oldItem, #NonNull Test newItem) {
return newItem.getRowNumber() == oldItem.getRowNumber();
}
};
#NonNull
#Override
public TestHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.test_item, parent, false);
return new TestHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull TestAdapter.TestHolder holder, int position) {
Test currentTest = getItem(position);
holder.textViewRowNumber.setText(String.valueOf(currentTest.getRowNumber()));
}
public Test getTestAt(int position){ return getItem(position);}
class TestHolder extends RecyclerView.ViewHolder{
private TextView textViewRowNumber;
public TestHolder(View itemView){
super(itemView);
textViewRowNumber = itemView.findViewById(R.id.test_text_view);
}
}
}
TestDao.Java
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import java.util.List;
#Dao
public interface TestDao {
#Insert
void insert(Test test);
#Delete
void delete(Test test);
#Query("SELECT * FROM test_table")
LiveData<List<Test>> getAllEntries();
#Query("SELECT Count(*) FROM test_table")
LiveData<Integer>getNumberOfEntries();
}
TestDatabase.Java
import android.content.Context;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
#Database(entities = Test.class, version = 1)
public abstract class TestDatabase extends RoomDatabase {
private static TestDatabase instance;
public abstract TestDao testDao();
public static synchronized TestDatabase getInstance(Context context){
if(instance == null){
instance = Room.databaseBuilder(context.getApplicationContext(),
TestDatabase.class, "test_database")
.fallbackToDestructiveMigration()
.build();
}
return instance;
}
}
TestRepository.Java
import android.app.Application;
import android.os.AsyncTask;
import androidx.lifecycle.LiveData;
import java.util.List;
public class TestRepository {
private TestDao testDao;
private LiveData<List<Test>> allTests;
private LiveData<Integer> numberOfEntries;
public TestRepository(Application application) {
TestDatabase database = TestDatabase.getInstance(application);
testDao = database.testDao();
allTests = testDao.getAllEntries();
numberOfEntries = testDao.getNumberOfEntries();
}
public void insert(Test test) {
new InsertTestAsyncTask(testDao).execute(test);
}
public void delete(Test test) {
new DeleteTestAsyncTask(testDao).execute(test);
}
public LiveData<Integer> getNumberOfEntries() {
return numberOfEntries;
}
public LiveData<List<Test>> getAllTests() {
return allTests;
}
private static class InsertTestAsyncTask extends AsyncTask<Test, Void, Void> {
private TestDao testDao;
private InsertTestAsyncTask(TestDao testDao) {
this.testDao = testDao;
}
#Override
protected Void doInBackground(Test... tests) {
testDao.insert(tests[0]);
return null;
}
}
private static class DeleteTestAsyncTask extends AsyncTask<Test, Void, Void> {
private TestDao testDao;
private DeleteTestAsyncTask(TestDao testDao) {
this.testDao = testDao;
}
#Override
protected Void doInBackground(Test... tests) {
testDao.delete(tests[0]);
return null;
}
}
}
TestViewModel.Java
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import java.util.List;
public class TestViewModel extends AndroidViewModel {
private TestRepository repository;
private LiveData<Integer> numberOfEntries;
private LiveData<List<Test>> allTests;
public TestViewModel(#NonNull Application application) {
super(application);
repository = new TestRepository(application);
numberOfEntries = repository.getNumberOfEntries();
allTests = repository.getAllTests();
}
public void insert(Test test) { repository.insert(test);}
public void delete(Test test) { repository.delete(test);}
public LiveData<Integer> getNumberOfEntries(){ return numberOfEntries; }
public LiveData<List<Test>> getAllTests() { return allTests;}
}
Thanks!
Follow these steps, I hope it will help:
get your itemList from TestAdapter.
you can change any raw you want. (For example change data of item in raw 6)
send it back to the testAdapter.
call method notifyDataSetChanged();.
if you only change one item at a time, it's better to call notifyItemChanged(position); abecause it has a better performance than notifyDataSetChanged();
You have more other tools like notifyItemInserted(position);
notifyItemRemoved(position); that might help you.
Try to modify your ItemTouchHelper implementation like below:
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0,
ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
testViewModel.delete(adapter.getTestAt(viewHolder.getAdapterPosition()));
//get current list from adapter
List currentList = adapter.getCurrentList();
//remove item from list
currentList.remove(viewHolder.getAdapterPosition());
//submit the current list to refresh view
adapter.submitList(currentList);
}
}).attachToRecyclerView(recyclerView);
I knew my question is similar with the other questioners but it was not solved my problem because I am still curious about how to declare the item which is the children of parent node. This is my stucture data on my Firebase:
I've tried to created the classes for my case:
DolanIemClass.java
private String name_tourism;
private String location_tourism;
private String info_tourism;
private String telepon;
private String url_photo;
private String url_photo_collage;
private double lat_location_tourism;
private double lng_location_tourism;
public DolanItemClass() {
//constructor untuk panggilan ke DataSnapshot.getValue
}
public DolanItemClass(String name_tourism, String location_tourism, String info_tourism, String telepon, String url_photo, String url_photo_collage, double lat_location_tourism, double lng_location_tourism) {
this.name_tourism = name_tourism;
this.location_tourism = location_tourism;
this.info_tourism = info_tourism;
this.telepon = telepon;
this.url_photo = url_photo;
this.url_photo_collage = url_photo_collage;
this.lat_location_tourism = lat_location_tourism;
this.lng_location_tourism = lng_location_tourism;
}
public String getUrl_photo_collage() {
return url_photo_collage;
}
public String getName_tourism() {
return name_tourism;
}
public void setName_tourism(String name_tourism) {
this.name_tourism = name_tourism;
}
public String getLocation_tourism() {
return location_tourism;
}
public void setLocation_tourism(String location_tourism) {
this.location_tourism = location_tourism;
}
public String getInfo_tourism() {
return info_tourism;
}
public void setInfo_tourism(String info_tourism) {
this.info_tourism = info_tourism;
}
public String getTelepon() {
return telepon;
}
public void setTelepon(String telepon) {
this.telepon = telepon;
}
public String getUrl_photo() {
return url_photo;
}
public void setUrl_photo(String url_photo) {
this.url_photo = url_photo;
}
public double getLat_location_tourism() {
return lat_location_tourism;
}
public void setLat_location_tourism(double lat_location_tourism) {
this.lat_location_tourism = lat_location_tourism;
}
public double getLng_location_tourism() {
return lng_location_tourism;
}
public void setLng_location_tourism(double lng_location_tourism) {
this.lng_location_tourism = lng_location_tourism;
}
}
DolanViewHolder.class
import android.view.View;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
public class DolanImageViewHolder extends RecyclerView.ViewHolder {
private final ImageView imgDetailData;
public DolanImageViewHolder(#NonNull View itemView) {
super(itemView);
imgDetailData = itemView.findViewById(R.id.img_detail_item_data);
}
public void showImageArray(DolanItemClass dolanItemClass){
Glide.with(itemView.getContext()).load(dolanItemClass.getUrl_photo_collage()).into(imgDetailData);
}
}
And the activity class to show the list
package co.id.roningrum.firebasearrayimage;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.firebase.ui.database.FirebaseRecyclerAdapter;
import com.firebase.ui.database.FirebaseRecyclerOptions;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;
import com.google.firebase.database.ValueEventListener;
public class DetailTouristListAct extends AppCompatActivity {
private ImageView imgDetailData;
private TextView tvNamaDetail, tvAlamatDetail, tvDescDetail;
private RecyclerView rvImageDetailCollages;
private DatabaseReference databaseReference;
private ValueEventListener valueEventListener;
private FirebaseRecyclerAdapter<DolanItemClass, DolanImageViewHolder> firebaseRecyclerAdapter;
public static final String EXTRA_WISATA_KEY = "tourist_key";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail_tourist_list);
String touristKey = getIntent().getStringExtra(EXTRA_WISATA_KEY);
if(touristKey == null){
throw new IllegalArgumentException("Must pass Extra");
}
imgDetailData = findViewById(R.id.img_detail_data);
tvNamaDetail = findViewById(R.id.tv_name_detail);
tvAlamatDetail = findViewById(R.id.tv_info_tourism_detail);
tvDescDetail = findViewById(R.id.tv_address_detail);
rvImageDetailCollages = findViewById(R.id.rv_photo_collage);
databaseReference = FirebaseDatabase.getInstance().getReference().child("Tourism").child(touristKey);
rvImageDetailCollages.setLayoutManager(new GridLayoutManager(this, 2));
LoadDetailData();
}
private void ShowCollage() {
Query query = databaseReference.child("url_photo_collage");
FirebaseRecyclerOptions<DolanItemClass> options = new FirebaseRecyclerOptions.Builder<DolanItemClass>()
.setQuery(query, DolanItemClass.class)
.build();
firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<DolanItemClass, DolanImageViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull DolanImageViewHolder dolanImageViewHolder, int i, #NonNull DolanItemClass dolanItemClass) {
dolanImageViewHolder.showImageArray(dolanItemClass);
}
#NonNull
#Override
public DolanImageViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new DolanImageViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_image_data, parent, false));
}
};
firebaseRecyclerAdapter.notifyDataSetChanged();
rvImageDetailCollages.setAdapter(firebaseRecyclerAdapter);
}
private void LoadDetailData() {
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
DolanItemClass dolanItemClass = dataSnapshot.getValue(DolanItemClass.class);
tvNamaDetail.setText(dolanItemClass.getName_tourism());
tvAlamatDetail.setText(dolanItemClass.getLocation_tourism());
tvDescDetail.setText(dolanItemClass.getInfo_tourism());
Glide.with(getApplicationContext()).load(dolanItemClass.getUrl_photo()).into(imgDetailData);
ShowCollage();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
databaseReference.addValueEventListener(eventListener);
valueEventListener = eventListener;
}
#Override
protected void onStart() {
super.onStart();
LoadDetailData();
if(firebaseRecyclerAdapter!=null){
firebaseRecyclerAdapter.startListening();
}
}
#Override
protected void onStop() {
super.onStop();
databaseReference.removeEventListener(valueEventListener);
}
}
I expected that I can show the array of url_photo_collage node but I don't have any idea for my item class.
The problem in your code is that your url_photo_collage field is declared in your DolanItemClass class of type String while in your database is an array. To solve this, change the type of your field from String to a List<String> and get it accordingly in your adapter.
Base on this instructions I've created RecyclerView filtering in my app. Almost everything works fine but there are 2 strange things.
When I input text into search view and there is only one item which meets requirements until I hide keyboard I can't see this item.
Second problem is more complicated because it occurs from time to time. My item in RecyclerView has an image in background and not always when filtering image is loaded properly.
Because I now my description might be unclear here is an gif which shows the problem:
Here is my adapter class:
package com.ostojan.x360.view;
import android.support.v7.util.SortedList;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.ostojan.x360.R;
import com.ostojan.x360.model.Game;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class GameAdapter extends RecyclerView.Adapter<GameViewHolder> {
private SortedList<Game> games;
private ArrayList<Game> allGames;
private View.OnClickListener onClickListener;
public GameAdapter(View.OnClickListener onClickListener, List<Game> games) {
this(onClickListener);
this.games.addAll(games);
this.allGames.addAll(games);
}
public GameAdapter(View.OnClickListener onClickListener) {
this.onClickListener = onClickListener;
this.games = new SortedList<Game>(Game.class, new GamesSortedListCallback(this));
this.allGames = new ArrayList<>();
}
#Override
public GameViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_game, parent, false);
view.setOnClickListener(onClickListener);
return new GameViewHolder(view);
}
#Override
public void onBindViewHolder(GameViewHolder holder, int position) {
Game game = games.get(position);
holder.title.setText(game.getTitle());
Picasso.with(holder.itemView.getContext())
.load(game.getCoverLink().toString())
.placeholder(R.drawable.ic_loading)
.fit()
.centerCrop()
.error(R.drawable.ic_error)
.into(holder.coverImage);
}
#Override
public int getItemCount() {
return games.size();
}
public void add(Game game) {
this.games.add(game);
this.allGames.add(game);
notifyDataSetChanged();
}
public void addAll(Collection<Game> games) {
this.games.addAll(games);
this.allGames.addAll(games);
notifyDataSetChanged();
}
public void remove(Game game) {
games.beginBatchedUpdates();
games.remove(game);
allGames.remove(game);
games.endBatchedUpdates();
}
public void replaceAll(Collection<Game> games) {
this.games.beginBatchedUpdates();
List<Game> gamesToRemove = new ArrayList<>();
for (int i = 0; i < this.games.size(); i++) {
Game game = this.games.get(i);
if (!games.contains(game)) {
gamesToRemove.add(game);
}
}
for (Game game : gamesToRemove) {
this.games.remove(game);
}
this.games.addAll(games);
this.games.endBatchedUpdates();
}
public Game get(int index) {
return this.games.get(index);
}
public Collection<Game> getGames() {
return allGames;
}
public void clear() {
this.games.clear();
notifyDataSetChanged();
}
public void search(String query) {
replaceAll(filterGames(query));
}
private Collection<Game> filterGames(String query) {
query = query.toLowerCase();
List<Game> filteredGames = new ArrayList<>();
for (Game game : allGames) {
String gameTitle = game.getTitle().toLowerCase();
if (gameTitle.contains(query)) {
filteredGames.add(game);
}
}
return filteredGames;
}
}
View holder:
package com.ostojan.x360.view;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.ostojan.x360.R;
import butterknife.BindView;
import butterknife.ButterKnife;
public class GameViewHolder extends RecyclerView.ViewHolder {
#BindView(R.id.text_title)
TextView title;
#BindView(R.id.image_cover)
ImageView coverImage;
public GameViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
SortedList callback:
package com.ostojan.x360.view;
import android.support.v7.util.SortedList;
import android.support.v7.widget.RecyclerView;
import com.ostojan.x360.model.Game;
import java.util.Comparator;
public class GamesSortedListCallback extends SortedList.Callback<Game> {
private static final Comparator<Game> GAMES_COMPARATOR = new Comparator<Game>() {
#Override
public int compare(Game o1, Game o2) {
return o1.getId().compareTo(o2.getId());
}
};
private RecyclerView.Adapter<GameViewHolder> adapter;
public GamesSortedListCallback(RecyclerView.Adapter<GameViewHolder> adapter) {
this.adapter = adapter;
}
#Override
public int compare(Game o1, Game o2) {
return GAMES_COMPARATOR.compare(o1, o2);
}
#Override
public void onChanged(int position, int count) {
adapter.notifyItemRangeChanged(position, count);
}
#Override
public boolean areContentsTheSame(Game oldItem, Game newItem) {
return oldItem.equals(newItem);
}
#Override
public boolean areItemsTheSame(Game item1, Game item2) {
return item1.getId() == item1.getId();
}
#Override
public void onInserted(int position, int count) {
adapter.notifyItemRangeInserted(position, count);
}
#Override
public void onRemoved(int position, int count) {
adapter.notifyItemRangeRemoved(position, count);
}
#Override
public void onMoved(int fromPosition, int toPosition) {
adapter.notifyItemMoved(fromPosition, toPosition);
}
}
And here how I call filtering from activity:
RecyclerView gamesList;
GameAdapter gamesAdapter;
#Override
public boolean onQueryTextSubmit(String query) {
onQueryTextChange(query);
return true;
}
#Override
public boolean onQueryTextChange(String newText) {
gamesAdapter.search(newText);
gamesList.scrollToPosition(0);
return true;
}