Why this code don't give null pointer exception? - android

I'm little bit confused about below code, where I'm adding a Fragment inside a Fragment, onCreateView() method before adding it's View. From my point of view as I did not yet set the View so when the R.id.rv_container will call to get the FrameLayout for that Child Fragment it will get null pointer exception but that's not happening. It working good.
So what is the reason of this? Why I'm wrong about null pointer exception?
Fragment Class:
public class Chats extends Fragment {
#Override
public View onCreateView(
#NonNull LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState
) {
initRvView();
return inflater.inflate(R.layout.fragment_chat,
container, false);
}
private void initRvView() {
final String POST_RV = "chat_recycler";
RecyclerViewFragment recyclerViewFragment = (RecyclerViewFragment)
getChildFragmentManager()
.findFragmentByTag(POST_RV);
if (recyclerViewFragment == null) {
recyclerViewFragment = new RecyclerViewFragment(FROM_MESSAGING);
}
getChildFragmentManager().beginTransaction()
.replace(R.id.rv_container,
recyclerViewFragment,
POST_RV)
.commit();
}
}
Fragment Layout (R.layout.fragment_chat):
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<FrameLayout
android:id="#+id/rv_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
If you look at the code initRvView() method is calling before set the View but didn't showing any null pointer exception.

Related

Why is the container null for static fragment?

I have the following Layout with static fragment and RelativeLayout as parent:
<?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:padding="#dimen/activity_vertical_margin">
<fragment
android:id="#+id/list_fragment"
android:name="com.listfragmenttest.MyListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
Yet the container or parent comes up null in OnCreateView:
public class MyListFragment extends ListFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.my_list_fragment, container, false);
}
}
Is this the normal behavior for Static fragment?
Yes, that's how it is implemented. Fragments inflated statically from XML get a null as parent container.
For details, consult FragmentManager source. In particular, onCreateView() that handles fragment instantiation from layout inflation, setting mInLayout = true and calls to performCreateView() that are conditional on mInLayout.

having a condition to fragment adding

