RecyclerView Intent classes - android

I've looked everywhere and can't figure out how to change an intent class in a Recyclerview's onBindViewHolder from the main activity.
If someone knows of a post that explains how you can do this for each different recycled view to go to a different activity please comment it! If you know how to do this even better!
#Override
public void onBindViewHolder(RecyclerViewHolder holder, final int position) {
holder.crate.setImageResource(listData.get(position).getCrate());
holder.crateName.setText(listData.get(position).getCrateName());
holder.cratePrice.setText(listData.get(position).getCratePrice());
holder.setItemClickListener(new ItemClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(context, ***changeThisClass***.class);
context.startActivity(intent);
}
});
}

I've looked everywhere and can't figure out how to change an intent
class in a Recyclerview's onBindViewHolder from the main activity.
You need to give transfer the control of your itemClickListener in RecylerView to the main activity by using a Listener. First, create an interface for the listener in your Adapter:
public class YourAdapter extends RecyclerView.Adapter<YourAdapter.RecyclerViewHolder> {
private YourAdapterListener mListener;
// define the listener
public interface YourAdapterListener {
void onItemClickListener();
}
// set the listener with this
public void setListener(YourAdapterListener listener) {
this.mListener = listener;
}
...
#Override
public void onBindViewHolder(RecyclerViewHolder holder, final int position) {
...
holder.setItemClickListener(new ItemClickListener() {
#Override
public void onClick(View view) {
// tell the listener about the click event.
mListener.onItemClickListener();
}
});
}
}
Then, you need to set the listener in the main activity:
YourAdapter adapter = new YourAdapter();
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
adapter.setListener(new YourAdapter.YourAdapterListener() {
#Override
public void onItemClickListener() {
Intent intent = new Intent(YourActivity.this, YourClass.class);
startActivity(intent);
}
});
Now you can set each class for intent for different RecyclerView by changing it inside the Activity where the RecyclerView reside.

