How to use PlaceAutoCompleteFragment widget in a Fragment - Android? - android

I am using PlaceAutoCompleteFragment inside a Fragment. First time when Fragment(App fragment in which PlaceAutoCompleteFragment is placed) opens it works fine like a charm. But, then second time I hit button to open Fragment it crashes with below error. It works only a single time.
FATAL EXCEPTION:
android.view.InflateException: Binary XML file line #64: Error inflating class fragment
Caused by: java.lang.IllegalArgumentException: Binary XML file line #64: Duplicate id 0x7f0d0094, tag null, or parent id 0xffffffff with another fragment for com.google.android.gms.location.places.ui.PlaceAutocompleteFragment
This is how i am using this:
SupportPlaceAutocompleteFragment placeAutocompleteFragment = (SupportPlaceAutocompleteFragment) getActivity().getSupportFragmentManager().
findFragmentById(R.id.place_autocomplete_fragment);
placeAutocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
#Override
public void onPlaceSelected(Place place) {
System.out.println(place.getAddress());
}
#Override
public void onError(Status status) {
}
});
Error is on this line in onCreateDialog method, where layout is inflating:
View view = inflater.inflate(R.layout.add_geofence_layout, null);
XML:
<fragment
android:id="#+id/place_autocomplete_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:name="com.google.android.gms.location.places.ui.SupportPlaceAutocompleteFragment" />
Wondering! Why this code works only once?
DialogFragment class:
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.add_geofence_layout, null);
viewHolder = new ViewHolder();
viewHolder.initializeView(view);
viewHolder.placeAutocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
#Override
public void onPlaceSelected(Place place) {
System.out.println(place.getAddress());
}
#Override
public void onError(Status status) {
}
});
}
Note:- I am using a PlaceautoCompleteFragment inside a DialogFragment. If i use this inside an Activity it works fine.

Don't add PlaceAutocompleteFragment directly to your fragment layout. you need to add PlaceAutocompleteFragment dynamically and remove it on onDestroyView().
layout.xml
<LinearLayout
android:id="#+id/placeLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="visible">
</LinearLayout>
Add PlaceAutocompleteFragment
PlaceAutocompleteFragment autocompleteFragment=new PlaceAutocompleteFragment();
FragmentManager fragmentManager = getActivity().getFragmentManager();
android.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.placeLayout,autocompleteFragment);
fragmentTransaction.commit();
Remove it onDestroy
#Override
public void onDestroyView() {
super.onDestroyView();
if (getActivity() != null) {
FragmentManager fragmentManager = getActivity().getFragmentManager();
android.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.remove(autocompleteFragment);
fragmentTransaction.commit();
}
}

Try this if this works:
View view;
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = getActivity().getLayoutInflater();
if(view == null) {
view = inflater.inflate(R.layout.add_geofence_layout, null);
}
viewHolder = new ViewHolder();
viewHolder.initializeView(view);
viewHolder.placeAutocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
#Override
public void onPlaceSelected(Place place) {
System.out.println(place.getAddress());
}
#Override
public void onError(Status status) {
}
});
}

You should give more context regarding the layout. The Exceptions states: "Duplicate id " are you sure you aren't using the same id twice?

Try to remove the fragment at onDestroyView()
#Override
public void onDestroyView() {
super.onDestroyView();
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.remove(mPlaceAutocompleteFragment);
ft.commit();
}

Related

app getting crash while resume app

