I have a a view where a bunch of my Sqlite data is displayed. I recently added a column to my database called location_position. I have added a button to my relative layout so that when its clicked I want the data inside to be sorted in ascending format. I have tried following a few examples online but with the way my app is setup im struggling tom get it to work.
I have a routeView.java class and a routeAdapter
I would really apreciate if someone can show me how to have the content sorted when the button is clicked, or any resources with similar solutions
public class RouteView extends AppCompatActivity {
RecyclerView recyclerView;
routeAdapter routeAdapter;
ArrayList<String> location_id, location_name, location_county, location_description, location_route, location_position;
MyDatabaseHelper myDB;
Button createPDFButton, btnNorth, southBtn;
Context mContext = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_route_view);
Button southBtn = findViewById(R.id.button_south);
southBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Collections.sort(ArrayList);
}
});
// btnRemove = findViewById(R.id.btnRemove);
recyclerView = findViewById(R.id.recyclerView);
myDB = new MyDatabaseHelper(this);
createPDFButton = findViewById(R.id.createPDFButton);
location_id = new ArrayList<>();
location_name = new ArrayList<>();
location_county = new ArrayList<>();
location_description = new ArrayList<>();
location_route = new ArrayList<>();
location_position = new ArrayList<>();
Cursor cursor = myDB.readAllData();
createPDFButton.setOnClickListener(new View.OnClickListener() {
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
#Override
public void onClick(View v) {
if (UserActivity.checkAppPermission(RouteView.this, "android.permission.WRITE_EXTERNAL_STORAGE", 1)){
generatePDF(recyclerView);
}
}
});
while (cursor.moveToNext()){
if(cursor.getString(4).equals("1")) {
location_id.add(cursor.getString(0));
location_name.add(cursor.getString(1));
location_county.add(cursor.getString(2));
location_description.add(cursor.getString(3));
location_route.add(cursor.getString(4));
location_position.add(cursor.getString(8));
}
}
routeAdapter = new routeAdapter(this, this, location_id, location_name, location_county, location_description, location_route, location_position);
recyclerView.setAdapter(routeAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
and this is the route adapter class
public class routeAdapter extends RecyclerView.Adapter<routeAdapter.MyViewHolder> {
//private final ClickListener listener;
private Context context;
MyDatabaseHelper myDB;
Activity activity;
private ArrayList location_id, location_name, location_county, location_description, location_position, location_route, location_image_url;
Button btnRemove;
String id, name, county, description;
routeAdapter(Activity activity, Context context, ArrayList location_id, ArrayList location_name, ArrayList location_county,
ArrayList location_description, ArrayList location_route, ArrayList location_position){
this.activity = activity;
this.context = context;
this.location_id = location_id;
this.location_name = location_name;
this.location_county = location_county;
this.location_description = location_description;
this.location_position = location_position;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.route_row, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, final int position) {
holder.location_id_txt.setText(String.valueOf(location_id.get(position)));
holder.location_name_txt.setText(String.valueOf(location_name.get(position)));
holder.location_county_txt.setText(String.valueOf(location_county.get(position)));
holder.location_description_txt.setText(String.valueOf(location_description.get(position)));
holder.mainLayout2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(context, RouteView.class);
intent.putExtra("id", String.valueOf(location_id.get(position)));
intent.putExtra("name", String.valueOf(location_name.get(position)));
intent.putExtra("county", String.valueOf(location_county.get(position)));
intent.putExtra("description",String.valueOf(location_description.get(position)));
activity.startActivityForResult(intent, 2);
}
});
}
#Override
public int getItemCount() { return location_id.size(); }
class MyViewHolder extends RecyclerView.ViewHolder {
TextView location_id_txt, location_name_txt, location_county_txt, location_description_txt, added_to_route_txt, location_image_url;
LinearLayout mainLayout2;
Button btnRemove;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
location_id_txt = itemView.findViewById(R.id.location_id_txt);
location_name_txt = itemView.findViewById(R.id.location_name_txt);
location_county_txt = itemView.findViewById(R.id.location_county_txt);
location_description_txt = itemView.findViewById(R.id.location_description_txt);
mainLayout2 = itemView.findViewById(R.id.mainLayout2);
}
}
}
This is the basic concept:
On clicking a button or whatever to sort the things in a specific order, you sort the ArrayList that contains the values reflected in the RecyclerView. Then you update/ recreate the RecyclerView to register the changes.
Related
As the title says, I'm trying to add an item from a different class. I get no errors but the item doesn't appear. I've read about updating the recyclerview but I'm still not sure how to do this. Below is the code.
The home page is where the list will be shown and the floating action button will redirect the user to the add item page. Here the user will enter the name, price, description, etc. After pressing the button to add the item, it redirects the user back to the home page and the list should update.
Home.java
public class Home extends AppCompatActivity{
private FirebaseAuth mAuth;
private FloatingActionButton addItemFab;
private RecyclerView recyclerView;
// The adapter is responsible for loading the items in the recycler view we need. This ensures good performance
private RecyclerView.Adapter adapter;
// The layout manager is responsible for laying out the items in the Recycler view
private RecyclerView.LayoutManager layoutManager;
private ArrayList<Item> itemList;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.home_activity);
// Initialize Firebase Auth
mAuth = FirebaseAuth.getInstance();
// floating action button to add an item page
addItemFab = findViewById(R.id.addItemFab);
addItemFab.setOnClickListener(view -> {
Intent intent = new Intent(Home.this, AddItem.class);
startActivity(intent);
});
itemList = new ArrayList<Item>();
// add item for testing
itemList.add(new Item(R.drawable.ic_logo, "Baby Stroller", "A stroller for baby", "59.99"));
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
adapter = new Adapter(itemList);
adapter.notifyItemInserted(itemList.size()-1);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
}
// log out back to start page
public void goToStart(View view){
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
}
}
Adapter.java
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder>{
private ArrayList<Item> ItemList;
public static class ViewHolder extends RecyclerView.ViewHolder{
public ImageView item_image;
public TextView item_name;
public TextView item_desc;
public TextView item_price;
public ViewHolder(#NonNull View itemView) {
super(itemView);
item_image = itemView.findViewById(R.id.item_image);
item_name = itemView.findViewById(R.id.item_name);
item_desc = itemView.findViewById(R.id.desc);
item_price = itemView.findViewById(R.id.price);
}
}
public Adapter(ArrayList<Item> itemList) {ItemList = itemList;}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_items, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Item currentItem = ItemList.get(position);
holder.item_image.setImageResource(currentItem.getItemImage());
holder.item_name.setText(currentItem.getItemName());
holder.item_desc.setText(currentItem.getItemDesc());
holder.item_price.setText(currentItem.getItemPrice());
}
#Override
public int getItemCount() {
return ItemList.size();
}
}
Item.java
public class Item {
private int itemImage;
private String itemName;
private String itemDesc;
private String itemPrice;
public Item(int itemImage, String itemName, String itemDesc, String itemPrice){
this.itemImage = itemImage;
this.itemName = itemName;
this.itemDesc = itemDesc;
this.itemPrice = itemPrice;
}
public int getItemImage(){return itemImage;}
public String getItemName(){return itemName;}
public String getItemDesc(){return itemDesc;}
public String getItemPrice(){return itemPrice;}
}
AddItem.java
public class AddItem extends AppCompatActivity {
ImageView itemImage;
EditText itemName;
EditText itemPrice;
EditText itemDesc;
private ArrayList<Item> itemList;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.add_item_activity);
itemImage = findViewById(R.id.image_holder);
itemName = findViewById(R.id.add_item_name);
itemPrice = findViewById(R.id.add_price);
itemDesc = findViewById(R.id.add_desc);
itemList = new ArrayList<Item>();
}
public void addItem(View view) {
itemList.add(new Item(R.drawable.ic_logo, itemName.getText().toString(), itemPrice.getText().toString(), itemDesc.getText().toString()));
Intent intent = new Intent(this, Home.class);
startActivity(intent);
}
}
Thanks for the help.
You should not be updating itemList in AddItem because this array have nothing to do whith the list of your recyclerView, what you should do instead is :
Start the AddActivity -> let the user create the Item object -> return the object to the HomeActivity and update your recyclerView there
To do that you can use StartActivityForResult by declaring it in your homeActivity and launch it in FAB:
ActivityResultLauncher<Intent> mStartForResult =
registerForActivityResult(new
ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
Intent intent = result.getData();
Item item = (Item) intent.getParcelableExtra("myItem");
adapter.addItem(item);
}
});
#Override
protected void onCreate(Bundle savedInstanceState) {
...
addItemFab.setOnClickListener(view -> {
Intent intent = new Intent(Home.this, AddItem.class);
startActivity(intent);
});
}
With the method addItem in your adapter as :
public void addItem(Item item){
ItemList.add(item)
this.notifyDataSetChanged()
}
And you would send back your item in AddItem like that :
public void addItem(View view) {
Item newItem = new Item(R.drawable.ic_logo, itemName.getText().toString(), itemPrice.getText().toString(), itemDesc.getText().toString());
Intent resultIntent = new Intent();
resultIntent.putExtra("myItem", newItem);
setResult(RESULT_OK, resultIntent);
finish();
}
Your Item should implement Parcelable to be able to be accepted in the intent
You can read more about how to communicate between activity here : https://developer.android.com/training/basics/intents/result
And more about Recycler view here : https://developer.android.com/develop/ui/views/layout/recyclerview
I have a recyclerview. There are city names in the recyclerview and when I long click, I want to delete it from the recyclerview. I wrote some code in adapter class. When I click on the city names, I can delete them, but when I view the recyclerview again, the city names I deleted appear again. How can I fix this ?
My adapter class
public class Adapter extends RecyclerView.Adapter<Adapter.MyViewHolder> {
ArrayList<City> arrayList;
Context context;
public Adapter(ArrayList<City> arrayList ,Context context ){
this.arrayList = arrayList;
this.context = context;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
RecyclerviewRowBinding recyclerviewRowBinding = RecyclerviewRowBinding.inflate(LayoutInflater.from(parent.getContext()),parent,false);
return new MyViewHolder(recyclerviewRowBinding);
}
#Override
public void onBindViewHolder(#NonNull Adapter.MyViewHolder holder, int position) {
holder.binding.MytxtCities.setText(arrayList.get(position).cityName);
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setIcon(R.drawable.warningicon);
builder.setMessage("Are you sure that you want to delete "+arrayList.get(position).cityName);
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
arrayList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position,arrayList.size());
}
}).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
}).show();
return true;
}
});
holder.itemView.setOnClickListener(v -> {
Intent intent = new Intent(holder.itemView.getContext(),MainActivity.class);
intent.putExtra("citId",arrayList.get(position).id);
holder.itemView.getContext().startActivity(intent);
});
}
#Override
public int getItemCount() {
return arrayList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView Mytxt_cities;
private RecyclerviewRowBinding binding;
public MyViewHolder(#NonNull RecyclerviewRowBinding binding) {
super(binding.getRoot());
this.binding = binding;
Mytxt_cities = itemView.findViewById(R.id.Mytxt_cities);
}
}
}
My recyclerview class is cities class
public class cities extends AppCompatActivity {
RecyclerView recyclerView ;
ArrayList<City> cityArrayList;
Adapter cityadapter;
ImageView cities_back_icon;
public void init(){
cities_back_icon = findViewById(R.id.Id_cities_back_icon);
cities_back_icon_click_register();
cityArrayList = new ArrayList<>();
recyclerView = findViewById(R.id.recyclerview_id);
SQLGet_Data();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cities);
init();
}
private void cities_back_icon_click_register(){
cities_back_icon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(cities.this, MainActivity.class);
startActivity(intent);
}
});
}
private void SQLGet_Data(){
try {
SQLiteDatabase sqLiteDatabase = this.openOrCreateDatabase("City",MODE_PRIVATE,null);
Cursor cursor = sqLiteDatabase.rawQuery("SELECT*FROM city",null);
int idIx = cursor.getColumnIndex("id");
int nameIx = cursor.getColumnIndex("cityname");
while(cursor.moveToNext()){
String cityname = cursor.getString(nameIx);
int id = cursor.getInt(idIx);
City city = new City(cityname,id);
cityArrayList.add(city);
}
cityadapter.notifyDataSetChanged();
cursor.close();
}
catch (Exception e ){
e.printStackTrace();
}
/*---------------------- set recyclerview-----------------------------*/
recyclerView.setLayoutManager(new LinearLayoutManager(cities.this));
cityadapter = new Adapter(cityArrayList,this);
recyclerView.setAdapter(cityadapter);
/*--------------------------We drew a line between the data in the recyclerview------------------------------------*/
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL);
Drawable drawable = ContextCompat.getDrawable(getApplicationContext(), R.drawable.custom_divider);
dividerItemDecoration.setDrawable(drawable);
recyclerView.addItemDecoration(dividerItemDecoration);
}
}
The problem is that you are only deleting the cities from your ArrayList that is inside your adapter. But those cities still remain in your SQL database. Then when you restart the Activity your ArrayList will be created with the data of your SQL database, where those deleted cities still exist.
To delete cities consistently you need to delete the cities not only in your adapter but also in your SQL database.
I Am working on project where users recognizes text(OCR) and then see all their text(OCR) history in another activity
App Link : https://play.google.com/store/apps/details?id=com.thetechroot.vision
I added shared preference and recycle view,
but i am only getting the first Text that was recognized
Working :-
Users Recognize Text(OCR) in Textactivity, then to view users history of scanned text(OCR) the history is shown in different activity
How Can I Saved Textview From One Activity to diff activity, and show it into recycleview using shared preference
TEXTACTIVTY.JAVA
textRecognizer.processImage(image)
.addOnSuccessListener(new OnSuccessListener<FirebaseVisionText>() {
#Override
public void onSuccess(final FirebaseVisionText firebaseVisionText) {
translatelan(firebaseVisionText);
cd_text_re.setVisibility(View.VISIBLE);
spinnerlan.setVisibility(View.VISIBLE);
txtrecog.setText(firebaseVisionText.getText());
String th = SharedCommon.getSharedPreferencesString(getApplicationContext(), texthistory,firebaseVisionText.getText());
//int i = SharedCommon.getPreferencesInt(getApplicationContext(), key1,50);
final SharedCommon scth = new SharedCommon();
if (txtrecog.equals("")){
Toast.makeText(TextActivity.this, "Text: "+th, Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(TextActivity.this, "Text: "+th, Toast.LENGTH_SHORT).show();
scth.putSharedPreferencesString(getApplicationContext(), SharedCommon.texthistory, th);
}
/* SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit();
editor.putString("name", String.valueOf(txtrecog.getText()));
editor.putInt("idName", 1);
editor.apply();*/
drawtextvision(firebaseVisionText);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
MyAdapter.java
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<String> values;
ArrayList personNames;
Context context;
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView txtHeader;
public TextView txtFooter;
public View layout;
public ViewHolder(View v) {
super(v);
layout = v;
txtHeader = (TextView) v.findViewById(R.id.firstLine);
txtFooter = (TextView) v.findViewById(R.id.secondLine);
}
}
public void add(int position, String item) {
values.add(position, item);
notifyItemInserted(position);
}
public void remove(int position) {
values.remove(position);
notifyItemRemoved(position);
}
public MyAdapter(Context context, ArrayList personNames) {
this.context = context;
this.personNames = personNames;
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(List<String> myDataset) {
values = myDataset;
}
// Create new views (invoked by the layout manager)
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
/*final String th = SharedCommon.getSharedPreferencesString(getApplicationContext(), texthistory,"");
*/
LayoutInflater inflater = LayoutInflater.from(
parent.getContext());
View v =
inflater.inflate(R.layout.layout_history_text, parent, false);
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(v);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
final String name = values.get(position);
holder.txtHeader.setText(name);
holder.txtHeader.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
holder.txtFooter.setText("Footer: " + name);
}
});
//holder.txtFooter.setText("Footer: " + name);
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return values.size();
}
}
HISTORYACTIVITY.JAVA
public class AboutActivity extends AppCompatActivity {
/* WebView webView;*/
ProgressDialog mprogreeinternet;
String apppackagename = "com.thetechroot.vision";
int versionCode = BuildConfig.VERSION_CODE;
String versionName = BuildConfig.VERSION_NAME;
String appid = BuildConfig.APPLICATION_ID;
Button btnlimit;
WebView webview;
/* private RecyclerView recyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager layoutManager;*/
private RecyclerView recyclerView;
private MyAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
LinearLayout layouthide,layoutcredit;
int[] photos={R.drawable.logoam, R.drawable.iconshandwrit52,R.drawable.productsearch52,R.drawable.iconsqrcode52};
ImageButton arrdown,arrup,arrcre,arrcreup;
TextView txthistory;
TextView mItemDescription;
ImageButton mDescriptionImg,mupImg;
CardView cdhistory;
#SuppressLint("WrongViewCast")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
/* btnlimit = (Button) findViewById(R.id.btnlimit);*/
final String th = SharedCommon.getSharedPreferencesString(getApplicationContext(), texthistory,"");
// Toast.makeText(this, ""+th, Toast.LENGTH_SHORT).show();
recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
// recyclerView.setHasFixedSize(true);
// use a linear layout manager
mLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(mLayoutManager);
// Use the default animator
// recyclerView.setItemAnimator(new DefaultItemAnimator());
// you could add item decorators
// RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST);
// recyclerView.addItemDecoration(itemDecoration);
ArrayList<String> values = new ArrayList<String>();
/*for (int i = 0; i < 100; i++) {
values.add("Test" + i);
}*/
Toast.makeText(this, ""+String.valueOf(th), Toast.LENGTH_SHORT).show();
values.add(""+String.valueOf(th));
// specify an adapter (see also next example)
mAdapter = new MyAdapter(values);
recyclerView.setAdapter(mAdapter);
ItemTouchHelper.SimpleCallback simpleItemTouchCallback =
new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder
target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
// input.remove(viewHolder.getAdapterPosition());
mAdapter.notifyItemRemoved(viewHolder.getAdapterPosition());
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);
}
#Override
public void onBackPressed() {
super.onBackPressed();
Intent startIntent = new Intent(AboutActivity.this, TextActivity.class);
startActivity(startIntent);
finish();
}
}
It's a position issue, you have to use setTag() and getTag(), check this
final String name = values.get(position);
**holder.txtFooter.setTag(name);**
holder.txtHeader.setText(name);
holder.txtHeader.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
**holder.txtFooter.setText("Footer: " + v.getTag());**
}
});
Here TEXTACTIVTY.JAVA you are using single string, so instead of appending it to previous strings in shared preference you are replacing the history. Ideally you should save Strings array and retrieve the same. Currently values have size one because it has only one string.
First use Sting Array. To save String Array in shared preferences do the following
StringBuilder sb = new StringBuilder();
for (int i = 0; i < playlists.length; i++) {
sb.append(playlists[i]).append(",");
}
prefsEditor.putString(PLAYLISTS, sb.toString());
Then when you get the String from SharedPreferences simply parse it like this:
String[] playlists = playlist.split(",");
Refer Put and get String array from shared preferences
And https://blog.fossasia.org/storing-a-data-list-in-phimpme-android/ for more.
I am using RecyclerView and new items appear in it only at the top of the list. I want to use default insert animation for this action, but it breaks OnClick() method inside ViewHolder.
If I have inserted new item, OnClick() uses data from the previous item of ArrayList. If I use NotifyDataSetChanged(), data is ok, but of course, there is no animation. Looks like there is problem with ViewHolder.bind() method being not called. How can I update index of every item after NotifyItemInserted(0)?
RecyclerAdapter.java
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
private Context context;
private LayoutInflater inflater;
private ArrayList<Song> data = new ArrayList<>();
//то, что ниже - для анимации
private static final int UNSELECTED = -1;
private RecyclerView recyclerView;
private int selectedItem = UNSELECTED;
public RecyclerAdapter(Context context, ArrayList<Song> data, RecyclerView recyclerView) {
this.context = context;
inflater = LayoutInflater.from(context);
this.data = data;
this.recyclerView = recyclerView;
}
public void insert(Song song)
{
data.add(0, song);
recyclerView.scrollToPosition(0);
notifyItemInserted(0);
}
public void swap(ArrayList<Song> datas){
data.clear();
data.addAll(datas);
notifyDataSetChanged();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView tv_songName;
TextView tv_songGenreID;
TextView tv_songUserInfo;
ExpandableLayout expandableLayout;
private CardView expandButton;
private int position;
private TextView youtubeButton;
private TextView shareButton;
public ViewHolder(View itemView) {
super(itemView);
tv_songName = (TextView) itemView.findViewById(R.id.tv_songName);
tv_songGenreID = (TextView) itemView.findViewById(R.id.tv_songGenreID);
tv_songUserInfo = (TextView) itemView.findViewById(R.id.tv_songUserInfo);
youtubeButton = (TextView) itemView.findViewById(R.id.youtube_button);
shareButton = (TextView) itemView.findViewById(R.id.share_button);
expandableLayout = (ExpandableLayout) itemView.findViewById(R.id.expandable_layout);
expandableLayout.setInterpolator(new OvershootInterpolator());
expandButton = (CardView) itemView.findViewById(R.id.card_view);
expandButton.setOnClickListener(this);
youtubeButton.setOnClickListener(this);
shareButton.setOnClickListener(this);
}
public void bind(int position) {
this.position = position;
Song current = data.get(position);
StringBuilder songInfo = new StringBuilder();
songInfo.append(context.getString(R.string.genre));
songInfo.append(current.songGenreID);
songInfo.append(System.getProperty("line.separator"));
songInfo.append(context.getString(R.string.album));
this.tv_songName.setText(current.songName);
this.tv_songGenreID.setText(songInfo);
this.tv_songUserInfo.setText(current.songUserInfo);
expandButton.setSelected(false);
expandableLayout.collapse(false);
}
#Override
public void onClick(View view) {
switch (view.getId())
{
case R.id.youtube_button:
String youtubeURL = data.get(position).songName.replaceAll(" ", "%20");
youtubeURL = "https://www.youtube.com/results?search_query=" + youtubeURL;
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(youtubeURL));
context.startActivity(browserIntent);
break;
case R.id.share_button:
String songName = data.get(position).songName;
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_TEXT, songName);
shareIntent.setType("text/plain");
context.startActivity(shareIntent);
break;
default:
ViewHolder holder = (ViewHolder) recyclerView.findViewHolderForAdapterPosition(selectedItem);
if (holder != null) {
holder.expandButton.setSelected(false);
holder.expandableLayout.collapse();
}
if (position == selectedItem) {
selectedItem = UNSELECTED;
} else {
expandButton.setSelected(true);
expandableLayout.expand();
selectedItem = position;
}
break;
}
}
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v=inflater.inflate(R.layout.recycler_item, parent,false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.bind(position);
setAnimation(holder.itemView, position);
}
private int lastPosition = -1;
private void setAnimation(View viewToAnimate, int position) {
if (position > lastPosition) {
Animation anim = AnimationUtils.loadAnimation(context, android.R.anim.fade_in);
viewToAnimate.startAnimation(anim);
lastPosition = position;
}
}
#Override
public int getItemCount() {
return data.size();
}
}
OnCreate() of Activity.java
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.AppTheme_NoActionBar);
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
layout = (CoordinatorLayout)findViewById(R.id.coordinator1);
FloatingActionButton myFab = (FloatingActionButton) findViewById(R.id.floatingActionButton);
mRecyclerView = (RecyclerViewEmptySupport) findViewById(R.id.my_recycler_view);
mRecyclerView.setEmptyView(findViewById(R.id.list_empty));
myFab.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
FragmentManager fm = getSupportFragmentManager();
AddSongDialogFragment addSongDialogFragment = new AddSongDialogFragment();
addSongDialogFragment.show(fm, "add_song");
}
});
mAdapter = new RecyclerAdapter(MainActivity.this, data, mRecyclerView);
mLayoutManager = new LinearLayoutManager(MainActivity.this);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(mLayoutManager);
dbHelper = new DBHelper(this);
mAdapter.swap(dbHelper.readFromDB());
RecyclerView.ItemAnimator itemAnimator = new DefaultItemAnimator();
itemAnimator.setAddDuration(700);
itemAnimator.setRemoveDuration(1000);
mRecyclerView.setItemAnimator(itemAnimator);
}
Use getAdapterPosition() to get correct position of your item from your VIewHolder. That way the positions will not be mixed up after moving/deleting items from the RecyclerView.
NOTE: If the user clicks on the empty space during the animationgetAdapterPosition() might return -1: make sure to handle the case.
Good luck
You can use notifyItemRangeChanged(position, data.size()); to notify the other items after you added the new item.
You can also animate the swap() function if you use the functions notifyItemRemoved() notifyItemInserted() and notifyItemMoved() instead of notifyDataSetChanged(). You only have to check if the new list includes the items of the old list.
I have a question about passing clicked cardview data to activity, and here the full story :
I have an Activity called "Details", which contains 2 TextViews in it's layout, Title & Description .
I have setup a fragment ( tab_1 ) which contain the recyclerview codes and the the items data, each item of those contain : title & description .
What i want :
When the user click the item, it will open the Details Activity, and change Details layout title, with clicked item title, and the same for description .
I've manged to create the other activity as an example, and made intent to start it, plus adding "addOnTouchlistener" thanks to Stackoverflow, i've found the way to make it .
So, how to make this alive? I've tried many ways of the available answers on Stackoverflow, but all of them not working, or not related to my request .
Here are my files :
itemsdata.java :
public class itemsdata {
int CatPic;
String title;
String Descr;
int Exapnd;
int expand_no;
tab_1.java ( fragment )
public class tab_1 extends Fragment implements SearchView.OnQueryTextListener {
private RecyclerView mRecyclerView;
public RecyclingViewAdapter adapter;
private Activity context;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.tab_1, container, false);
mRecyclerView = (RecyclerView)layout.findViewById(R.id.recycler_view);
mRecyclerView.addOnItemTouchListener(new RecyclerItemClickListener
(getContext(), new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
Intent i = new Intent(view.getContext(), DetailsActivity.class);
view.getContext().startActivity(i);
}
}));
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
adapter = new RecyclingViewAdapter(getActivity(),Listed());
mRecyclerView.setAdapter(adapter);
return layout;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.main, menu);
final MenuItem item = menu.findItem(R.id.action_search);
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(item);
searchView.setOnQueryTextListener(this);
}
#Override
public boolean onQueryTextChange(String query) {
final List<itemsdata> filteredModelList = filter(Listed(), query);
adapter.animateTo(filteredModelList);
mRecyclerView.scrollToPosition(0);
return true;
}
#Override
public boolean onQueryTextSubmit(String query) {
return true;
}
private List<itemsdata> filter(List<itemsdata> models, String query) {
query = query.toLowerCase();
final List<itemsdata> filteredModelList = new ArrayList<>();
for (itemsdata model : models) {
final String text = model.title.toLowerCase();
if (text.contains(query)) {
filteredModelList.add(model);
}
}
return filteredModelList;
}
public List<itemsdata> Listed()
{
//Titles Strings
String sys_title1 = getString(R.string.system_item_title_1);
String sys_title2 = getString(R.string.system_item_title_2);
String sys_title3 = getString(R.string.system_item_title_3);
//Description Strings
String sys_descr1 = getString(R.string.system_item_desc_1);
String sys_descr2 = getString(R.string.system_item_desc_2);
String sys_descr3 = getString(R.string.system_item_desc_3);
//Adding New Cards
List<itemsdata> data = new ArrayList<>();
//Categories Icons New Items ** Make It The Same
int[] icons = {
R.drawable.facebook_icon ,
R.drawable.twitter_icon ,
R.drawable.twitter_icon
};
//Expand Button New Items
int[] expandbutton = {
R.drawable.expanded ,
R.drawable.expanded ,
R.drawable.expanded
};
//UnExpand Button New Items
int[] unexpandbutton = {
R.drawable.ca_expand ,
R.drawable.ca_expand ,
R.drawable.ca_expand
};
//Titles New Items
String[] titles = {
sys_title1 ,
sys_title2 ,
sys_title3
};
//Description New Items
String[] Description = {
sys_descr1 ,
sys_descr2 ,
sys_descr3
};
for(int i = 0;i<titles.length && i < icons.length && i < Description.length && i < unexpandbutton.length && i < expandbutton.length ; i++)
{
itemsdata current = new itemsdata();
current.CatPic = icons[i];
current.title = titles[i];
current.Descr = Description[i];
current.expand_no = unexpandbutton[i];
current.Exapnd = expandbutton[i];
data.add(current);
}
return data;
}
}
Details Activity :
public class DetailsActivity extends AppCompatActivity{
TextView title;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.details);
title = (TextView)findViewById(R.id.details_title);
}
EDIT : I've made it, i have added a button which open the fragment, and passed the data, in the Adapter, but i want it via tab_1.java, not the Adapter, i mean i want to click on the item to open the fragment, not on a button, here a snap from my Adapter code ( i've added it in OnBindViewHolder )
I've setup a OnClick and implemented the Vew.setOnClick ..etc, but when i click the item, nothing happen.
#Override
public void onBindViewHolder(final MyRecycleViewHolder holder, int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(v.getContext(),DetailsActivity.class);
v.getContext().startActivity(i);
}
});
//Referencing Data
final itemsdata currentobject = mdata.get(position);
//Referencing Items
holder.ProbTitle.setText(currentobject.title);
holder.ProbDescr.setText(currentobject.Descr);
holder.CategoryPic.setImageResource(currentobject.CatPic);
holder.ExpandButton.setImageResource(currentobject.Exapnd);
holder.ExpandNoButton.setImageResource(currentobject.expand_no);
//What Happen When You Click Expand Button .
holder.ExpandButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(v.getContext(), DetailsActivity.class);
i.putExtra("TitleKey",holder.ProbTitle.getText().toString());
v.getContext().startActivity(i);
}
}
);
public static class MyRecycleViewHolder extends RecyclerView.ViewHolder
{
SwipeLayout swipeLayout;
//Defining Items .
TextView ProbTitle;
ImageButton ExpandButton;
TextView ProbDescr;
ImageButton ExpandNoButton;
ImageView CategoryPic;
/*
TextView Card_Star;
TextView Card_UnStar;
*/
TextView Card_Share;
//Referencing Resources
public MyRecycleViewHolder(final View itemView) {
super(itemView);
ProbTitle = (TextView) itemView.findViewById(R.id.prob_title);
CategoryPic = (ImageView) itemView.findViewById(R.id.cat_pic);
ProbDescr = (TextView) itemView.findViewById(R.id.prob_descr);
ExpandButton = (ImageButton) itemView.findViewById(R.id.expand_button);
ExpandNoButton = (ImageButton) itemView.findViewById(R.id.expand_no_button);
/*
Card_Star = (TextView) itemView.findViewById(R.id.card_star);
Card_UnStar = (TextView) itemView.findViewById(R.id.card_unstar);
*/
Card_Share = (TextView) itemView.findViewById(R.id.card_share);
swipeLayout = (SwipeLayout) itemView.findViewById(R.id.swipe);
}
create an Interface inside your adapter containing methods. And while implementing your Adapter, those methods will be implemented in your activity and you can perform whatever action you want.
public class Adapter extends RecyclerView.Adapter<MyRecycleViewHolder> {
public interface Callbacks {
public void onButtonClicked(String titleKey);
}
private Callbacks mCallbacks;
public Adapter() {
}
#Override
public MyRecycleViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_details, null);
return new MyRecycleViewHolder(v);
}
#Override
public void onBindViewHolder(final MyRecycleViewHolder holder, final int i) {
holder.ExpandButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mCallbacks != null) {
mCallbacks.onButtonClicked(holder.ProbTitle.getText().toString());
}
}
});
}
#Override
public int getItemCount() {
return;
}
public void setCallbacks(Callbacks callbacks) {
this.mCallbacks = callbacks;
}
}
you may try do this on your onItemClick()
Intent i = new Intent(view.getContext(), DetailsActivity.class);
i.putExtra("title", yourTitle);
i.putExtra("description", yourDescription);
view.getContext().startActivity(i);
and when oncreate in your DetailActivity,do this
String title = getIntent().getStringExtra("title");
String description = getIntent().getStringExtra("description");
so you can pass title and description to DetailActivity
IMO, you implement setOnClickListener inside Adapter of RecyclerView. You can refer to my following sample code, then apply its logic to your code. Hope it helps!
public class MyRVAdapter extends RecyclerView.Adapter<MyRVAdapter.ViewHolder> {
Context mContext;
List<String> mStringList;
public MyRVAdapter(Context mContext, List<String> mStringList) {
this.mContext = mContext;
this.mStringList = mStringList;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview, parent, false);
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TextView textView1 = (TextView) v.findViewById(R.id.textView1);
TextView textView2 = (TextView) v.findViewById(R.id.textView2);
Bundle bundle = new Bundle();
bundle.putString("key1", textView1.getText().toString());
bundle.putString("key2", textView2.getText().toString());
passToAnotherActivity(bundle);
}
});
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// do something...
}
#Override
public int getItemCount() {
if (mStringList != null) {
return mStringList.size();
}
return 0;
}
private void passToAnotherActivity(Bundle bundle) {
if (mContext == null)
return;
if (mContext instanceof MainActivity) {
MainActivity activity = (MainActivity) mContext;
activity.passToAnotherActivity(bundle); // this method must be implemented inside `MainActivity`
}
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public ViewHolder(View itemView) {
super(itemView);
// do something...
}
#Override
public void onClick(View v) {
}
}
}
First of all make your "itemsdata" object to implement Parcelable. You can check it here . In your onItemClick method you pass the object to your Details activity using intent.putExtra("key",listOfDataItems.get(position));
In your DetailsActivity you can get your custom object with getParcelable("key")
All above methods worked, but kinda long, so this one worked for me :
Cardview cardview;
cardView = (CardView)itemView.findViewById(R.id.cv);
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent (view.getContext(), DetailsActivity.class);
i.putExtra("TitleKey",ProbTitle.getText().toString());
i.putExtra("DescrKey",ProbDescr.getText().toString());
view.getContext().startActivity(i);
}
});
And in Details.java :
TextView title;
TextView Descr;
title = (TextView)findViewById(R.id.details_title);
Descr = (TextView)findViewById(R.id.details_descr);
String titleresult = result.getExtras().getString("TitleKey");
String Descrresult = result.getExtras().getString("DescrKey");
title.setText(titleresult);
Descr.setText(Descrresult);