Do you want to change that class based on some rule? Activity.class - is an object of type Class.
So, you can create a separate method:
private Class selectClass(int param){
if (param == 0)
return Activity1.class;
if (param == 1)
return Activity2.class;
....
}
and then do:
Intent intent = new Intent(context, selectClass(...);
or you can do something like this:
Class clazz = null;
if (param == 0)
clazz = Activity1.class;
if (param == 1)
clazz = Activity2.class;
....
if (clazz != null) {
Intent intent = new Intent(context, clazz);
....
}

Related

How to pass intent from Adapter class to other activity but my variable is in other activity

I have a problem. I want to pass my intent String "EmailHolder" from "WarehouseActivity" to "ProfilWarehouseActivity" by click on a recyclerview item in my Adapter Class which is named as "WarehouseAdapter". I want to pass the EmailHolder to fill my data when the user updates data inside ProfilWarehouseActivity.
Here is the "Intent" from my "WarehouseActivity" class :
private String EmailHolder;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_warehouse);
Bundle extras = getIntent().getExtras();
EmailHolder = extras.getString("emailuser");
Here is how I make intent in Adapter Class "WarehouseAdapter" to pass ID data into "ProfilWarehouseActivity" :
#SuppressLint("SetTextI18n")
#Override
public void onBindViewHolder(#NonNull WarehouseAdapter.ViewHolder holder, final int position) {
holder.namaitem.setText(listItems.get(position).get(Konfigurasi_Warehouse.TAG_WAREHOUSENAMA));
holder.stockitem.setText("Stock : "+listItems.get(position).get(Konfigurasi_Warehouse.TAG_WAREHOUSESTOCK));
holder.merekitem.setText("Merek : "+listItems.get(position).get(Konfigurasi_Warehouse.TAG_WAREHOUSEMEREK));
holder.tglin.setText("Tanggal Masuk : "+listItems.get(position).get(Konfigurasi_Warehouse.TAG_WAREHOUSETGLIN));
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v ) {
String idItem = listItems.get(position).get(Konfigurasi.TAG_ITEMID);
passid(idItem);
}
});
}
private void passid(String idItem) {
Intent intent = new Intent(context, ProfilWarehouseActivity.class);
intent.putExtra(Konfigurasi_Warehouse.WAREHOUSE_ID,idItem);
//i think this is for get my EmailHolder from WarehouseActivity to pass it with Intent from this Adapter class
context.startActivity(intent);
}
My question is How to pass Intent with a string "EmailHolder" that contain Intent value through my WarehouseAdapter (Adapter class), but "EmailHolder" is from my WarehouseActivity?
EDIT : Here is how i used the Adapter class from my WarehouseActivity
final WarehouseAdapter mAdapter = new WarehouseAdapter( WarehouseActivity.this,list);
mRecyclerView.setLayoutManager(new LinearLayoutManager(WarehouseActivity.this));
mRecyclerView.setAdapter(mAdapter);
You can have couple of options to solve this:
Option 1:
If you want to start "ProfilWarehouseActivity" activity from the adapter, then you need to pass the "EmailHolder" from "WarehouseActivity" to your adapter by either its constructor, or a setter:
Passing String into Adapter Constructor
final WarehouseAdapter mAdapter = new WarehouseAdapter( WarehouseActivity.this, list, EmailHolder);
Passing String using a Setter
In "ProfilWarehouseActivity" activity:
mAdapter.setEmailHolder(EmailHolder);
In WarehouseAdapter adapter:
private String mEmailHolder;
public void setEmailHolder(String emailHolder) {
this.mEmailHolder = emailHolder;
}
....
private void passid(String idItem) {
Intent intent = new Intent(context, ProfilWarehouseActivity.class);
intent.putExtra(Konfigurasi_Warehouse.WAREHOUSE_ID, idItem);
intent.putExtra("EmailHolder", mEmailHolder);
//i think this is for get my EmailHolder from WarehouseActivity to pass it with Intent from this Adapter class
context.startActivity(intent);
}
Option 2:
The other option is to create a listener and implement it in "ProfilWarehouseActivity", And pass the itemId as a parameter to the listener callback. Then let your "ProfilWarehouseActivity" call the "WarehouseActivity" instead of the WarehouseAdapter whenever this listener is triggered.
In WarehouseAdapter adapter:
public interface ItemClickListener {
public void onItemClick(int idItem);
}
ItemClickListener mItemClickListener;
public void setItemClickListener(ItemClickListener listener) {
mItemClickListener = listener;
}
private void passid(String idItem) {
if (mItemClickListener != null)
mItemClickListener.onItemClick(idItem);
}
In "ProfilWarehouseActivity" activity:
class ProfilWarehouseActivity extends AppCompatActivity implements WarehouseAdapter.ItemClickListener {
private String EmailHolder;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_warehouse);
Bundle extras = getIntent().getExtras();
EmailHolder = extras.getString("emailuser");
}
#Override
onItemClick(int itemId) {
Intent intent = new Intent(this, ProfilWarehouseActivity.class);
intent.putExtra(Konfigurasi_Warehouse.WAREHOUSE_ID, idItem);
intent.putExtra("EmailHolder", EmailHolder);
startActivity(intent);
}
...
final WarehouseAdapter mAdapter = new WarehouseAdapter( WarehouseActivity.this,list);
mAdapter.setItemClickListener(this);
Pass the emailHolder value to your Adapter while creating your Adapter constructor. If I am not wrong, you might be calling the Adapater from your Activity, so just pass the value as constructor parameter.
wareHouseAdapter = new new WarehouseAdapter( WarehouseActivity.this,list,EmailHolder);
And in the WarehouseAdapter
WarehouseAdapter(otherparameter,String emailHolder) {
this.emailHolder= emailHolder;
}
And on clicking the recyclerView item
private void passid(String idItem) {
Intent intent = new Intent(context, ProfilWarehouseActivity.class);
intent.putExtra(Konfigurasi_Warehouse.WAREHOUSE_ID,idItem);
//i think this is for get my EmailHolder from WarehouseActivity to pass it with Intent from this Adapter class
intent.putExtra("emailHolder",emailHolder);
context.startActivity(intent);
}
i think i accidently found the answer (inspired from the other answer before me, thank you)... i just need to set String "EmailHolder" in "WarehouseActivity" to "public static" :
public static String EmailHolder;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_warehouse);
mRecyclerView = findViewById(R.id.recyclerViewItemWar);
Bundle extras = getIntent().getExtras();
EmailHolder = extras.getString("emailuser");
And then use intent from "WarehouseAdapter" like this :
private void passid(String idItem) {
Intent intent = new Intent(context, ProfilWarehouseActivity.class);
intent.putExtra(Konfigurasi_Warehouse.WAREHOUSE_ID,idItem);
intent.putExtra("emailuser",WarehouseActivity.EmailHolder); //i add this
context.startActivity(intent);
}
is it fine to change String from "private" to "public static"..?
For that you have use "interface " You cant directly pass value in Constructor also.

