I'm a beginner in android how can i pass the data from alert dialog to recyclerview adapter because i cannot able to find the topic in internet or in stackoverflow
An alert dialog is basically just an activity with a change to the AndroidManifest.xml so if you can create an activity and edit the theme in the manifest to something like this:
<activity
android:name=".DialogActivity"
android:label="#string/title_activity_dialog"
android:theme="#style/Theme.AppCompat.Dialog.Alert" />
You can treat the activity as any normal activity and add whatever you want from it to a recyclerview adapter. It would be helpful if you can share some of what you have attempted to better get an idea however.
You need a callback. An interface will be implemented on the recyclerview host. Then the DialogFragment will use the life cycle to obtained the interface.
Interface Callback {
void passData(YourObject object);
}
ActivityOrFragment extenda WHATEVER implements Callback {
#Override
void passData(YourObject object){adapter.addData(object);}
//you have to create the method in the adapter and uodate usibg notify data set change or something suitable
}
YourDialogFragment extends DialogFragment {
private Callback callback;
//If the recycler is in an activity
#Override
onAttach(Context contex){
callback = (Callback) context;
}
//If the recycler is in a fragment
#Override
onViewCreated(...){
//find the fragment and initialize the callback
callback = getFragmentManager...
}
}
The user probably interact with the dialog so once thar interqction is done use the callback
callback.passData(userCreatedObject);
Related
I'm developing a chat application. There are chatrooms and inside these rooms there are messages. When a user clicks on the chatroom I want to go to another activity where messages are displayed.
In my adapter class, I have this onclick() method written in onBindViewHolder where I would normally make an intent along with the data I need. Something like this:
#Override
public void onBindViewHolder(#NonNull ChatRoomAdapter.ChatRoomViewHolder holder, final int position) {
holder.mRoomTitle.setText(mChatRooms.get(position).getTitle());
holder.mRoomDescription.setText(mChatRooms.get(position).getDescription());
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(this, NextActivity.java);
intent.putExtra("test", mChatRooms.get(position).getTitle());
}
});
}
But I'm trying the MVP architecture design and I want to pass roomTitle to the Interactor/presenter class of my next activity. How can I achieve this?
In RecyclerView adapter you need to pass a onItemClickListener in the adapter.
Refer to the Google's MVP sample - > https://github.com/googlesamples/android-architecture/tree/todo-mvp/
Especially refer the TaskItemListener in TaskFragment. They are doing the same thing what you are trying to achieve. In this they open Task details (new activity) from List of tasks(recyclervView).
/**
* Listener for clicks on tasks in the ListView.
*/
TaskItemListener mItemListener = new TaskItemListener() {
#Override
public void onTaskClick(Task clickedTask) {
mPresenter.openTaskDetails(clickedTask);
}
#Override
public void onCompleteTaskClick(Task completedTask) {
mPresenter.completeTask(completedTask);
}
#Override
public void onActivateTaskClick(Task activatedTask) {
mPresenter.activateTask(activatedTask);
}
};
And then pass it to adapter of Recycler view
mListAdapter = new TasksAdapter(new ArrayList<Task>(0), mItemListener);
And on item click
rowView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mItemListener.onTaskClick(task);
}
});
Follow this article to know more about MVP.
You can do one thing that creates a method in the next activity's presenter
setRoomTitle(String roomTitle);
Whenever, you click and send intent and get in next Activity call that
mPresenter.setRoomTitle(roomTitle);
Is it make sense? So, you can sent your title or other data in next activity's presenter.
Let me know if you have more query then.
Thanks.
Happy coding :)
The adapter is only responsible for binding the view and the data together. Your business logic should go into the controller class which is your Activity or Fragment containing the RecyclerView. This way you can reuse it for any other Activity, and it also makes debugging/maintaining a lot easier since you know that your logic code is in one place.
But how do you link both together? It's simply done by implementing a callback interface and passing it to your adapter. A callback interface could be something like this:
interface OnClickCallback{
void onClick(String title);
}
Just add a member variable to your adapter class called mCallback for example and affect a reference to it through the adapter constructor or through a setter method.
You can either make your Activity implement this interface and pass itself as the reference or you can instantiate it in an object and pass it instead.
Then just write this:
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mCallback.onClick(mChatRooms.get(position).getTitle());
}
});
The onClick method should create an intent to your new Activity with an extra containing the title. In your new Activity's onCreate method, you can retrieve the title value by using:
String title = getIntent().getStringExtra(YOUR_TITLE_KEY_HERE);
Im trying to figure a way how to call an activity that an adapter has started. Is there a way to get the instance of the activity from startactivity and make a method call into the activity ?
I'ved got an adapter that has a list
public class LanguageDownloadRVAdapter extends RecyclerView.Adapter<LanguageDownloadRVAdapter.DownloadViewHolder>{
And in this adapter, it starts a particular activity called MainActivity
context.startActivity(new Intent(context, MainActivity.class));
((Activity)context).finish();
Here is the MainActivity that it starts
public class MainActivity extends AppCompatActivity implements IabBroadcastListener{
How can I make a call from the adapter to a method in the MainActivity. (im just trying to perform inapp purchase which is implemented in the MainActivity). so how can i do something like this.
mainactivity.perform_inapp_purchase();
Try to use EventBus for passing data between activity and list adapter. You can do it in the same way for passing data between activity and fragment.
This work the same way as storing data in global variable (in a fancier way)
In the adapter:
Add a new Field private Context mContext;
In the adapter Constructor add one more parameter as below, and assign it into class level variable:
public LanguageDownloadRVAdapter(......,Context context){
//your code.
this.mContext=context;
}
In the Adapter where you want to call Activity's perform_inapp_purchase() method:
if(mContext instanceof MainActivity){
((MainActivity) mContext).perform_inapp_purchase();
}
More Generalized Approach:
If you need to use this same adapter for more than one activity then :
Create an Interface
public interface InAppPerchaceInterface{
void perform_inapp_purchase();
}
Implement this interface in activities
Then in Adapter, call like below:
if(mContext instanceof InAppPerchaceInterface){
((InAppPerchaceInterface) mContext).perform_inapp_purchase();
}
You can store the instance in the application class, but you should be careful about the memory leaks.
In the onCreate of your activity
protected void onCreate(Bundle savedInstanceState)
{
// get the instance using this and store it in the application class or in the place that you want to call from it
}
From where will you call your method?
I didn't understand the situation.
Here is what I would like to do:
1) Inside an Activity a dialog is shown. I use DialogFragment and FragmentManager for this, by calling:
dialogFragment.show(fragmentManager, "edit_task_list");
2) Inside the Dialog I have layout with a custom Button. I would like to perform some action when the button is clicked and later close the dialog.
How should I connect everything? I see two options:
1) onclick attribute in the Button and a method inside the Actvity. That was my original plan, but I don't how to get the Dialog from the Activity to dismiss it. Even if this is not the right way, how could this be done? I would like to understand how this works.
2) set on click listener on the button when the Dialog is created in DialogFragment. This will require me to pass some context from the Activity to the DialogFragment, so I would like to avoid it (and keep the DialogFragment as simple as possible).
Which of those options should I take?
Number 2 Doesn't require you to pass any context (and you shouldn't). You define an interface that can act as a contract between fragments and activities and make your activity implement it.
From your dialog and in your button.onClick(), you do something like this (untested code):
if ( getActivity() != null
&& !getActivity().finishing()
&& getActivity() instanceOf YourInterface) {
((YourInterface)getActivity()).onSomeNiceMethod();
dismiss(); // close the dialog (if this is what you want).
}
The interface looks like:
public interface YourInterface {
void onSomeNiceMethod();
}
And your Activity…
public class YourActivity implements YourInterface {
void onSomeNiceMethod() {
// Hey! The Button In The Dialog Has Been Pressed!
}
}
All Activity and Fragment classes have a built-in callback method for you to use when you start another Activity, Fragment, Dialog, or DialogFragment.
void onActivityResult(int requestCode, int resultCode, Intent data)
Since you want to start the Dialog from an Activity, using the Dialog class is better than the DialogFragment class. The latter is better for starting a dialog from a Fragment, because it has two methods for communicating back to the Fragment (get/set TargetFragment())
The Dialog class has the getOwnerActivity() method. This is the Activity you use when creating the Dialog with one of its constructors.
You set a onClickListener on the button in the Dialog class. To pass the result back to the Activity:
getOwnerActivity().onActivityResult(intIdentifyingme, Activity.RESULT_OK,
intent);
dismiss(); // close the dialog
You put additional info you want to send in an Intent.
1) onclick attribute in the Button and a method inside the Actvity.
That was my original plan, but I don't how to get the Dialog from the
Activity to dismiss it. Even if this is not the right way, how could
this be done? I would like to understand how this works.
Basically your Activity has to remember/know which dialog is active at the moment with something like curDialog=dialogFragment;, then when handling the button onclick action you'll know which dialog to dismiss. But this is really not a good idea since basically the Button View would "leak" from your DialogFragment to your Activity, which breaks object encapsulation.
2) set on click listener on the button when the Dialog is created in
DialogFragment. This will require me to pass some context from the
Activity to the DialogFragment, so I would like to avoid it (and keep
the DialogFragment as simple as possible).
As a previous answer mentioned, you don't need to pass any Context to it, especially since you can get the Activity by calling getActivity().
The solution depends on whether or not this dialog would be used by multiple Activities:
Used by a single Activity: #Martin's solution will work just fine
Used by multiple Activity: abstraction can be used such that only the user's decision is passed to a listener. This is a (modified) solution I came up for the same problem:
public class BaseDialogFragment extends DialogFragment {
protected TextView dialogEn;
protected Button dialogYes;
private Button dialogNo;
protected OnSelectListener listener;
public interface OnSelectListener {
public void onSelect(int type, boolean yes);
}
public void setOnSelectListener(OnSelectListener listener) {
this.listener = listener;
}
public BaseDialogFragment() {
super();
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.dialog_confirm, container, false);
dialogYes = (Button) v.findViewById(R.id.yes);
dialogNo = (Button) v.findViewById(R.id.no);
dialogEn = (TextView) view.findViewById(R.id.dialog_en);
dialogEn.setText(getArguments().getString("text_en"));
dialogYes.setOnClickListener(this);
dialogNo.setOnClickListener(this);
return v;
}
public void onClick(View v) {
if (listener != null) {
listener.onSelect(getArguments().getInt("type"),
v == dialogYes ? true : false);
}
getDialog().dismiss();
}
}
To use it some additional info needs to be provided:
Bundle bundle = new Bundle();
bundle.putInt("type", type); //type: an unique integer value that helps differentiate result from different dialogs
bundle.putString("text_en", en); //en: String to be displayed
dialog.setArguments(bundle);
dialog.setOnSelectListener(this);
So if the type value above is set to 115, then a dialogYes button click would trigger public void onSelect(int type, boolean yes) method to be called with 115 and true as the 1st & 2nd parameters.
Your first point about the onClick attribute in the xml should be avoided. Because handling a Dialog that way could be really painfull if you respect events like screen rotation or a setup with multiple dialogs. This leads into leaked window errors most of the time and needs unnecessary code overhead to avoid this. Because you have to keep track of the Dialog which is actually shown yourself.
To be able to dismiss the Dialog this way you can use the Tag you setted as you called dialogFragment.show(fragmentManager, "edit_task_list");
DialogFragment frag = (DialogFragment)getFragmentManager().findFragmentByTag("edit_task_list");
if(frag != null)
frag.dismiss();
The proper solution is to use an interface as a callback for the communication between the DialogFragment and the Activity. This keeps the Dialog modular and the code easy. Here is an example from the docs. For this you don't need a Context. You simply pass the interface to the dialog in the onAttach() callback. It has a reference of the Activity as a parameter, which called that Dialog.
// Example interface for the communication
public interface OnArticleSelectedListener {
public void onButtonClicked(/*any Parameters*/);
}
public static class FragmentA extends DialogFragment {
OnArticleSelectedListener mListener;
...
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnArticleSelectedListener) activity; // get the interface of the Activity
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnArticleSelectedListener");
}
}
...
}
Handle the Button click in the Dialog and call dismiss() in it, that the Dialog can dismiss itself. Have a look at this question why to use dismiss() instead of getDialog().dismiss().
yourButton.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v){
if(mListener != null) // check if the listener is still valid
mListener.onButtonClicked(...); // calls the Activity implementation of this callback
dismiss(); // dismiss the Dialog
}
});
In onPause() of the Dialog set the reference of the interface to null. This way you can be sure that the callback will only be used if the Dialog is showing.
Your Activity looks something like this to be able to handle the callback:
public class MyActivity extends Activity implements OnArticleSelectedListener{
...
#Override
public void onButtonClicked(...){
// your implementation here
}
}
I don't know your overall setup but if you would use an AlertDialog a click on the Buttons dismiss the Dialog automatically when the method returns.
I've created an Activity that contains a ViewPager with n number of Fragments. I have also added a Previous, Next and Finish buttons. Fragments are either multiple choice ListViews or just a single answer type.
How should I get the data from each fragment when the user hits Finish? Should I get each answer on the onPageSelected event from the ViewPager?
Communications between a Fragment and the activity that contains it is done via Interfaces.
The fragment should expose an interface listener and the activity should implement it and get notified by the fragment once an event happens.
You can use my example, and you can also change so the activity doesn't implement, but you can create the listener in run time anonymously (like you do for buttons on click listener many times).
class MyFragment {
// Container Activity must implement this interface
public interface OnNextPageListener {
public void onNextPageSelected(String DataString);
}
// define listener in fragment
OnNextPageListener mNextPageListener;
.... class code
#Override
public void onAttach(Activity activity) {
try {
mNextPageListener = (OnNextPageListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnNextPageListener");
}
.... class code...
...button press onclick listener method...
mNextPageListener.onNextPageSelected("My Name is Slim Shaddy");
}
class MainActivity extends Activity implements MyFragment.OnNextPageListener
public void onNextPageSelected(String StringData) {
}
...
read more here http://developer.android.com/training/basics/fragments/communicating.html
Either way I suggest you do this when someone pressed the button in the fragment, or hooking the ViewPager.OnPageChangeListener, starting the saving the data on onPageScrollStateChanged and completing it on the OnPageSelected so you ensure you have the data even if the fragment is not available anymore.
I'm converting some of my project to use fragments. How do we communicate with a fragment dialog? I want to create a fragment dialog just to get some text input from the user. When the dialog is dismissed, I'd like to pass the entered text back to the "parent" fragment (the one that started it). Example:
public class MyFragment extends Fragment {
public void onBtnClick() {
// What's a good way to get data back from this dialog
// once it's dismissed?
DialogFragment dlgFrag = MyFragmentDialog.newInstance();
dlgFrag.show(getFragmentManager(), "dialog");
}
}
Thanks
As eternalmatt said the given solution does not really answer the question. The way to communicate the dialog with the fragment is calling:
dialog.setTargetFragment(myCallingFragment, requestCode);
The way I do this is by creating the FragmentDialog with an static method where the listener is instanciated an then do the setFragmentTarget() stuff:
public mySuperFragmentDialog extends DialogFragment {
public interface SuperListener{
void onSomethingHappened();
}
public static mySuperFragmentDialog newInstance(SuperListener listener){
MySuperFagmentDialog f = new MySuperFragmentDialog();
f.setTargetFragment((Fragment) listener, /*requestCode*/ 1234);
return f;
}
}
To create the dialog from the fragment just do as usual:
Dialog dialog = MySuperFragmentDialog.newInstance(parentFragment);
dialog.show();
Then when you want to comunicate with the fragment which calls the dialog just:
Fragment parentFragment = getTargetFragment();
((SuperListener) parentFragment).onSomethingHappened();
This solution works only when dialog is gonna be created from Fragments and not from Activities, but you can combine both methods ('setFragmentTarget()' and the 'onAttach()' one) plus some Class checks to provide a full solution.
A great way to pass this kind of Events is a Callback Interface like descripted in the Android Developers Guide
Your Fragment define a Callback Interface like
public class MyFragment extends Fragment {
...
// Container Activity must implement this interface
public interface OnArticleSelectedListener {
public void onArticleSelected(Uri articleUri);
}
...
}
Then you check inside your onAttach Method if the Parent implemented the Callback Interface and save the Instance.
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnArticleSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
}
}
when your Event inside the Fragment happens you simply call the Callback Handler
mListener.onArticleSelected(...);
Hope that helps, further infos here
I had this problem once and after I solved it, I created a project that would remind me how I did it. I put the project on github so anyone can see the solution. Here is the link: https://github.com/mumasaba/FragmentFragmentBoss
In this project, we have a simple app with a TextView displaying the words 'Hello World'. This text view is on a fragment which is hosted by the main app activity. This fragment needs to display a new word that the user can enter after they click on the add options menu icon. When clicked, the options menu item calls up a dialog allowing the user to type in their new word. After the user is done, they can click ok to dismiss the dialog and display their new input on the fragment's text view. Therefore, Fragment to DialogFragment communication is illustrated.
There is a new pattern possible which is to share a ViewModel instance between fragments. When instantiating a ViewModelFactory where to get your ViewModels, you have to specify a context as parameter. If the context is the same for both fragments (i.e: the parent activity or parent fragment) and you instantiate the same ViewModel from both fragments, you will get the same instance.
This opens a new range of possibilities but also challenges.