for the last 4 hours ive been trying to understand how to do it.
to be clear, i need to add a fragment under a certain condition and for my purpose the condition can be either:
a. if the parent's id matches to what i seek.
b. if the fragment's id matches to what i seek.
i tried to put the condition inside the fragment itself:
public class BlockFrag extends Fragment{
SharedPreferences sp;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
sp = getActivity().getSharedPreferences("myOptions", Context.MODE_PRIVATE);
int id = container.getId();//didn't work(i think the container is null for some reason
switch (id)
{
default: return inflater.inflate(R.layout.nothing, container, false);
case (R.id.redFrame): {
if (sp.getBoolean("redBlock", true)) {
return inflater.inflate(R.layout.block_frag, container, false);
}
}
case (R.id.greenFrame): {
if (sp.getBoolean("greenBlock", true)) {
return inflater.inflate(R.layout.block_frag, container, false);
}
i also tried to get the condition programatically but i cant understand how to prevent the fragment to automatically generate when i call the layout it's placed.
this is the layout it's placed for example
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/redFrame"
android:layout_weight="0.33333">
<fragment
android:name="com.example.dor.myapplication.BlockFrag"
android:id="#+id/blockRed"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="#layout/block_frag"/>
this is the fragment's layout if it matters...
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
<ImageView
android:layout_width="118dp"
android:layout_height="match_parent"
android:id="#+id/blockFrag"
android:src="#drawable/block"
android:layout_weight="0.33333"
android:layout_above="#+id/linearLayout"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_gravity="left"
android:scaleType="fitXY"/>
thank you for helping, any kind of way to do this will help me.
I did something similar earlier, I had to decide based on a value from PickHeaderFragment which Fragment to show inside my root_frame_body, here's how I achieved it:
My Parent or Host Fragment:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="#000"
android:layout_height="wrap_content"
android:id="#+id/root_frame_header" />
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="#000"
android:layout_weight="1"
android:layout_height="match_parent"
android:id="#+id/root_frame_body" />
</LinearLayout>
Inside my Host Fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View rootView = inflater.inflate(R.layout.fragment_pick, container, false);
headerFragment = PickHeaderFragment.newInstance("");
getChildFragmentManager().beginTransaction().replace(R.id.root_frame_header, headerFragment).commit();
}
My PickHeaderFragment has an OnPickHeaderFragmentInteractionListener Interface implemented which looks like this:
public interface OnPickHeaderFragmentInteractionListener {
public void onFragmentInteraction(int res);
}
I ensure my Host Fragment will implement this interface by adding it during onAttach (inside PickHeaderFragment) like so:
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
Fragment f = getParentFragment();
mListener = (OnPickHeaderFragmentInteractionListener) getParentFragment();
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnFragmentInteractionListener");
}
}
Now, when the enter Button inside my PickHeaderFragment is clicked I call this event to let my Host Fragment know to change the root_frame_body:
Inside my Host Fragment I have:
#Override
public void onFragmentInteraction(int res) {
if (res == R.id.btnEnter) {
getChildFragmentManager().beginTransaction().replace(R.id.root_frame_body, new PickByItemBodyFragment()).commit();;
}
}
I am now able to change the layout (or which Fragment is displayed) in my Host Fragment after an event occurs inside a child Fragment.
Note: In my example I have nested Fragments, but you could just as easily have several Fragments within an Activity.
In summary I would recommend you follow a similar pattern of having a host Activity or Fragment and ensuring you have a FrameLayout added to your view to allow you to inflate whatever Fragment you need.
An added benefit to doing it this way is that you can segregate your code into separate Fragments also.
Leigh thank you for your answer but i don't know if you didn't understand my question or i didn't understand your answer...
anyway, i solved my problem through programatically adding the fragment in r=the onCreate of the activity and inserting the adding to an "if"
BlockFrag rb = new BlockFrag();
FragmentManager fragmentManager = getFragmentManager ();//declaring Fragment Manager
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction ();// declaring Fragment Transaction
if(condition)
{
editor.putBoolean("redBlock", true);
fragmentTransaction.add(R.id.redFrame, rb);//adding the fragment
}
needless to say i didn't declare the fragment in my activity layout and didn't perform any changes in the fragment class or fragment xml layout.

Android: GetMap() == null inside DialogFragment

Im trying put a MapFragment inside a DialogFragment, it works fine but i dont know how can I wait until getMap()!=null... hereĀ“s my code:
public class DialogMapa extends DialogFragment{
private SupportMapFragment fragment;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.layout_dialog_mapa, container,false);
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
SupportMapFragment fragment = new SupportMapFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.map, fragment).commit();
GoogleMap mapa = null;
try {
mapa =fragment.getMap();
} catch (Exception e) {
e.printStackTrace();
}
if (mapa==null) Toast.makeText(getActivity(), "NULL", Toast.LENGTH_SHORT).show();
return view;
}
}
and my inflate 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:padding="0dp" >
<FrameLayout
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
</RelativeLayout>
Thanks in advance!!
So with the new maps framework, that call is not guaranteed to return non null. The map is pretty complex and is initializing a lot of state on and off the render thread.
In your case it's safe to call after onFragmentsResumed() or after the fragment is attached to an activity. You could always use a handler to check again some point later.
getMap() is not null inside onStart() of the dialog fragment, after view created.

Fragments inside a fragment Android application