I get a memory leak when I start a transition with shared elements from a recycler item

The recyclerview is in a (androidx) fragment attached to the main activity.
This is the part of the recycler adapter from which the new activity is called:
MainActivity activity;
#Override
public void onBindViewHolder(final MyRecyclerAdapter.ViewHolder viewHolder, final int position) {
final View background = viewHolder.background;
ViewCompat.setTransitionName(background,"background_" + position);
background.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(activity, DetailActivity.class);
Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, background, "background_" + position).toBundle();
activity.startActivity(intent, options);
}
}
}
That's the error I get (once for every shared element i pass to ActivityOptionsCompat):
E/BufferItemConsumer: [unnamed-29987-0] Failed to release buffer:
Unknown error -1 (1)
This error gives me every time you call "finishAfterTransition();" a bug where the current window loses focus
Edit:
As Mahabub Karim suggested, I replaced the Activity Reference with a callback (unfortunately it does not change the error message):
//Adapter Class
OnItemClickListener onItemClickListener;
public static interface OnItemClickListener {
public abstract void onItemClicked(MyRecyclerAdapter.ViewHolder viewHolder, int position);
}
#Override
public void onBindViewHolder(final MyRecyclerAdapter.ViewHolder viewHolder, final int position) {
final View background = viewHolder.background;
ViewCompat.setTransitionName(background,"background_" + position);
background.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onItemClickListener.onItemClicked(viewHolder,position);
}
}
}
public void setListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
//MainActivity Class
...
#Override
public void onItemClicked(MyRecyclerAdapter.ViewHolder viewHolder, int position) {
final View background = viewHolder.background;
Intent intent = new Intent(this, DetailActivity.class);
Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(this, background, "background_" + position).toBundle();
startActivity(intent, options);
}
...
Never ever take activity or fragment reference to adapter cause it's create a cyclic dependency means activity takes reference of adapter and adapter takes reference of activity so there is no way to leave memory. Always each one takes memory reference. Use callback method instead, which will implement by activity from adapter listener.
Use this links accepted answer ->
Callback from Adapter

Android: how do I fix CardView selection based on position passed in an Intent?

I pass data from my RecyclerView Adapter to my MainActiviy. I also use an interface in the Adapter to capture the CardView item position in the MainActivity's onItemClick() and pass that position to a new Activity (CardViewDetails) using an intent. Problem is the CardViewDetails loads the wrong CardView. How do I use the CardView "position" to launch the correct CardView? What am I missing here?
MainActivity
...
public void passDataFromAdapter(Bundle bundle) {
data = bundle.getString("spantimeinhours");
data2 = bundle.getLong("timeinhours");
}
// This method works with an interface in the Adapter to capture the
// CardView item position.
#Override
public void onItemClick(int position, final View view) {
Intent intent = new Intent(this,Details.class);
intent.putExtra("adapterSpanTimeInHours",data);
intent.putExtra("adapterTimeInHours",data2);
startActivity(intent);
}
Details
...
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_details);
Bundle extras = getIntent().getExtras();
msgFromAdapter = extras.getString("adapterSpanTimeInHours");
msg2FromAdapter = extras.getLong("adapterTimeInHours", 0);
}
Adapter
public class MyRecylerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private void passDataFromAdapter(Bundle bundle) {
if (context == null)
return;
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
activity.passDataFromAdapter(bundle); // this method must be implemented inside `MainActivity`
}
}
}
paste this in your onBindViewHolder
viewHolder.myView.setOnClickListener(new View.OnClickListener() {
// Handles the row being clicked.
#Override
public void onClick(View view) {
int adapterPos = itemHolder.getAdapterPosition(); // get the item position.
if (adapterPos != RecyclerView.NO_POSITION) {
if (recyclerItemClickListener != null) {
recyclerItemClickListener.onItemClick(adapterPos, itemHolder.itemView);
}
}
}
});