Please any one help me, I am new in android studio, my app getting crash while resume application,
I have three different fragment layout which have
<fragment
android:id="#+id/map_online"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/action_bar" /> with different ID.
while resume application I need to load one Fragment with map,
I am getting following error:
Caused by: java.lang.IllegalArgumentException: Binary XML file line
39: Duplicate id 0x7f0f018a, tag null, or parent id 0xffffffff with another fragment for com.google.android.gms.maps.SupportMapFragment
Please any one sugggest how to solve this.
This is my fragment class:
public class ClientRequestFragment extends Fragment implements OnMapReadyCallback {
View clientRequestView;
private static final String TAG = ClientRequestFragment.class.getSimpleName();
GoogleMap googleMap;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
SupportMapFragment mapFragment = (SupportMapFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.map_online);
mapFragment.getMapAsync(this);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
LayoutInflater li = (LayoutInflater) getActivity().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
clientRequestView = li.inflate(R.layout.offline_fragment, container, false);
return clientRequestView;
}
public void addFragment(Fragment fragment, boolean addToBackStack,
String tag, boolean isAnimate) {
FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
if (isAnimate) {
ft.setCustomAnimations(R.anim.slide_in_right,
R.anim.slide_out_left, R.anim.slide_in_left,
R.anim.slide_out_right);
}
if (addToBackStack) {
ft.addToBackStack(tag);
}
ft.replace(R.id.content_frame, fragment, tag);
ft.commitAllowingStateLoss();
}
#Override
public void onClick(View view) {
}
#Override
public void onMapReady(GoogleMap googleMap) {
this.googleMap = googleMap;
//googleMap.setMyLocationEnabled(true);
/* try {
// Customise the styling of the base map using a JSON object defined
// in a raw resource file.
boolean success = googleMap.setMapStyle(
MapStyleOptions.loadRawResourceStyle(
getActivity(), R.raw.retro_style_json));
if (!success) {
Log.e(TAG, "Style parsing failed.");
}
} catch (Resources.NotFoundException e) {
Log.e(TAG, "Can't find style. Error: ", e);
}*/
}
#Override
public void onDestroyView() {
super.onDestroyView();
FragmentManager fm = getActivity().getSupportFragmentManager();
Fragment fragment = (fm.findFragmentById(R.id.map_online));
FragmentTransaction ft = fm.beginTransaction();
ft.remove(fragment);
ft.commit();
}
#Override
public void onPause() {
super.onPause();
}
}
Thank you.
Your app getting crash because static fragment inside fragment can not be remove or replace , you can only hide or show this static fragment.
make your xml file like this:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/coreLayout"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<FrameLayout
android:id="#+id/fragment_home_container"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
in your fragment.java file write this code:
PlaceAutocompleteFragment autocompleteFragmentSourceAddress = new PlaceAutocompleteFragment();
replaceFragment(autocompleteFragmentSourceAddress, R.id.fragment_home_container);
You need to remove fragment before push new one in your fragment view have been re-created so add ==null condition in onCreatedView method,
View mainView;// this should be global variable.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if(mainview==null){
mainView = inflater.inflate(R.layout.fragment_layout, container, false);
initializeView();//initialize all views in this method instead of onActivityCreated
}
return mainView;
}
Add this when you push above fragment to avoid duplication
try {
android.app.Fragment fragment = getFragmentManager().findFragmentById(R.id.map_online);
if (fragment != null) {
android.app.FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.remove(fragment);
ft.commit();
}
} catch (Exception e) {
e.printStackTrace();
}

getSupportFragmentManager() undefined in adapter when using AppCompatActivity