I'm trying to put 2 fragments inside a fragment. I found some code on internet but, as far as I could go, I don't succeed to put 2 fragments in 1 fragment.
I have seen tips dealing with FragmentManager and especially the method getChildFragmentManager() but I don't know how it works with 2 fragments.
For the story, I'm using an activity with ActionBar which creates 3 fragments. In one of them, I need to handle a graph and a kind of menu to change the graph scale. In this way, I need 2 fragments in one fragment.
Here is the code :
The fragment which handles the others:
public class GraphDisplayFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.graph_fragment, container, false);
return myFragmentView;
}
}
The code to draw the graph:
public class GraphFragment extends Fragment {
private static final int SERIES_NR = 1;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
GraphicalView myFragmentView = ChartFactory.getTimeChartView(this.getActivity(), getDateDemoDataset(), getDemoRenderer(),null);
return myFragmentView;
}
//some functions to set graph propreties
}
The XML files :
graph_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" >
<fragment
android:id="#+id/graph_fragment"
android:name="com.test.GraphFragment"
android:layout_width="match_parent"
android:layout_height="259dp" >
</fragment>
<fragment
android:name="com.test.GraphDetailFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/graph_detail_fragment">
</fragment>
</LinearLayout>
graph_detail.xml with a test implementation
<?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="211dp"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
The weird thing is, it works at the begining when I switch between fragments in the ActionBar but after 3-4 moves, I get this error :
android.view.InflateException: Binary XML file line #7: Error inflating class fragment
If anyone has the solution, it would be awesome!
So first off change your xml for graph_fragment.xml to this
<?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" >
<FrameLayout
android:id="#+id/graph_fragment_holder"
android:layout_width="match_parent"
android:layout_height="259dp" >
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/graph_detail_fragment_holder">
</FrameLayout>
</LinearLayout>
Then in code to inflate them from the fragment use something like this
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.graph_fragment,
container, false);
FirstChildFragment frag1 = (FirstChildFragment) getChildFragmentManager()
.findFragmentById(R.id.first_frag_layout);
SecondChildFragment frag1 = (SecondChildFragment) getChildFragmentManager()
.findFragmentById(R.id.second_frag_layout);
if (null == frag1) {
FirstChildFragment = new frag1();
FragmentTransaction transaction = getChildFragmentManager()
.beginTransaction();
transaction.add(R.id.graph_fragment_holder, frag1)
.addToBackStack(null).commit();
}
if (null == frag2) {
SecondChildFragment = new frag2();
FragmentTransaction transaction = getChildFragmentManager()
.beginTransaction();
transaction.add(R.id.graph_detail_fragment_holder, frag2)
.addToBackStack(null).commit();
}
return rootView;
}
MyFragment myFragment = (MyFragment)getChildFragmentManager().findFragmentById(R.id.my_fragment);
You can try to use the method *findFragmentById(fragment_id)* from SupportFragmentManager to get the instance of fragment from your .xml file and insert your fragment there.
Something like:
Fragment myFragment = getSupportFragmentManager().findFragmentById(R.id.myFragmentId);
I hope to help you.
Best regards.
Adriano

Nullpointer exception while getting EditText in an Activity

This is my layout file.
<RelativeLayout 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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".ImageDownloadActivity" >
<EditText
android:id="#+id/url_text"
android:layout_width = "match_parent"
android:layout_height="wrap_content"
android:hint="#string/url_field_hint"
android:inputType="textUri"
android:layout_alignParentTop="true"/>
<Button
android:id="#+id/download_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/download_url"
android:layout_below="#+id/url_text"
android:layout_centerHorizontal="true"
android:onClick="downloadImage"
/>
</RelativeLayout>
And this is my Fragment class
public class ImageDownloadFragment extends Fragment {
public ImageDownloadFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return (RelativeLayout)inflater.inflate(R.layout.image_download, null);
}
}
In an activity I am doing this.
imageDownloadFragment = new ImageDownloadFragment();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.image_download_layout, imageDownloadFragment);
fragmentTransaction.commit();
EditText urlText = (EditText)findViewById(R.id.url_text);
if(urlText!=null)
urlText.setText(urlEntered);
So I have an xml layout. I am inflating that in a Fragment and then I am replacing the fragment in a container. Everything works fine till this point. But after committing the FragmentTransaction, when I try to access the EditText View in the fragment, it gives me the null pointer exception. All the ids are correct in the R file. Please suggest
You should try:
public class ImageDownloadFragment extends Fragment {
private EditText ed;
public ImageDownloadFragment() {}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.image_download, container, false);
ed = (EditText)v.findViewById(R.id.url_text);
return v;
}
}
Since the EditText you want to retrieve is located (I suppose) inside your Fragment's layout.
Check findViewById returns NULL when using Fragment
In your onCreateView try to use
return (RelativeLayout)inflater.inflate(R.layout.image_download, container, false);
Hope it helps else please comment.

Categories

Resources