How to update textview in activity from fragment's recyclerview ViewHolder class - android

I have a problem in updating textview in activity class whenever recyclerview item is deleted from it. getActivity() is not available here. Thanx in advance guys.
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView delete_from_cart;
public ViewHolder(final View itemView) {
super(itemView);
delete_from_cart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// here I want to change the textview
DatabaseHelper dh = new DatabaseHelper(context);
dh.deleteCartDetail(product_name.getText().toString());
delete(getLayoutPosition());
}
});
}
}

There can be different ways to implement this. Below are some.
Use interface callbacks, which will be passed in constructor of that Adapter class. (Best for your requirement.)
Pass activity reference in Adapter class, and call activity method to update textview. Like activity.updateText();
You can use EventBus. That can communicate in all over your app.

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{
public interface MyCallback{
public void updateText(String text);
}
final private MyCallback callback;
public MyAdapter(MyCallback callback){
this.callback = callback;
}
... Some Other code
delete_from_cart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Do other stuff
callback.updateText("some text");
}
});
}
public class MyActivity extends Activity implements MyCallback{
#Override
public void updateText(String someText){
myTextView.setText(someText);
}
}

Related

Calling Fragment method from attached RecyclerView.Adapter

I recently started coding my first Android project using Android Studio 3.1.2 and SDK 19.
One of my fragments contains a RecyclerView with a custom RecyclerView.Adapter attached. On the CardView the Adapter gets by its ViewHolder, there can be a button. The target is, if the button is pressed, a method of my fragment should be called, though it's an instance of a custom subclass of Fragment:
From RequestingFragment:
public abstract class RequestingFragment extends Fragment implements RequestCallbacks {
public final static void startRequest(final RequestOperation, String param) {
//this is the guy i want to call
}
//these are the RequestCallbacks, they're all getting called in startRequest()
public void onSuccess(JSONObject json, String parsingkey) { }
public void onError() { }
public void onFinished() { }
Now one of my RequestingFragments contains a RecyclerView, on which a custom ErrorCompactAdapter is attached. Inside the Adapters ViewHolder, where I load the layout for the single CardViews, there's a button, which should call startRequest() onClick from my RequestingFragment
From ErrorCompactAdapter:
public class ErrorCompactAdapter extends RecyclerView.Adapter<ErrorCompactAdapter.ErrorCompactViewHolder> {
private Context context;
private ArrayList<Error> errors;
public ErrorCompactAdapter(Context context, ArrayList<Error> errors) {
this.context = context;
this.errors = errors;
}
public void onBindViewHolder(ErrorCompactViewHolder, int position) {
//...
holder.errorTakeOverButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//here's were i'm stuck
}
});
//...
}
}
My first approach was to change the context attribute of ErrorCompactAdapter to a RequestingFragment, so that I can call startRequest() on this.
private Context context; // private RequestingFragment attacher;
public void onClick(View v) {
attacher.startRequest(/*params*/);
}
But i'm very unsure, if the fragment that contains the RecyclerView will be the one which receives the response of the request, or if a somehow "pseudo-anonymous" Fragment will receive the response and simply does nothing with it then. Can someone enlight me, if this is the correct path? Thanks in advance.
Pass the Fragment in you ErrorCompactAdapter class's constructor. This works for me the way I want. I had the same issue.
RequestingFragment mFragment;
public ErrorCompactAdapter(Context context, ArrayList<Error> errors,
RequestingFragment fragment)
{
this.context = context;
this.errors = errors;
this.mFragment = fragment;
}
// While passing the fragment into your adapter, do it this way.
ErrorCompactAdapter errorCompactAdapter = new ErrorCompactAdapter(
context, errors, RequestingFragment.this);
holder.errorTakeOverButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// use you method of fragment here
mFragment.startRequest();
}
});

Recycler View onClick

I have an activity that creates a tab layout inside of it. The layout contains two fragments. The first fragment has a recycler view. Each card in the recycler view has a check box and a string.
If I click on the checkbox I want to send this card's string to a List located in the activity so I can populate it onto the second tab fragment.
On the first fragment cards I have an on click that sets boolean to true which is saved on an object. I am trying to figure out how to grab this object when it is clicked and send it to the activities list.
Activity-
public class MainActivity extends AppCompatActivity {
public static List toSendList = new ArrayList();
...more code
}
Recycler Adapter-
//initialize variables...
CheckBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (CheckBox.isChecked()) {
//MainActivity.toSendList.add(Obj);
obj.setIsChecked(true);
}
}
});
... more code
You might try EventBus and see if you like it. With it, you define an
'event' which can also be the object that you want to pass to your activity (or an event which wraps it). In the receiving activities, add your Subcribers. You then pass events/objects by calling
EventBus.getDefault().post(new CustomEvent());
and any place where a Subcriber is still attached will receive the event.
You can implement a listener which you will use on the Activity. For example:
You create a interface for a click listener.
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.PhotoHolder> {
// ... all the code
public interface RecyclerViewOnClickListener(/* same arguments as above */);
}
On your view holder.
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public ViewHolder(View v) {
super(v);
// ... do all the initialization
v.setOnClickListener(this);
}
#Override
public void onClick(View v) {
mOnClickListener(int position /* or whatever argument you like */)
}
}
On your RecyclerAdapter you store a listener for the click. So the adapter would end up with more code:
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.PhotoHolder> {
// ... all the code
public interface RecyclerViewOnClickListener(/* same arguments as above */);
public RecyclerAdapter(RecyclerViewOnClickListener onClickListener) {
mOnClickListener = onClickListener;
}
}
So finally, in your Activity you just instantiate the RecyclerViewOnClickListener and pass it as an argument for the adapter.
try this :
Activity-
public class MainActivity extends AppCompatActivity {
public static List toSendList = new ArrayList();
...more code
public setPassData(String string)
{
//do something with this string
}
}
Fragment A/B
public void setPassData(String string)
{
((ActivityName)getActivity()).setPassData(string);
}
Recycler Adapter-
//initialize variables...
CheckBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (CheckBox.isChecked()) {
//MainActivity.toSendList.add(Obj);
obj.setIsChecked(true);
((FragmentName)mContext).setPassData(SomeStringToPass);
}
}
});