I have an activity (MainActivity) which extends AppCompatActivity because I am using some of the material design elements in my app.
I then have an array adapter with a few fields and a button. This adapter has a separate view and is injected into my MainActivity layout.
When I click the button on the adapter view, I want to open a new fragment which displays a bunch of text, however, I can't seem to do this and I think it is because I am not extending FragmentActivity in my MainActivity? I read on another post that I should be able to extend AppCompatActivity and still be able to reference the fragment manager...here is my code to open the fragment:
In my custom array adapter, onClick() of a button:
holder.desc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
JobDescFragment fragment= new JobDescFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
});
The error I get is that it cannot resolve getSupportFragmentManager(). What am I doing wrong?
I am importing android.support.v4.app.Fragment and .FragmentManager in my adapter.
Thanks in advance for the help!
EDIT:
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<com.lorentzos.flingswipe.SwipeFlingAdapterView
android:id="#+id/frame"
android:background="#color/laborswipe_lightgray"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:context=".MainActivity"
android:layout_gravity="top" />
<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" />
</merge>
you can try this
FragmentTransaction ft = ((AppCompatActivity) mContext).getSupportFragmentManager()
.beginTransaction();
In kotlin it will be like this for example. I have tried it and it work perfectly
val dialog = IntervAddFragment()//The fragment that u want to open for example
val ft = (context as AppCompatActivity).supportFragmentManager.beginTransaction()
dialog.show(ft, ContentValues.TAG)
Hi this is simple just pass the reference of YourParent Activity
Just use the snippet like this below in Your Adapter class to open fragment
Fragment fragment = new YourFragment();
FragmentManager fm = ((MainActivity) mContext).getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.frame_container, fragment);
ft.commit();
in adapter use
appCompatActivity object instead of context
it will work
pass context in adapter and use
context.getSupportFragmentManager().beginTransaction();
avoid unwanted codes
public class AdapterRecyclerViewDoc extends RecyclerView.Adapter<AdapterRecyclerViewDoc.ShareDocViewHolder> {
ArrayList<ModelDoc> arrayList;
AppCompatActivity appCompatActivity;
public AdapterRecyclerViewDoc(ArrayList<ModelDoc> arrayList, AppCompatActivity appCompatActivity) {
this.arrayList=arrayList;
this.appCompatActivity=appCompatActivity;
}
#Override
public ShareDocViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate
(R.layout.recyclerview_item_doc, parent, false);
ShareDocViewHolder eventViewHolder = new ShareDocViewHolder(v);
this.appCompatActivity.getSupportFragmentManager();
return eventViewHolder;
}
To make the code more flexible and separate logic you should understand responsibilities of your components. It is clear that your Adapter should not know about the Fragment and what is base class of Activity. So what should you do?
In your Activity you should set a listener to item clicked event inside adapter:
public class YourActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_your);
//... some findViewById, etc.
YourAdapter adapter = new YourAdapter(this, data, new OnDetailsRequestListener(){
public void onDetailsRequested(int itemId){
DetailsFragment fragment = DetailsFragment.newInstance(itemId);
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment)
.addToBackStack(null)
.commit();
});
//... recyclerView.setAdapter ... etc.
}
public interface onDetailsRequestListener{
void onDetailsRequestLister(int itemId);//here could be whatever you want, itemId, details, whatever...
}
}
And inside your adapter you would have:
//...
public AdapterConstructor(Context context, ArrayList data, YourActivity.OnDetailsRequestListener detailsRequestListener) {
this.data = data;
this.context = context;
this.detailsRequestListener = detailsRequestListener;
//...
}
//Inside bindView
holder.desc.setTag(position);
holder.desc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int position = (int)view.getTag();
int itemId = data.get(position).getId();
detailsRequestListener.onDetailsRequested(itemId);
}
});
From your class
YourAdapter=new YourAdapter(context, list, YourClass.this.getSupportFragmentManager)
Adapter
public Adapter(context, list, FragmentManager manager){
this.manager=manager;
Action
FragmentTransaction ft = fragmentcontext.beginTransaction();
SlideshowDialogFragment newFragment = SlideshowDialogFragment.newInstance();
newFragment.setArguments(bundle);
newFragment.show(ft, "slideshow");
FragmentTransaction trans =((FragmentActivity)context).getSupportFragmentManager()
.beginTransaction();
If you try this, you will see it work.

Android FragmentManager for same Activity hide() doesnt work

Hi guys im working on my MainActivity and I am dealing with the following problem:
In my MainActivity I have 3 buttons(button1, button2, button3). With each I can add a Fragment(Fragment2, Fragment1, ProfileFragment) to my container. Everytime a button is pressed, it checks the Fragments if there is already anotherone visible.
If yes, FragmentManager().beginnTransaction().fragment.hide() should hide it.
Then it checks if the fragment bound to the button already exists.
If no, it adds it.
If yes, it should make the existing hidden fragment visible again with FragmentManager().beginnTransaction().fragment.show()
Now: If I press button2 as the first when I start my App everything works fine and I can infinitely switch between the fragments.
But: If I press button1 as the first, and then switch to button2 or button3, the fragment bound to button1 (m2fragment) can't be shown again. It just shows m1fragment (which should be hidden when I press button1)
The same happens if I press button3 as the first. Everytime I try to switch back to button3(profileFragment) it just shows m1fragment.
May be there a problem with the googleMap which I call from the xml from m2Fragment??
Anyone can see where I made (a) mistake(s) ? I would be really glad since I am dealing with this for several days now.
Thank you all !
Cut from my MainActivity:
public class MainActivity extends FragmentActivity implements ProfileFragment.OnFragmentInteractionListener,
OfferFragment.OnFragmentInteractionListener, MapsFragment.OnFragmentInteractionListener, OpenerFragment.OnFragmentInteractionListener, GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
protected int fragment1Open = 0;
protected int fragment2Open = 0;
protected int profileFragmentOpen = 0;
Fragment1 m1Fragment = new Fragment1();
Fragment2 m2Fragment = new Fragment2();
ProfileFragment mProfileFragment = new ProfileFragment();
OpenerFragment mOpenerFragment = new OpenerFragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState==null) {
getFragmentManager().beginTransaction().add(R.id.container,mOpenerFragment).commit();
}
final Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//check fragments
if(mOpenerFragment.isVisible()) {
getFragmentManager().beginTransaction().remove(mOpenerFragment).commit();
Log.d("button1", "remove OpenerFragment");
}
if(m1Fragment.isVisible()) {
getFragmentManager().beginTransaction().hide(m1Fragment).commit();
}
if(mProfileFragment.isVisible()) {
getFragmentManager().beginTransaction().hide(mProfileFragment).commit();
}
if(fragment2Open==0) {
fragment2Open=1;
getFragmentManager().beginTransaction().add(R.id.container, m2Fragment).commit();
} else {
getFragmentManager().beginTransaction().show(m2Fragment).commit();
}
}
});
final Button button2 = (Button) findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//hide other fragments
if(mOpenerFragment.isVisible()) {
getFragmentManager().beginTransaction().remove(mOpenerFragment).commit();
}
if(mProfileFragment.isVisible()) {
getFragmentManager().beginTransaction().hide(mProfileFragment).commit();
}
if(m2Fragment.isVisible()) {
getFragmentManager().beginTransaction().hide(m2Fragment).commit();
}
if(fragment1Open==0) {
fragment1Open=1;
getFragmentManager().beginTransaction().add(R.id.container, m1Fragment).commit();
} else {
getFragmentManager().beginTransaction().show(m1Fragment).commit();
}
}
});
final Button button3 = (Button) findViewById(R.id.button3);
button3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//hide other fragments
if(mOpenerFragment.isVisible()) {
getFragmentManager().beginTransaction().remove(mOpenerFragment).commit();
}
if(m1Fragment.isVisible()) {
getFragmentManager().beginTransaction().hide(m1Fragment).commit();
}
if(m2Fragment.isVisible()) {
getFragmentManager().beginTransaction().hide(m2Fragment).commit();
}
//open fragment
if(profileFragmentOpen==0) {
profileFragmentOpen=1;
getFragmentManager().beginTransaction().add(R.id.container, mProfileFragment).commit();
} else {
getFragmentManager().beginTransaction().show(mProfileFragment).commit();
}
}
});
mProfileFragment and m2Fragment use identically onCreate and onCreateView methods:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootview = inflater.inflate(R.layout.fragment_profile, container, false);
return rootview;
}
m1Fragment has the same methods, but gets a googleMaps fragment from its xml file.
m1Fragment:
public class Fragment1 extends Fragment implements OnMapReadyCallback {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MapFragment mapFragment=(MapFragment) getFragmentManager().findFragmentById(mapid);
if (mapFragment==null) {
mapFragment = MapFragment.newInstance();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.container, mapFragment);
fragmentTransaction.commit();
mapFragment.getMapAsync(this);
}
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap map) {
//right upper corner, location layer activated
map.setMyLocationEnabled(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_maps, container, false);
return rootView;
}
fragment_1.xml:
<fragment
android:id="#id/mapid"
class="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
MapFragment mapFragment=(MapFragment) getFragmentManager().findFragmentById(mapid);
in this line your actually tring to get the parent's fragmentManager (in your case the activity),and fail to find the fragment.
and then in this line:
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.container, mapFragment);
fragmentTransaction.commit();
you are adding to the parent FragmentManager.
a quick to solution is to replace getFragmentManger() with getChildFragmentManager, which refers to the fragment's FragmentManager.
Maybe you should try to use :
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack if needed
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
With fragment_container as FrameLayout in your activity?
I'm not 100% sure, but i think it'll avoid such issues
I just solved it:
Withing my MapsFragment class I instantiated a googleMaps fragment "twice". Trying to hide the mapFragment I just hid one of them, leaving the other one visible in front.
For people having similar issues here my solution:
I erased the
<fragment
android:id="#id/mapid"
class="com.google.android.gms.maps.MapFragment"/>
from the xml layout file.
And inside the MapsFragment class I changed
MapFragment mapFragment=(MapFragment) getChildFragmentManager().findFragmentById(mapid);
to
MapFragment mapFragment = MapFragment.newInstance();
getChildFragmentManager().beginTransaction().add(R.id.framLay, mapFragment).commit();
Now I put one clean Instance of MapFragment into my FrameLayout and it works properly.

