how can i call or invoke Regular Activity class method from a fragment.
I have tried to invoke Registration class method activityFunction from fragment like below and it returns null pointer exception. below is the entire fragment class and any help would be highly appreciated. i have googled around and it has been mentioned that i have to manually assign fragment to activity and then call the method , but i sort of couldnt find a way to do that .
Any help would be highly appreciated. Below in the code i was trying to call activity method from fragment on clicking a button.
Registration media = new Registration();
media.activityFunction();
public class fragment_login extends Fragment {
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public fragment_login() {
// Required empty public constructor
}
public static fragment_login newInstance(String param1, String param2) {
fragment_login fragment = new fragment_login();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_login, container, false);
login = v.findViewById(R.id.et_email);
password = v.findViewById(R.id.et_password);
send = v.findViewById(R.id.btn_login);
return v;
}
// thats where i am trying to call clas method from fragment
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
send.setOnClickListener(new View.OnClickListener() {
Registration media = new Registration();
media.activityFunction();
}
});
}
You can use Local Broadcast Receiver to send the event from fragment to activity and do the work that you want to do from fragment. For Example
Fragment.java
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context);
Intent localIntent = new Intent(“CUSTOM_ACTION”);
intent.putExtra("key", "value");
localBroadcastManager.sendBroadcast(localIntent);
Activity.java
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive( Context context, Intent intent ) {
String data = intent.getStringExtra(“key”);
Log.d( “Received data : “, data);
}
};
register broadcast receiver in activity in onResume() and unregister in onStop().
register using below code
IntentFilter filter = new IntentFilter("CUSTOM_ACTION");
registerReceiver(receiver, filter);
unregister using below code:
localBroadcastManager.unregisterReceiver(receiver);
Note: Don't forget to use the same action as declared while sending broadcast.
You can call activity method like this, if fragment is loaded in that activity
((MainActivity)getActivity()).abcMethod();
Related
I have created a simple main fragment page with a button that calls the activity class layout and on reaching activty class ,that acitivity class call back fragment class layout on button click .
Below is the simple fragment class with a simple button that calls activity class and it works without any issue. But once Acitiviy page is opened , on clicking button to go back to fragment layout ,it crash the app every second time i click that button. any help would be highly appreciated.
with below error
java.lang.IllegalArgumentException: No view found for id 0x7f0b007d
(org.pjsip.pjsua2:id/container01) for fragment fragment_login{1bd38c1
(5a612956-fc18-4272-8230-f79e71fed06a) id=0x7f0b007d}
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:875)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:8107)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
public class fragment_login extends Fragment {
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public int Register=0;
public fragment_login() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static fragment_login newInstance(String param1, String param2) {
fragment_login fragment = new fragment_login();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_login, container, false);
send = v.findViewById(R.id.btn_login);
return v;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
send.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), MainActivity3.class);
startActivity(intent);
// i am calling Mainactivity3 class here ,which takes me to activity layout and it works
}
});
}
// below is the activity class which get called on clicking button from fragment class and here i am trying to call back fragment class , but it crash every second time i click this button.
public class MainActivity3 extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
Button send = (Button)findViewById(R.id.btn_register);
send.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// below code to get back to fragment layout works ony once after fresh loading the app and it crash every second time i click this button.
getSupportFragmentManager().beginTransaction().add(R.id.container01,new fragment_login()).commit();
}
});
Define Id 'container01' in your MainActivity XML to add fragment into container.
MainActivity XML
<!--Container for Fragments-->
<FrameLayout
android:id="#+id/contFragments"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_centerHorizontal="true"
android:layout_weight="1"
android:visibility="visible" />
I have a ListView in a Fragment that is populated when the app starts.
I put a ParcelableArrayList in a Bundle in my newInstance method, and I get it back in my OnCreateView after passing the ArrayList in the newInstance method in my Activity (which is the data read from the SQLite database).
This part works, as I display my data in my Fragment correctly.
I implemented a button that removes all data from the table, and I would now like to update my view after I cleaned the table.
The remove all button is handled in my main activity where I call my database handler to empty the table.
What is the best way to do that ? Here are the parts of the code that seem relevant to me :
My Fragment class :
public class MainFragment extends Fragment {
public static final String RECETTES_KEY = "recettes_key";
private List<Recette> mRecettes;
private ListView mListView;
public MainFragment() {
// Required empty public constructor
}
public static MainFragment newInstance(List<Recette> r) {
MainFragment fragment = new MainFragment();
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(RECETTES_KEY, (ArrayList<? extends Parcelable>) r);
fragment.setArguments(bundle);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mRecettes = getArguments().getParcelableArrayList(RECETTES_KEY);
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_main, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
configureListView();
}
// Configure ListView
private void configureListView(){
this.mListView = getView().findViewById(R.id.activity_main_list_view);
RecetteAdapter adapter = new RecetteAdapter(getContext(), mRecettes);
mListView.setAdapter(adapter);
}
}
Relevant parts from my Main acivity :
This is in my OnCreate method :
mDatabaseHandler = new DatabaseHandler(this);
mRecettes = mDatabaseHandler.readRecettes();
mDatabaseHandler.close();
This is in the method I use to show a fragment :
if (this.mMainFragment == null) this.mMainFragment = MainFragment.newInstance(mRecettes);
this.startTransactionFragment(this.mMainFragment);
Let me know if I should add more of my code, this is my first time posting :)
Lucile
In your R.layout.fragment_main, you can add an id to the root view, say with android:id#+id/fragment_root
And whenever you want to change the fragment view:
In activity:
MainFragment fragment = (MainFragment) getSupportFragmentManager().getFragmentById(R.id.fragment_root);
fragment.updateList(mRecettes);
And then create the new method updateList() in your MainFragment
public void updateList(List<Recette> recettes) {
mRecettes.clear();
mRecettes.addAll(recettes);
configureListView();
}
Also you can tag your fragment when you add it to your transaction instead of using its id, and then use getSupportFragmentManager().getFragmentByTag()
I am trying to send two strings via a bundle to the next fragment but the app crashes even before I get to the first fragment.
I get this error in the second fragment:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.guessit, PID: 22360
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference
at com.example.android.guessit.GameFlow.FragmentAnswer1.onCreateView(FragmentAnswer1.java:125)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2600)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:881)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
at androidx.fragment.app.FragmentManagerImpl.execSingleAction(FragmentManagerImpl.java:1696)
at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:299)
at androidx.fragment.app.FragmentStatePagerAdapter.finishUpdate(FragmentStatePagerAdapter.java:259)
at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1244)
at androidx.viewpager.widget.ViewPager.setCurrentItemInternal(ViewPager.java:669)
at androidx.viewpager.widget.ViewPager.setCurrentItemInternal(ViewPager.java:631)
at androidx.viewpager.widget.ViewPager.setCurrentItem(ViewPager.java:612)
at com.example.android.guessit.GameFlow.GameActivity.setViewPager(GameActivity.java:152)
at com.example.android.guessit.GameFlow.FragmentOneCategory$6.onClick(FragmentOneCategory.java:190)
at android.view.View.performClick(View.java:7352)
at android.view.View.performClickInternal(View.java:7318)
at android.view.View.access$3200(View.java:846)
at android.view.View$PerformClick.run(View.java:27800)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7050)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
I know that this means that the string value that I am trying to receive in the second fragment means that there is no value for that string but I don't know where the problem here is because the strings I am trying to send are not null.
This is the code I am using for the bundle in the first fragment (using this in onCreatView):
FragmentAnswer1 frag1 = new FragmentAnswer1();
Bundle args = new Bundle();
args.putString("question_1", question);
args.putString("answer_1", answer);
frag1.setArguments(args);
getFragmentManager().beginTransaction().add(R.id.container, frag1).commit(); // there is a message that says that "beginTransaction" may produce a nullPointer
Here is the code to receive the strings in the second fragment (currently also in onCreateView)
question = getArguments().getString("question_1"); // error is in this line
answer = getArguments().getString("answer_1");
question1.setText(question);
rightAnswer.setText(answer);
I already tried to move the above code into the onStartmethod but I still get the same error. I also tried using this solution but its not working for me. I did not find any other solution or method on how to resolve the problem.
Please let me know if you need more informations. Any help is much appreciated!
I have now found the correct way to send data from one Fragment to another while having a ViewPager. We have to use a ViewModel.
First we have to create a ViewModel, in this case our goal is to send a String from Fragment 1 to Fragment 2. Here is the code for the ViewModel with Getter and Setter method for the String:
public class ViewModelString extends ViewModel {
private MutableLiveData<String> mString = new MutableLiveData<>();
public MutableLiveData<String> getmString() {
return mString;
}
public void setmString(MutableLiveData<String> mString) {
this.mString = mString;
}
}
Then in Fragment 1 from where we want to sent the string we need to first initialize the ViewModel in onCreate.
public class Fragment1 extends Fragment {
private ViewModelString viewModel;
public Fragment1() {
// Required empty public constructor
}
public static Fragment1 newInstance() {
return new Fragment1();
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// initialize ViewModel here
viewModel = ViewModelProviders.of(requireActivity()).get(ViewModelString.class);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
String hello = "hello";
viewModel.setmString(hello);
}
}
Then in the second Fragment we also have to first initialize the viewModel and then create an observer. Here we then take the String that is stored in the ViewModel and set a TextView to its value:
public class Fragment2 extends Fragment {
private ViewModelString viewModel;
public Fragment2() {
// Required empty public constructor
}
public static Fragment2 newInstance() {
return new Fragment2();
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// initialize ViewModel here
viewModel = ViewModelProviders.of(requireActivity()).get(ViewModelString.class);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
TextView textView = findViewById(R.id.yourTextViewId);
// Gets the string
viewModel.getmString().observe(requireActivity(), new Observer<String>() {
#Override
public void onChanged(#Nullable String s) {
textView.setText(s);
}
});
}
...
}
I hope this helps anyone! Please feel free to edit my post.
Use Bundle to send String:
//Put the value
Bundle args = new Bundle();
args.putString("YourKey", "YourValue");
YourFragmentName ldf = new YourFragmentName ();
ldf.setArguments(args);
//Inflate the fragment
getActivity().getSupportFragmentManager().beginTransaction().add(R.id.container, ldf).commit();
In onCreateView of the new Fragment:
//Retrieve the value
Bundle bundle = this.getArguments();
if (bundle != null) {
String value = bundle.getString("YourKey");
}
Use a Bundle. Here's an example:
Fragment fragment = new Fragment();
Bundle bundle = new Bundle();
bundle.putInt("Key", "value");
fragment.setArguments(bundle);
fragmentManager.beginTransaction().replace(R.id.container, frag1).commit()
Bundle has put methods for lots of data types. See this
Then in your Fragment, retrieve the data in onCreate() method like:
Bundle bundle = this.getArguments();
if (bundle != null) {
int myInt = bundle.getString(Key);
}
try this.
var fragment: MainFragment =MainFragment()
val args = Bundle()
args.putString("question_1", "My question")
args.putString("answer_1", "My answer")
fragment.setArguments(args)
fragmentManager.beginTransaction().add(R.id.fragment_content, fragment).commit()
Please see all the four pictures, first 3 pictures has error screen, the last one has Fragment constructor.
https://i.stack.imgur.com/lbodG.png
https://i.stack.imgur.com/nysfG.png
https://i.stack.imgur.com/AHYCR.png
https://i.stack.imgur.com/telPC.png
You must have a default constructor for Fragment.
public class Tab1Fragment extends Fragment{
public Tab1Fragment(){
}
...
}
If you want to pass data to your fragment you must do that by setArguments(), not by passing it through constructor, not good practice.
Instead try something like this:
public class Tab1Fragment extends Fragment{
private static final String ARG_URL = "url";
public Tab1Fragment(){
}
public static Tab1Fragment newInstance(String url) {
Tab1Fragment fragment = new Tab1Fragment();
Bundle args = new Bundle();
args.putString(ARG_URL, url);
fragment.setArguments(args);
return fragment;
}
}
And to get url value in fragment use
getArguments().getString(ARG_URL);
Now use newInstance method to get fragment instance.
Tab1Fragment.newInstance("your url");
As #Mangal mentioned, a Fragment must have a default (no argument) constructor. To pass data to a new fragment, use a static function, like this
public static MyFragment newInstance(String someData) {
MyFragment fragment = new MyFragment ();
Bundle args = new Bundle();
args.putString("someData", someData);
fragment.setArguments(args);
return fragment;
}
and retrieve the data like this
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Bundle args = getArguments();
String someData = "";
if( args != null ) {
someData = args.getString("someData", "");
}
}
Then, instead of calling
new MyFragment(data);
in the code where you create the Fragment, you would instead call
MyFragment.getInstance(data);
I need to pass a String from an Activity to a fragment but nothing seems to work for me.
I found this answer on stackoverflow
From Activity you send data with intent as:
Bundle bundle = new Bundle(); bundle.putString("edttext", "From
Activity"); // set Fragmentclass Arguments Fragmentclass fragobj = new
Fragmentclass(); fragobj.setArguments(bundle);
and in Fragment onCreateView method:
#Override public View onCreateView(LayoutInflater inflater, ViewGroup
container,
Bundle savedInstanceState) {
String strtext = getArguments().getString("edttext");
return inflater.inflate(R.layout.fragment, container, false); }
But this doesn't work for me. When I click the button nothing happens.
Is it maybe because the fragment is already created? In my app: ToDoFragment> Activity(pass data to:>ToDoFragment
Here is my code but I don't thing it will provide more info:
Activity.java (inside OnClickListener of a button)
String datePassed = mDate.getText().toString();
String toDoPassed = mEditText.getText().toString();
Bundle bundle=new Bundle();
bundle.putString("key1", datePassed);
//set Fragmentclass Arguments
ToDoFragment myToDoFragment=new ToDoFragment();
myToDoFragment.setArguments(bundle);
ToDoFragment.java (inside oncreateview)
Bundle bundle = this.getArguments();
if (bundle != null) {
mToDoInfo = getActivity().getIntent().getStringExtra(key1);
If I understood correct, then you are not doing it wrong, but you are doing this in wrong scenario. This is on assumption that your fragment is already inflated & you are starting new Activity from it & want the data back as result from it. so what you need is something like this,
inside your ToDoFragment where I believe you are starting activity, do this instead:
startActivityForResult(new Intent(getActivity(), MyActivity.class), 1001);
& override onActivityResult method like:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 1001 && resultCode == Activity.RESULT_OK) {
String myData = data.getStringExtra("my_key");
}
}
& now inside onClick of your MyActivity,
Intent intent = new Intent();
intent.putExtra("my_key", "my_data");
setResult(RESULT_OK, intent);
finish();
this should invoke onActivityResult of fragment where we wrote code to get data.
Yes this is because the fragment is already created. Create a method in your fragment class and call it from inside the onClick method of your activity.
Let me make it Easy for you!
ToDoFragment myToDoFragment=new ToDoFragment(datePassed); //easy right?
and in your ToDoFragment class make a constructor with String as input!
You can simply follow this pattern to pass the values from activity to fragment
ToDoFragment.java
public class ToDoFragment extends Fragment {
String date;
public static Fragment newInstance(String date) {
ToDoFragment fragment = new ToDoFragment();
fragment.date = date;
return ToDoFragment;
}
}
In your activity's onclick
String toDoPassed = mEditText.getText().toString();
ToDoFragment myToDoFragment = ToDoFragment.newInstance(toDoPassed);