Creating Multiple event callbacks from fragment to the activity - android

I was able to create a single event callback from a fragment to the activity. However, I have problem with creating two event callbacks from the same fragment.
Basically, I have a button on the fragment1 layout, when click on it, it will execute something in mainactivity, and then, it changes hide the Button at fragment1 layout, and then I need to send a Boolean from the fragment to activity, then initiate fragment2.
How can I implement the 2nd callback interface in the mainacativity.
Here is my code:
at Fragment1:
public class Fragment1 extends Fragment{
private static final String TAG = "Fragment1";
Boolean in1, in2;
Button btn1;
ListenerA mListenerA;
public interface ListenerA{
public void methodA(Boolean in1);
};
ListenerB mListenerB;
public interface ListenerB{
public void methodB(Boolean in2);
};
#Override
public void onAttach(Context context) {
super.onAttach(context);
if(context instanceof ListenerA)
mListenerA = (ListenerA)context;
if(context instanceof ListenerB)
mListenerB = (ListenerB)context;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View myView = inflater.inflate(R.layout.fragment1, container, false);
btn1 = (Button) myView.findViewById(R.id.btn1_ID);
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mListenerA.methodA(true);
}
});
return myView;
}
public void showBtnMethod (Boolean showBtn){
if (showBtn==false) {
btn1.setVisibility(View.INVISIBLE);
mListenerB.methodB(true); //***** problematic line
}
}
}
and the code in the main activity is below. please note that on the first line I was able only to implement one method from the fragment.
public class MainActivity extends AppCompatActivity implements Fragment1.ListenerA {
private static final String TAG = "MainActivity";
public Fragment1 mFragment1;
public Fragment2 mFragment2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
FragmentTransaction transaction1 = getSupportFragmentManager().beginTransaction();
mFragment1 = new Fragment1();
transaction1.replace(R.id.content_fragment_ID, mFragment1);
transaction1.commit();
}
}
// this gets called by ListenerA when click on the button
public void methodA(Boolean in){
if (in==true){
Toast.makeText(MainActivity.this, "mMethodA Executed", Toast.LENGTH_SHORT).show();
triggerShowMethod();
}
};
private void triggerShowMethod(){
mFragment1.showBtnMethod(false);
};
// Problematic section is below
public void methodB(Boolean in){
if (in==true){
FragmentTransaction transaction2 = getSupportFragmentManager().beginTransaction();
mFragment2 = new Fragment2();
transaction2.replace(R.id.content_fragment_ID, mFragment2);
transaction2.commit();
Toast.makeText(MainActivity.this, "mMethodB Executed", Toast.LENGTH_LONG).show();
}
};
}

You can simply consolidate both interfaces into one:
public interface Listener{
public void methodA(Boolean in1);
public void methodB(Boolean in2);
};
and in your MainActivity:
public class MainActivity extends AppCompatActivity implements Fragment1.Listener

Your activity doesn't implement ListenerB.
public class MainActivity extends AppCompatActivity implements Fragment1.ListenerA, Fragment1.ListenerB {
}

Related

how to change fragment views programmatically from the parent activity