Get edittext value from fragment

I am using fragments,I have an edittext in fragment and I want to get value in main activity.
This is my fragment layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#878787" >
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="dfgdfgdf"
android:textSize="20dp"
android:layout_centerInParent="true"
android:id="#+id/user_name"/>
<EditText
android:id="#+id/message"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button
android:text="Gönder"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="getFromUser"
android:layout_marginTop="40dp"
/>
</RelativeLayout>
I am loading fragment with this function:
public void startChat(JsonObject user) {
FrameLayout layout = (FrameLayout)findViewById(R.id.container);
layout.setVisibility(View.VISIBLE);
Bundle bundle = new Bundle();
bundle.putString("name", user.get("name").getAsString());
sendTo=user.get("username").getAsString();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ConversationFragment conv = new ConversationFragment();
conv.setArguments(bundle);
fragmentTransaction.add(R.id.container, conv);
fragmentTransaction.commit();
viewPager.setVisibility(View.GONE);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setDisplayHomeAsUpEnabled(true);
}
And this is my fragment class
public class ConversationFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String name = getArguments().getString("name");
View rootView = inflater.inflate(R.layout.fragment_conversation, container, false);
TextView username=(TextView)rootView.findViewById(R.id.user_name);
username.setText(name);
return rootView;
}
}
As you can see when press the button main activity runs "getFromUser" function.I want to get edittext value in this function.How can I do this ?
It's always the same procedure for these things. You can't access a fragment's views just like that. You need a callback method.
Add this code to ConversationFragment:
private OnGetFromUserClickListener mListener;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnGetFromUserClickListener ) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnGetFromUserClickListener");
}
}
public void getFromUser(View v) {
if (mListener != null) {
EditText edit = (EditText)findViewById(R.id.message);
mListener.getFromUser(edit.getText().toString());
}
}
public interface OnGetFromUserClickListener {
void getFromUser(String message);
}
Make your MainActivity implement this interface. Replace getFromUser() inside MainActivity with:
public void getFromUser(String message) {
sendMessage(message);
}
Done.
Edit:
Actually, using the XML-onClick attribute is currently bugged (see onClick inside fragment called on Activity): It links to the activity instead of the fragment. You have to set the click listener programmatically to make sure the code won't break at some point in the future. So give the button an ID inside the XML (e.g. get_from_user) and add this code to onCreateView inside ConversationFragment:
v.findViewById(R.id.get_from_user).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (v.getId() == R.id.get_from_user) {
getFromUser(v);
}
}
});
Using this code vastly decouples the activity and the fragment from each other.
I resolved this problem.
public void getFromUser(View view) {
ConversationFragment fragment1 = (ConversationFragment)getSupportFragmentManager().findFragmentById(R.id.container);
View frag=fragment1.getView();
EditText editText1 =(EditText) frag.findViewById(R.id.message);
String message=editText1.getText().toString();
sendMessage(message);
}
Now I can get edittext value from fragment.

