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" />
Related
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();
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 have two fragments and a main activity. The first fragment, FriendsFragment (extends ListFragment) is displayed on the screen and when the user clicks an item, the main Activity replaces the FriendsFragment with FeedFragment, then calls a method from FeedFragment to update the textView.
I'm getting an error that the textView object in the FeedFragment class is null even though I instantiate using the findViewById method.
I have looked at related questions and have tried the solutions but nothing is working. I've tried doing getView().findViewById(R.id.feed_view), getActivity().findViewById(R.id.feed_view), and I've tried putting these in onActivityCreated() and onCreateView()
The only thing that worked is writing this code in onActivityCreated():
text = getView().findViewById(R.id.feed_view);
text.setText("some string");
but this is not what I want
FeedFragments.java
public class FeedFragment extends Fragment {
private static String TAG = "Feed Fragment";
private TextView text;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
Log.i(TAG, "Entered FeedFragment.java onActivityCreated()");
super.onActivityCreated(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
Log.i(TAG, "Entered FeedFragment.java onCreateView()");
View v = inflater.inflate(R.layout.fragment_feed, container,false);;
text = v.findViewById(R.id.feed_view);
return v;
}
public void updateDisplay(int position)
{
Log.i(TAG, "FeedFragment.java: updateDisplay()");
text.setText(position);
}
MainActivity.java
// previously declared feedFragment: feedFragment = new FeedFragment();
public void onItemSelected(int position)
{
Log.i(TAG, "Entered onItemSelected(" + position + ")");
fragManager = getFragmentManager();
FragmentTransaction fragTransaction = fragManager.beginTransaction();
fragTransaction.replace(R.id.fragment_container, feedFragment, "feed_fragment");
fragTransaction.addToBackStack(null);
fragTransaction.commit();
feedFragment.updateDisplay(position);
}
fragment_feed.xml
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/feed_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/greeting" />
</ScrollView>
activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
onViewcreated() is being called after updateDisplay() because the system doesn't run it right away.
you need to pass a value to the feedFragment on it's creation and store it in a bundle and retrieve it after the fragment internal code is run by the system.
the way you solve it is like this:
when you instantiate feedFragment you do it like this:
feedFragment = FeedFragment.newInstance(position)
and inside FeedFragment class you should have a static code:
private static final String ARG_PARAM1 = "param1";
public static FeedFragment newInstance(int param1) {
FeedFragment fragment = new FeedFragment();
Bundle args = new Bundle();
args.putInt(ARG_PARAM1, param1);
fragment.setArguments(args);
return fragment;
}
and non static code:
private int mParam1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getInt(ARG_PARAM1);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
Log.i(TAG, "Entered FeedFragment.java onCreateView()");
View v = inflater.inflate(R.layout.fragment_feed, container,false);;
text = v.findViewById(R.id.feed_view);
text.setText(String.valueOf(mParam1));
return v;
}
I wrapped mParam1 in String.valueOf() because when you pass integer to setText it thinks you try to use a Strings.xml resource instead of the number you chose.
also I used very generic variable names. please change them to something meaningful so that your code makes sense.
I have 3 tabs in my tabbed activity. I created 3 classes that extend Fragment and added my layouts. When I run it, it works fine. So I added some EditText widgets and a Button to my second tab. My question is : where do I put java code, for example, to handle onClickListener for that button.
I tried to do it in that main tabbed activity class but then the app crashed.
You can put that code in the relevant fragment of tabbed activity.
Application will crash because activity can not access the views which are inflated in fragment.
You can do like this :
public class PageFragment extends Fragment {
public static final String ARG_PAGE = "ARG_PAGE";
private int mPage;
public static PageFragment newInstance(int page) {
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
PageFragment fragment = new PageFragment();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPage = getArguments().getInt(ARG_PAGE);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_page, container, false);
TextView textView = (TextView) view;
textView.setText("Fragment #" + mPage);
return view;
}
}
For more check this tutorial.
You must add button click code to respective Fragment i.e. second tab in your case. Don't write code on activity which host that fragment.
Over the past days I've desperately been trying to build an android app with a simple fragment (which I use twice). I want to pass the contents of the fragments' EditText-boxes to a new activity. I just can't figure out how to get those contents from the fragments. What I have so far is this:
I've got my edit_text_fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<EditText
android:id="#+id/my_edit_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="my hint" />
</LinearLayout>
and the corresponding MyEditTextFragment.java:
public class MyEditTextFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.edit_text_fragment, container, false);
return view;
}
}
I then use this fragment twice in my main.xml like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<fragment
android:id="#+id/detailfragment_placeholder"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
class="com.example.fragmenttester5.MyEditTextFragment" />
<fragment
android:id="#+id/detailfragment_placeholder2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
class="com.example.fragmenttester5.MyEditTextFragment" />
<Button
android:id="#+id/submit_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Submit all of it" />
</LinearLayout>
and in my MainActivity I hooked up the button to a new activity:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button submitButton = (Button) findViewById(R.id.submit_button);
submitButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v){
Intent intent = new Intent(MainActivity.this, OtherActivity.class);
intent.putExtra("result1", "the_result_from_the_first_editText");
intent.putExtra("result2", "the_result_from_the_second_editText");
startActivity(intent);
}
});
}
}
I think I now need to define some kind of interface in the Fragment, but I can't find how. I read a couple examples and tutorials (like this one), but they make no sense to me at all. I don't understand the code given and I just don't understand how to adjust it for my use case.
So my question; can anybody help me to get the contents of the fragment from within the activity? Examples would be very very welcome since I'm just banging my head against the wall here..
You are right, that's kind of a standard way to pass data from a Fragment to an activity.
Basically you define a Listener interface which the Activity implements, and the Activity registers itself as a Listener with the Fragment.
Here's a simple example:
Fragment
class MyFragment extends Fragment {
interface Listener {
public void somethingHappenedInFragment(Object... anyDataYouWantToPassToActivity);
}
private Listener mListener;
public void setListener(Listener listener) {
mListener = listener;
}
// ... your code ...
// Now here you pass the data to the activity
mListener.somethingHappenedInFragment(some, data);
// ... more of your code
}
Activity
public MyActivity extends Activity implements MyFragment.Listener {
// ... your code ...
// creating the Fragment
MyFragment f = new MyFragment();
// register activity as listener
f.setListener(this);
// ... more of your code
// implementation of MyFragment.Listener interface
#Override
public void somethingHappenedInFragment(Object... anyDataYouWantToPassToActivity) {
// here you have the data passed from the fragment.
for (Object o : anyDataYouWantToPassToActivity {
System.out.println(o.toString();
}
}
}
On a high level, there are two tasks that you commonly need to solve with Fragments. The first is communicating data from an Activity to a Fragment. The second is communicating data from a Fragment to an Activity.
An Activity knows which Fragments it contains since it creates them, so it's easy to communicate that way - just call methods on the Fragment itself. But the inverse is not true; Fragments might be attached to any number of random Activities, so it doesn't know anything about it's parent.
The solution is to implement an interface that the Activity implements and the Fragment knows how to communicate with. That way, your Fragment has something it knows how to talk with. There are specific code examples for how to do it here: http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity
(In particular, check out the "Creating event callbacks to the activity" code examples).
So you'd create an Interface to talk with the Activity if the event happened in the Fragment. For situations like this, you can simply make an accessible method in the Fragment that the Activity can call. So
public class MyEditTextFragment extends Fragment {
private EditText mEditText;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.edit_text_fragment, container, false);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mEditText = (EditText) getView().findViewById(R.id.my_edit_text);
}
public Editable getText() {
return mEditText.getText();
}
}
Then
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MyEditTextFragment fragment1 = (MyEditTextFragment)
getFragmentManager().findFragmentById(R.id.detailfragment_placeholder);
final MyEditTextFragment fragment2 = (MyEditTextFragment)
getFragmentManager().findFragmentById(R.id.detailfragment_placeholder2);
Button submitButton = (Button) findViewById(R.id.submit_button);
submitButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v){
String firstResult = fragment1.getText().toString();
String secondResult = fragment2.getText().toString();
Intent intent = new Intent(MainActivity.this, OtherActivity.class);
intent.putExtra("result1", firstResult);
intent.putExtra("result2", secondResult);
startActivity(intent);
}
});
}
}
This assumes that you assigned the Fragment tags in your FragmentTransaction. Be sure to check for null Fragments (omitted for brevity)
Activity will be received data from updateDetail() method in Fragment
//// Activity
public class RssfeedActivity extends Activity implements MyListFragment.OnItemSelectedListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rssfeed);
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("Annv - Fragment", "onClick here");
}
});
}
// if the wizard generated an onCreateOptionsMenu you can delete
// it, not needed for this tutorial
#Override
public void onRssItemSelected(String link) {
// DetailFragment fragment = (DetailFragment) getFragmentManager()
// .findFragmentById(R.id.detailFragment);
// if (fragment != null && fragment.isInLayout()) {
// fragment.setText(link);
// }
// Intent start = new Intent(this, RssfeedSecondActivity.class);
// startActivity(start);
DetailFragment fragment = (DetailFragment) getFragmentManager()
.findFragmentById(R.id.detailFragment);
if (fragment != null && fragment.isInLayout()) {
fragment.setText(link);
}
}
}
/// Fragment
public class MyListFragment extends Fragment {
private OnItemSelectedListener listener;
private OnItemStartActivityListener listenerStartAct;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_rsslist_overview,
container, false);
Button button = (Button) view.findViewById(R.id.button1);
Log.d("Annv - Fragment", "run on " + getActivity().toString());
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
updateDetail();
}
});
return view;
}
public interface OnItemSelectedListener {
public void onRssItemSelected(String link);
}
public interface OnItemStartActivityListener {
public void onRssStartActivity(String link);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof OnItemSelectedListener) {
Log.d("Annv - Fragment", "activity " + activity.getLocalClassName());
listener = (OnItemSelectedListener) activity;
} else if (activity instanceof OnItemStartActivityListener) {
Log.d("Annv - Fragment", "activity " + activity.getLocalClassName());
listenerStartAct = (OnItemStartActivityListener) activity;
} else {
throw new ClassCastException(activity.toString()
+ " must implemenet MyListFragment.OnItemSelectedListener");
}
}
// May also be triggered from the Activity
public void updateDetail() {
// create fake data
// String newTime = String.valueOf(System.currentTimeMillis());
// // Send data to Activity
// listenerStartAct.onRssItemSelected(newTime);
if (getActivity() instanceof OnItemSelectedListener) {
listener.onRssItemSelected("start start");
} else {
String newTime = String.valueOf(System.currentTimeMillis());
listenerStartAct.onRssStartActivity(newTime);
}
}
}