How to make another activity implement listener

I simplified my code for you to get better understanding it.
I have MyAdapter and MyActivity working both perfectly.
class MyAdapter extends RecyclerView... {
...
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
...
holder.mImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((Listener) context).onSelected(object);
}
});
}
...
}
class MyActivity implements MyAdapter.Listener {
...
#Override
public void onSelected(Object object) {
// do things with object here
}
...
}
I want to make my another activity MyAnotherActivity implement MyAdapter.Listener.
When I run my app, and click on my object, an overriden onSelected() just ignored.
public class MyAnotherActivity implements MyAdapter.Listener {
...
#Override
public void onSelected(Object object) {
Log.e("MyAnotherActivity", "This text doesn't shows");
}
...
}
The used Listener implementation depends on the context parameter passed to MyAdapter constructor. Because on this line ((Listener) context).onSelected(object); you are casting the context field of the MyAdapter class to Listener implementation.
So when you are calling the constructor of the MyAdapter, you need to pass the context of MyAnotherActivity.
public class MyAnotherActivity implements MyAdapter.Listener {
#Override
protected void onCreate(Bundle savedInstanceState) {
...
MyAdapter adapter = new MyAdapter(this /*Context of MyAnotherActivity*/, ...);
...
}
}
If you want to implement any methods inside of any class (not just activity) , you can use EventBus, a lightweight library for passing messages and events around.
It's very easy to implement and the code samples will help you out along the way
http://greenrobot.org/eventbus/

adapter-like pattern for not AdapterView class

I need to transmit data from my activity layer to a view (or at least its fragment) that is not a child of AdapterView.
For a ListView, I could do this very easily with its adapter, but I am stuck on how to reproduce this behavior for a non AdapterView widget (for clarity, let's say a TextView).
I don't want to keep a reference to my fragment (or worse, the view) at Activity level.
Any ideas ?
One way to do this is to use java.util.Observable/Observer :
import java.util.Observable;
import java.util.Observer;
public class MyTextView extends View implements Observer{
#Override
public void update(Observable observable, Object data) {
this.setText((String)data);
}
}
Then, you need an Observable class :
import java.util.Observable;
public class MyObservable extends Observable {
public void setText(String text){
notifyObservers(text);
}
}
Activity :
public class MainActivity extends Activity {
TextView tv;
#Override
public void onCreate(Bundle savedInstanceState) {
...
MyObservable mtv = new MyTextView(getApplicationContext());
MyTextViewModel mm = new MyTextViewModel(10);
mm.addObserver(mtv);
mm.setText("test");
// demonstrated in an activity to shorten the sample, but ideally you would
// keep the observer at activity level and manage the view in the fragment
}
}
------------------------------------------------
Another way to do this is through android.database.DataSetObservable to implement a more traditional Adapter like object :
public class CustomAdapter extends DataSetObservable {
String mText;
public String getText() {
return mText;
}
public void setText(String text) {
mText = text;
}
}
You manipulate it like any other adapter at Activity level :
public class MyActivity extends Activity {
private CustomAdapter mCustomAdapter;
#Override
protected void onCreate() {
...
mCustomAdapter = new CustomAdapter();
}
private void initializeFragment (Fragment fragment) {
// this or whatever method you use to setup your fragments
((MyFragment) fragment).setCustomAdapter(mCustomAdapter);
}
private void onDataLoaded (Stg data) {
// callback method invoked when the network thread has finished loading data
mCustomAdapter.setText(data.text);
mCustomAdapter.notifyChanged();
}
Finally, the only thing missing is the link between your fragment and the view :
public class MyFragment extends Fragment {
private CustomAdapter mCustomAdapter;
public setCustomAdapter(CustomAdapter adapter) {
// this method allows to setup the adapter at startup
mCustomAdapter = adapter;
}
protected DataSetObserver mMyViewObserver = new MyObserver();
private class MyObserver extends DataSetObserver {
#Override
public void onChanged() {
mUpdateHandler.sendEmptyMessage(0);
}
}
private Handler mUpdateHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
updateMyView();
}
};
private void updateMyView() {
if (mView == null) {
return;
}
mView.setMainTextViewText(mCustomAdapter.getText());
}
}
And here you have it. Each time you call notifyChanged(), your observer gets called. In return, he invokes the handler that update the view.
Here you have it, leak free, thread safe custom adapter for any kind of view.

how to call button on clickListner outside the custom adapter of listview.

I have a Button on Listview and a custom adapter that loads the ListView. I want to call the Button onClickListner in main class not in the adapter class. how can i do this.
You can create one Global Interface
Like this
package com.radiofrance.interfaces;
public abstract class GlobalInterface implements eventInterface {
public void onClick(int values) {
}
public void onCancel() {
}
}
Then Implement this interface in Your Activity from which you call your adapter
public class SampleClickListener extends GlobalInterface {
#Override
public void onClick(final int values, final boolean state) {
}
}
now in your adapter pass this object of interface
Adapter adt = new Adpater(this, R.layout.row, arrRow,
new SampleClickListener());
and from your adapter call
listner.onClick(position, false);
Thanks

Categories

Resources