Why doesn't overridePendingTransition work?

I use this function to create animation when switching between 2 activities. But it makes my app stop (not crash, just like pause). I call overridePendingTransition from Adapter in a Fragment of a Activity.
public class LessonAdapter extends RecyclerView.Adapter {
private List<Lesson> lessonList;
private Context mContext;
public LessonAdapter(Context context, List<Lesson> ll) {
lessonList = ll;
mContext = context;
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.lesson_card,parent, false);
return new LessonHolder(view);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
final LessonHolder lessonHolder = (LessonHolder) holder;
lessonHolder.lessonName.setText(lessonList.get(position).getLessonName());
lessonHolder.lessonName.setTextColor(Color.parseColor("#0B8E46"));
lessonHolder.lessonDescription.setText(lessonList.get(position).getLessonDescription());
lessonHolder.lessonDescription.setTextColor(Color.parseColor("#686868"));
if (lessonList.get(position).getUuid() == 1) {
lessonHolder.lessonCard.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(mContext, WordTypeLessonActivity.class);
mContext.startActivity(i);
((Activity) mContext).overridePendingTransition(R.anim.slide_in, R.anim.slide_out);
}
});
}
if (lessonList.get(position).getUuid() == 2) {
lessonHolder.lessonCard.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(mContext, TenseLessonActivity.class);
mContext.startActivity(i);
((Activity) mContext).overridePendingTransition(R.anim.slide_in, R.anim.slide_out);
}
});
}
if (lessonList.get(position).getUuid() > 2) {
lessonHolder.lessonCard.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(mContext, LessonActivity.class);
i.putExtra("lesson_id", lessonList.get(position).getUuid());
mContext.startActivity(i);
((Activity) mContext).overridePendingTransition(R.anim.slide_in, R.anim.slide_out);
}
});
}
}
#Override
public int getItemCount() {
return lessonList.size();
}
}
You can try calling finish() first.
https://developer.android.com/reference/android/app/Activity.html#overridePendingTransition(int, int)
or supply the desired animation information through a ActivityOptions bundle to startActivity(Intent, Bundle) or a related function
as it recommends in the docs
a stacktrace would be nice and some code from the second activity, also why are you using fragments? Seems like you could do it all in one activity using fragments or not use fragments at all and use two activities.

RecyclerView reloads when an item is clicked