How do I add a Fragment to an Activity with a programmatically created content view

I want to add a Fragment to an Activity that implements its layout programmatically. I looked over the Fragment documentation but there aren't many examples describing what I need. Here is the type of code I tried to write:
public class DebugExampleTwo extends Activity {
private ExampleTwoFragment mFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FrameLayout frame = new FrameLayout(this);
if (savedInstanceState == null) {
mFragment = new ExampleTwoFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(frame.getId(), mFragment).commit();
}
setContentView(frame);
}
}
...
public class ExampleTwoFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
Button button = new Button(getActivity());
button.setText("Hello There");
return button;
}
}
This code compiles but crashes at start, probably because my FragmentTransaction.add() is incorrect. What is the correct way to do this?
It turns out there's more than one problem with that code. A fragment cannot be declared that way, inside the same java file as the activity but not as a public inner class. The framework expects the fragment's constructor (with no parameters) to be public and visible. Moving the fragment into the Activity as an inner class, or creating a new java file for the fragment fixes that.
The second issue is that when you're adding a fragment this way, you must pass a reference to the fragment's containing view, and that view must have a custom id. Using the default id will crash the app. Here's the updated code:
public class DebugExampleTwo extends Activity {
private static final int CONTENT_VIEW_ID = 10101010;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FrameLayout frame = new FrameLayout(this);
frame.setId(CONTENT_VIEW_ID);
setContentView(frame, new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
if (savedInstanceState == null) {
Fragment newFragment = new DebugExampleTwoFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(CONTENT_VIEW_ID, newFragment).commit();
}
}
public static class DebugExampleTwoFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
EditText v = new EditText(getActivity());
v.setText("Hello Fragment!");
return v;
}
}
}
Here is what I came up with after reading Tony Wong's comment:
public class DebugExampleTwo extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addFragment(android.R.id.content,
new DebugExampleTwoFragment(),
DebugExampleTwoFragment.FRAGMENT_TAG);
}
}
...
public abstract class BaseActivity extends Activity {
protected void addFragment(#IdRes int containerViewId,
#NonNull Fragment fragment,
#NonNull String fragmentTag) {
getSupportFragmentManager()
.beginTransaction()
.add(containerViewId, fragment, fragmentTag)
.disallowAddToBackStack()
.commit();
}
protected void replaceFragment(#IdRes int containerViewId,
#NonNull Fragment fragment,
#NonNull String fragmentTag,
#Nullable String backStackStateName) {
getSupportFragmentManager()
.beginTransaction()
.replace(containerViewId, fragment, fragmentTag)
.addToBackStack(backStackStateName)
.commit();
}
}
...
public class DebugExampleTwoFragment extends Fragment {
public static final String FRAGMENT_TAG =
BuildConfig.APPLICATION_ID + ".DEBUG_EXAMPLE_TWO_FRAGMENT_TAG";
// ...
}
Kotlin
If you are using Kotlin make sure to take a look at what the Kotlin extensions by Google provide or just write your own.
public class Example1 extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DemoFragment fragmentDemo = (DemoFragment)
getSupportFragmentManager().findFragmentById(R.id.frame_container);
//above part is to determine which fragment is in your frame_container
setFragment(fragmentDemo);
(OR)
setFragment(new TestFragment1());
}
// This could be moved into an abstract BaseActivity
// class for being re-used by several instances
protected void setFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(android.R.id.content, fragment);
fragmentTransaction.commit();
}
}
To add a fragment into a Activity or FramentActivity it requires a
Container. That container should be a "Framelayout", which can be
included in xml or else you can use the default container for that
like "android.R.id.content" to remove or replace a fragment in
Activity.
main.xml
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Framelayout to display Fragments -->
<FrameLayout
android:id="#+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="#+id/imagenext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_margin="16dp"
android:src="#drawable/next" />
</RelativeLayout>
After read all Answers I came up with elegant way:
public class MyActivity extends ActionBarActivity {
Fragment fragment ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
fragment = fm.findFragmentByTag("myFragmentTag");
if (fragment == null) {
FragmentTransaction ft = fm.beginTransaction();
fragment =new MyFragment();
ft.add(android.R.id.content,fragment,"myFragmentTag");
ft.commit();
}
}
basically you don't need to add a frameLayout as container of your fragment instead you can add straight the fragment into the android root View container
IMPORTANT: don't use replace fragment as most of the approach shown here, unless you don't mind to lose fragment variable instance state during onrecreation process.
For attaching fragment to an activity programmatically in Kotlin, you can look at the following code:
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// create fragment instance
val fragment : FragmentName = FragmentName.newInstance()
// for passing data to fragment
val bundle = Bundle()
bundle.putString("data_to_be_passed", DATA)
fragment.arguments = bundle
// check is important to prevent activity from attaching the fragment if already its attached
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.add(R.id.fragment_container, fragment, "fragment_name")
.commit()
}
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.MainActivity">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
FragmentName.kt
class FragmentName : Fragment() {
companion object {
fun newInstance() = FragmentName()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// receiving the data passed from activity here
val data = arguments!!.getString("data_to_be_passed")
return view
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
}
}
If you are familiar with Extensions in Kotlin then you can even better this code by following this article.
public abstract class SingleFragmentActivity extends Activity {
public static final String FRAGMENT_TAG = "single";
private Fragment fragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
fragment = onCreateFragment();
getFragmentManager().beginTransaction()
.add(android.R.id.content, fragment, FRAGMENT_TAG)
.commit();
} else {
fragment = getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
}
}
public abstract Fragment onCreateFragment();
public Fragment getFragment() {
return fragment;
}
}
use
public class ViewCatalogItemActivity extends SingleFragmentActivity {
#Override
public Fragment onCreateFragment() {
return new FragmentWorkShops();
}
}
For API level 17 or higher, View.generateViewId() will solve this problem. The utility method provides a unique id that is not used in build time.
This may help you
Defining a Fragment
create xml file for fragment view fragment_abc.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" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
create fragment ABCFragment.java
import androidx.fragment.app.Fragment;
public class FooFragment extends Fragment {
// The onCreateView method is called when Fragment should create its View object hierarchy,
// either dynamically or via XML layout inflation.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle
savedInstanceState) {
// Defines the xml file for the fragment
return inflater.inflate(R.layout.fragment_abc, parent, false);
}
// This event is triggered soon after onCreateView().
// Any view setup should occur here. E.g., view lookups and attaching view listeners.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// Setup any handles to view objects here
// EditText etFoo = (EditText) view.findViewById(R.id.etFoo);
}
}
Add frameLayout in your activity
<FrameLayout
android:id="#+id/your_placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent">
now in activity, add following method
protected void setFragment() {
// Begin the transaction
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
// Replace the contents of the container with the new fragment
ft.replace(R.id.fragment_container, new ABCFragment());
// or ft.add(R.id.your_placeholder, new ABCFragment());
// Complete the changes added above
ft.commit();
}
reference : https://guides.codepath.com/android/creating-and-using-fragments#defining-a-fragment

Categories

Resources