I am having a fragment that contains for example one button, I want to allow the Activity containing the fragment to change this button view like for example color and title or src Image.
What's the best way to do that ?
Update : sorry If I wasn't clear enough but I want the activity to change the whole view as it's likes , like setting the padding, the color or anything.
It will create the view programmatically and the fragment should replace the old view by the new one and change the view's ID so that the fragment code isn't affected. And If i created methods in the fragment that takes these views when should the Main activity call them ? since the activity has to wait for the layout of the fragment to be created.
1. You must get you fragment from your activity
val fragment = supportFragmentManager.findFragmentByTag("tag")
or
val fragment = supportFragmentManager.findFragmentById(R.id.fragment)
2. Create a method that will do what you wants in you fragment and call this method from the activity
fragment.hideButton()
or you can use interface
Try this way according to your requirement
public abstract class BaseFragment extends Fragment {
BaseActivity yourActivity;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
yourActivity = (BaseActivity) context;
}
#Override
public void onDetach() {
yourActivity = null;
super.onDetach();
}
public void refreshview(){}
public void setDada(Data data){}
#override
publicn void onStart(){
yourActivity.setCurrentOpenedFragment(this);
}
}
Create the BaseActivity class
public abstract class BaseActivity extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void setCurrentOpenedFragment(BaseFragment currentFragment){}
}
Extends the BaseFragment in your fragment i.e.
public class YourFragment extends BaseFragment{
View view;
Button button;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment, container, false);
button = (Button)view.findViewById(R.id.button);
return view;
}
#override
publicn void onStart(){
super.onStart();
//yourActivity.setCurrentOpenedFragment(this);
}
Data data;
#override
public void setDada(Data data){
this.data = data;
}
#Override
public void refreshview() {
button.setcolor(data.getcolor());
}
}
Write the below line of code in your Activity class
public class YourActivity extends BaseActivity{
public static final byte NONE = -1;
public static final byte HOME = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_activity);
changeFragment(new YourFragment(), HOME);
initview();
}
public void initview(){
Button b = (Button)findViewById(R.id.button);
b.setOnClickListener(new OnClickListener(){
if(currentFragmentOnDrawer != null){
Data data = new Data();
data.setColor(getResource().getcolor(R.color.red));
currentFragmentOnDrawer.setDada(data);
currentFragmentOnDrawer.refreshview()
}
});
}
BaseFragment currentFragmentOnDrawer;
#Override
public void setCurrentOpenedFragment(BaseFragment currentFragment) {
super.setCurrentOpenedFragment(currentFragment);
this.currentFragmentOnDrawer = currentFragment;
}
public void changeFragment(Fragment targetFragment, byte state) {
FragmentTransaction ft = getSupportFragmentManager()
.beginTransaction();
ft.replace(R.id.main_fragment, targetFragment, "" + state);
ft.addToBackStack("" + state);
ft.commit();
}
}
Hope it will help for you

android- How to make an existing fragment implement an activity's listener?

I'm going from a Fragment -> Activity. In the activity I make an interface and when the user clicks a button I pass in a string to an interface object I create and call finish(). In the fragment I implement that interface and want to get that string. But in the activity I get a crash saying the listener is null.
public class SampleActivity extends AppCompatActivity
{
private Button button;
private MatchActivity.OnMatchCompleteListener onMatchCompleteListener;
public interface OnMatchCompleteListener
{
public void matchComplete(String matchID);
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.someButton);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onMatchCompleteListener.matchComplete("finished");
finish();
}
});
}
}
Fragment
public class SampleFragment extends Fragment implements SampleActivity.OnMatchCompleteListener{
private View rootView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_login , container, false);
return rootView;
}
#Override
public void matchComplete(String matchID) {
Log.d("TEST",matchID);
}
}
if you have your fragment in the R.layout.activity_main and your fragment id is R.id.fragment use this:
onMatchCompleteListener =
((SampleFragment)getFragmentManager().findFragmentById(R.id.fragment))
otherwise use this solution:
SampleFragment fragment = new SampleFragment();
onMatchCompleteListener = fragment;
getFragmentManager().beginTransaction().add(R.layout.activity_main, fragment, "TAG_SIMPLE").commit();

fragment callback using interface