I am using Firebase for my apps back end and I am retrieving my data as excepted. After I retrieve my data, I am posting it by using otto bus and the code can be seen below.
#Subscribe
public void loadBrothers(ServiceCalls.SearchBrothersRequest request) {
final ServiceCalls.SearchBrothersResponse response = new ServiceCalls.SearchBrothersResponse();
response.Brothers = new ArrayList<>();
Firebase reference = new Firebase("my data's url here");
reference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int index = 0;
for (DataSnapshot brotherSnapchat : dataSnapshot.getChildren()) {
BrotherFireBase bro = brotherSnapchat.getValue(BrotherFireBase.class);
Log.i(LOG_TAG, bro.getName());
Log.i(LOG_TAG, bro.getWhy());
Log.i(LOG_TAG, bro.getPicture());
Log.i(LOG_TAG, bro.getMajor());
Log.i(LOG_TAG, bro.getCross());
Log.i(LOG_TAG, bro.getFact());
Brother brother = new Brother(
index,
bro.getName(),
bro.getWhy(),
bro.getPicture(),
bro.getMajor(),
bro.getCross(),
bro.getFact());
response.Brothers.add(brother);
index++;
}
bus.post(response);
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
Once the data is in my RecyclerView, I am to click an item and it's respective activity is to pop up in a custom activity dialog. However, since the activity is a dialog, you can see the RecyclerView reloading in the background. This does not happen when I do not retrieve the data from the internet. After a few clicks around, the app crashes due to an out of memory exception. Is there something I am missing?
Here is the activity where the recyclerView is found:
#Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_meet_a_brother, container, false);
adapter = new BrotherRecycleAdapter((BaseActivity) getActivity(),this);
brothers = adapter.getBrothers();
recyclerView =(RecyclerView) view.findViewById(R.id.fragment_meet_a_brother_recycleView);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(),3));
setUpAdapter();
bus.post(new ServiceCalls.SearchBrothersRequest("Hello"));
return view;
}
private void setUpAdapter(){
if(isAdded()){
recyclerView.setAdapter(adapter);
}
}
#Subscribe
public void onBrosLoaded(final ServiceCalls.SearchBrothersResponse response){
int oldBrotherLength = brothers.size();
brothers.clear();
adapter.notifyItemRangeRemoved(0, oldBrotherLength);
brothers.addAll(response.Brothers);
//Delete for Debug method...
adapter.notifyItemRangeChanged(0,brothers.size());
Log.i(LOG_TAG, Integer.toString(brothers.size()));
}
#Override
public void onBrotherClicked(Brother brother) {
Intent intent = BrotherPagerActivity.newIntent(getActivity(),brother);
Log.i(LOG_TAG,brother.getBrotherName() + " was Clicked");
startActivity(intent);
}
Just in case, here is also the activity that is started when a list item is clicked, it is a viewPager activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_brother_pager);
brothers = new ArrayList<>();
bus.post(new ServiceCalls.SearchBrothersRequest("Hello"));
FragmentManager fragmentManager = getSupportFragmentManager();
viewPager = (ViewPager) findViewById(R.id.activity_brother_viewPager);
viewPager.setAdapter(new FragmentStatePagerAdapter(fragmentManager) {
#Override
public Fragment getItem(int position) {
Brother brother = brothers.get(position);
return BrotherDetailsFragment.newInstance(brother);
}
#Override
public int getCount() {
return brothers.size();
}
});
}
#Subscribe
public void onBrosLoad(final ServiceCalls.SearchBrothersResponse response){
brothers.clear();
brothers.addAll(response.Brothers);
viewPager.getAdapter().notifyDataSetChanged();
Brother brother = getIntent().getParcelableExtra(BROTHER_EXTRA_INFO);
int brotherId = brother.getBrotherId();
for(int i=0;i<brothers.size();i++){
if(brothers.get(i).getBrotherId() == brotherId){
viewPager.setCurrentItem(i);
break;
}
}
Log.i(LOG_TAG, Integer.toString(brothers.size()));
}
public static Intent newIntent(Context context, Brother brother){
Intent intent = new Intent(context,BrotherPagerActivity.class);
intent.putExtra(BROTHER_EXTRA_INFO,brother);
return intent;
}
Any help is greatly appreciated thank you!
in public void onBrotherClicked(Brother brother) where RecyclerView resides, you call:
Intent intent = BrotherPagerActivity.newIntent(getActivity(),brother);
which will call
Intent intent = new Intent(context,BrotherPagerActivity.class);`
in newIntent of your viewPager activity.
This could be a recursive call.
try adding:
public static Intent newIntent(Context context, Brother brother){
Intent intent = new Intent(context,BrotherPagerActivity.class);
intent.putExtra(BROTHER_EXTRA_INFO,brother);
return intent;
}
in Activity where your RecyclerView resides. And call your ViewPage activity there.
-- UPDATE --
Call your viewpager activity (which is used to show Brother data) with the following code:
private void showBrotherData(Brother brother){
Intent intent = new Intent(this, BrotherPagerActivity.class);
intent.putExtra(BROTHER_EXTRA_INFO, brother);
this.startActivity(intent);
}
I found the answer! I changed my recyclerView to only updated if the size of the array was zero.
#Subscribe
public void onBrosLoaded(final ServiceCalls.SearchBrothersResponse response){
int oldBrotherLength = brothers.size();
Log.i(LOG_TAG, "Brother lists old size" + Integer.toString(oldBrotherLength));
if(oldBrotherLength ==0){
brothers.clear();
adapter.notifyItemRangeRemoved(0, oldBrotherLength);
brothers.addAll(response.Brothers);
//Delete for Debug method...
adapter.notifyItemRangeChanged(0,brothers.size());
} else{
return;
}
Log.i(LOG_TAG, Integer.toString(brothers.size()));
}
I don't know how good this solution is in terms of cleaness but it works for me. I hope this helps someone.

Categories

Resources