I have an Activity that starts a Fragment. Inside that fragment i have an EditText. And when i get the text that the user types there, i want to get that from my Activity with the help of an interface. I'm using this guide
On my MainActivity i'm implementing the commentListener interface and i've managed to get the result inside the onCommentEntered method. But on doneListener, which is triggered when the user presses a button finishing the activity, i'm getting null.
Obviously onCommentEntered runs after doneListener.
Any suggestions on how to get the result on doneListener?
class MainActivity implements fragment.commentListener{
static String comment;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addtransaction);
done=(TextView)findViewById(R.id.done_button);
}
// called when user presses a button and MainActivity finishes.
public void doneListener(View v){
// Here i get NULL
System.out.println(comment);
finish();
}
#Override
public void onCommentEntered(String data) {
comment=data;
// Here i get what the user typed
System.out.println(comment);
}
}
My fragment
public class thefragment extends Fragment {
commentListener cListener;
static TextView note;
EditText comment;
public interface commentListener{
void onCommentEntered(String data);
}
public static thefragment newInstance(){
return new thefragment ();
}
public thefragment (){
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
cListener=(commentListener) context;
}
#Override
public void onDetach() {
super.onDetach();
cListener=null;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v;
v=inflater.inflate(R.layout.fragment, container, false);
comment=(EditText)v.findViewById(R.id.comment_picker);
comment.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
cListener.onCommentEntered(comment.getText().toString());
}
}
});
return v;
}
}
Create a new Interface, as well as implement the same in Fragment. create a method in the interface and override the same in Fragments. While calling the fragment from Activity create an Interface type fragment and call the interface method.
eg:
public class thefragment extends Fragment implement fragmentNofyInterface {
...
#Override
protected void notify(String txt){
mTvTxt.setText(txt);
}
.....
}
Interface Format
public interface fragmentNofyInterface {
protected void notify(String txt);
}
Activity format
class MainActivity implements fragment.commentListener{
.....
private fragmentNofyInterface mFragmentNotifier;
.........
thefragment mFragment = new thefragment();
mFragmentNotifier = (fragmentNofyInterface ) mFragment;
FragmentTransaction transaction = mFragmentMngr.beginTransaction().
add(R.id.rl_fragment_navigation_container,
mFragment);
transaction .commit();
......
//Notify the fragment when you required
mFragmentNotifier.notify("hello world");
}
Switching to addTextChangedListener and TextWatcher for my EditText, like this here,
seems to fix my problem.Now onCommentEntered method is called before doneListener and thus String commentgets whatever was typed in the EditText.Thanks everyone for helping.

Communication between Fragments in ViewPager

I'm trying to do this: http://android-er.blogspot.com/2012/06/communication-between-fragments-in.html
Except that I'm using a FragmentStatePagerAdapter
I have an Activity with two fragments(FragmentA & FragmentB)
FragmentA has an edittext and a button, FragmentB has a textview
Now all I want is that whenever I enter something in the edittext and click the button, that something will appear on my textview.
MainActivity:
public class MainActivity extends FragmentActivity {
ViewPager viewPager = null;
String TabFragmentB;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager)findViewById(R.id.pager);
FragmentManager fragmentManager = getSupportFragmentManager();
viewPager.setAdapter(new MyAdapter(fragmentManager));
}
public class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter (FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment fragment = null;
if (i == 0)
{
fragment = new FragmentA();
}
if (i == 1)
{
fragment = new FragmentB();
}
return fragment;
}
#Override
public int getCount() {
return 2;
}
}
public void setTabFragmentB(String t) {
TabFragmentB = t;
}
public String getTabFragmentB() {
return TabFragmentB;
}
}
FragmentA:
public class FragmentA extends Fragment {
EditText et;
Button bt;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fraga, container, false);
et = (EditText)v.findViewById(R.id.edit1);
bt = (Button)v.findViewById(R.id.button1);
bt.setOnClickListener(Click);
return v;
}
OnClickListener Click = new OnClickListener(){
#Override
public void onClick(View v) {
String textPassToB = et.getText().toString();
String TabOfFragmentB = ((MainActivity)getActivity()).getTabFragmentB();
FragmentB fragmentB = (FragmentB)getActivity()
.getSupportFragmentManager()
.findFragmentByTag(TabOfFragmentB);
fragmentB.updateText(textPassToB);
}
};
}
FragmentB:
public class FragmentB extends Fragment {
TextView tv;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragb, container, false);
tv = (TextView)v.findViewById(R.id.text1);
String myTag = getTag();
((MainActivity)getActivity()).setTabFragmentB(myTag);
return v;
}
public void updateText(String t){
tv.setText(t);
}
}
LogCat:
FATAL EXCEPTION: main
java.lang.NullPointerException
at lmf.sample1.FragmentA$1.onClick(FragmentA.java:43)
at android.view.View.performClick(View.java:4212)
at android.view.View$PerformClick.run(View.java:17476)
at android.os.Handler.handleCallback(Handler.java:800)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5371)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
at dalvik.system.NativeStart.main(Native Method)
Whenever I click the button on my first fragment, my app crashes. What the hell is the problem?
You could use Intents (register broadcast receiver in fragment B and send broadcasts from fragment A.
Use EventBus: https://github.com/greenrobot/EventBus. It's my favorite approach. Very convinient to use, easy communications between any components (Activity & Services, for example).
Steps to do:
First, create some class to represent event when your text changes:
public class TextChangedEvent {
public String newText;
public TextChangedEvent(String newText) {
this.newText = newText;
}
}
Then, in fragment A:
//when text changes
EventBus bus = EventBus.getDefault();
bus.post(new TextChangedEvent(newText));
in fragment B:
EventBus bus = EventBus.getDefault();
//Register to EventBus
#Override
public void onCreate(SavedInstanceState savedState) {
bus.register(this);
}
//catch Event from fragment A
public void onEvent(TextChangedEvent event) {
yourTextView.setText(event.newText);
}
Fragments have access to there parent Activity.
Therefore the simplest approach is to register a callback in the parent Activity.
Update: Submit cache added to MainActivity.
public class MainActivity extends FragmentActivity {
private OnButtonClicked mOnButtonClicked;
private String mSubmitCache;
public interface OnButtonClicked {
void submit(final String s);
}
public void setOnButtonClicked(final OnButtonClicked c) {
mOnButtonClicked = c;
// deliver cached string, if any
if (TextUtils.isEmpty(mSubmitCache) == false) {
c.submit(mSubmitCache);
}
}
public void buttonClicked(final String s) {
if (mOnButtonClicked == null) {
// if FragmentB doesn't exist jet, cache value
mSubmitCache = s;
return;
}
mOnButtonClicked.submit(s);
}
}
public class FragmentA extends Fragment implements OnClickListener {
private MainActivity mMain;
private Button mButton;
#Override public onAttach(Activity a) {
mMain = (MainActivity) a;
}
#Override public void onClick(View v) {
mMain.buttonClicked("send this to FragmentB.");
}
}
public class FragmentB extends Fragment implements MainActivity.OnButtonClicked {
private MainActivity mMain;
private TextView mTextView;
// Called when the fragment's activity has been created
// and this fragment's view hierarchy instantiated
#Override public void onActivityCreated(Bundle savedState) {
mMain = (MainActivity) getActivity();
mMain.setOnButtonClicked(this);
}
#Override void submit(final String s) {
mTextView.setText(s);
}
}
I use Mr. Rodion's solution above. But in addition, Android Studio asked me to add #Subscribe annotation before onEvent method.
Like this:
#Subscribe
public void onEvent(TextChangedEvent event) {
textView.setText(event.newText);
}
According to EventBus’ API:
Subscribers implement event handling methods (also called “subscriber methods”) that will be called when an event is posted. These are defined with the #Subscribe annotation. Please note that with EventBus 3 the method name can be chosen freely (no naming conventions like in EventBus 2).
FragmentB is not even created until you switch to it so fragmentB.updateText(textPassToB); gives you NullPointerException.
You will need to store the text from the EditText in your activity and later when (if) the FragmentB is created you will need to read value from it.

Return data from DialogFragment to MainActivity

I'm trying return a String from the DialogFragment, following this instructions https://stackoverflow.com/a/14808425/2933117 , but I only get logcat error
java.lang.ClassCastException: com.example.testinterface.MainActivity cannot be cast to com.example.testinterface.InterDialog$EditNameDialogListener
I appreciate any help or explanation of why I get an error, thanks in advance.
Here is my code:
MainActivity
public class MainActivity extends FragmentActivity {
private Button Btn;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Btn=(Button)findViewById(R.id.button1);
Btn.setOnClickListener(new View.OnClickListener(){
public void onClick (View view) {
FragmentManager fm = getSupportFragmentManager();
InterDialog pruebafragment = new InterDialog();
pruebafragment.show(fm,"MyFragment");
}
});
}
public void onFinishEditDialog (String inputText) {
Toast.makeText(this, "Hi, " + inputText, Toast.LENGTH_SHORT).show();
}
}
and DialogFragment
public class InterDialog extends DialogFragment {
public interface EditNameDialogListener {
void onFinishEditDialog(String inputText);
}
public InterDialog() {
// Empty constructor required for DialogFragment
}
EditNameDialogListener activity;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.new_layout, container);
activity = (EditNameDialogListener) getActivity();
Button button = (Button)view.findViewById(R.id.Btnreturn);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
activity.onFinishEditDialog("errorrrr");
getDialog().dismiss();
}
});
return view;
}
}
The line:
activity = (EditNameDialogListener) getActivity();
is what is breaking it. Make sure your activity implements the EditNameDialogListener interface by doing
public class MainActivity extends FragmentActivity implements EditNameDialogListener {
Hope that helps

Categories

Resources