Fragment's view placed inside a FrameLayout throws a NullPointerException - java

I'm trying to use a FrameLayout on one of my activities. I want this FrameLayout to be a placeholder in an activity and I want to add/replace/remove fragments inside it.
I have a simple cafe app used for studying android. For simplicity I will post the code for the Cake and Breads category.
Problem: NullPointerException. I don't know the reason WHY my fragment's view is null. I'm guessing maybe the fragment lifecycle didn't run so the view was not inflated thus accessing the view throws a nullpointer? Please help me understand WHY a nullpointer is thrown.
Flow of the App
User selects a specific cake or bread in a ListFragment > CakeAndBreadActivity is called > Display Cake or Bread specific detail
I'm looking for: the explanation and reason behind the NullPointerException in the view and How can I display the Cakes and Bread details into the fragment when using FrameLayout.
NullPointerException
--------- beginning of crash
10-25 01:41:21.550 2374-2374/com.cafe E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.cafe, PID: 2374
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.cafe/com.cafe.CakeAndBreadActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)' on a null object reference
at com.cafe.CakeAndBreadDetailFragment.displayCakeAndBreadDetails(CakeAndBreadDetailFragment.java:97)
at com.cafe.CakeAndBreadActivity.displayCakeAndBreadDetails(CakeAndBreadActivity.java:30)
at com.cafe.CakeAndBreadActivity.onCreate(CakeAndBreadActivity.java:19)
at android.app.Activity.performCreate(Activity.java:6237)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
at android.app.ActivityThread.-wrap11(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:148) 
at android.app.ActivityThread.main(ActivityThread.java:5417) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
CakeAndBreadActivity
public class CakeAndBreadActivity extends Activity implements CakeAndBreadDetailFragment.onCakeAndBreadDetailFragmentListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cake_and_bread);
displayCakeAndBreadDetails();
}
public void displayCakeAndBreadDetails(){
Intent cakeAndBreadIntent = getIntent();
int cakeAndBreadId = Integer.valueOf(cakeAndBreadIntent.getIntExtra("cakeAndBreadNumber", 0));
CakeAndBreadDetailFragment cakeAndBreadDetail = new CakeAndBreadDetailFragment();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
cakeAndBreadDetail.displayCakeAndBreadDetails(cakeAndBreadId);
fragmentTransaction.replace(R.id.cake_and_bread_detail_frame_layout_id, cakeAndBreadDetail);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
#Override
public void onCakeAndBreadDetail(int id) {
}
}
activity_cake_and_bread.xml
<?xml version="1.0" encoding="utf-8"?>
<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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="com.cafe.CakeAndBreadActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="#+id/cake_and_bread_detail_frame_layout_id"/>
</LinearLayout>
CakeAndBreadDetailFragment
public class CakeAndBreadDetailFragment extends Fragment {
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private String mParam1;
private String mParam2;
private onCakeAndBreadDetailFragmentListener mListener;
public CakeAndBreadDetailFragment() {
}
public static CakeAndBreadDetailFragment newInstance(String param1, String param2) {
CakeAndBreadDetailFragment fragment = new CakeAndBreadDetailFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_cake_and_bread_detail, container, false);
}
public void onButtonPressed(int id) {
if (mListener != null) {
mListener.onCakeAndBreadDetail(id);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof onCakeAndBreadDetailFragmentListener) {
mListener = (onCakeAndBreadDetailFragmentListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement onCakeAndBreadDetailFragmentListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface onCakeAndBreadDetailFragmentListener {
// TODO: Update argument type and name
void onCakeAndBreadDetail(int id);
}
public void displayCakeAndBreadDetails(int id){
CakeAndBread cakeAndBread = (CakeAndBread)CakeAndBread.getCakeAndBreadList().get(id);
View cakeAndBreadView = getView();
TextView cakeAndBreadTextView = (TextView)cakeAndBreadView.findViewById(R.id.cake_and_bread_detail_fragment_id);
cakeAndBreadTextView.setText(cakeAndBread.getCakeAndBreadName() + " " + cakeAndBread.getCakeAndBreadNutritionFacts());
}
}
fragment_cake_and_bread_detail.xml
<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"
tools:context="com.cafe.CakeAndBreadDetailFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:id="#+id/cake_and_bread_detail_fragment_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
EDIT: as suggested, the fragment was not completely loaded when I'm trying to access the view, thus the nullpointerexception is thrown. Now my problem is the framelayout or the fragment doesn't show the textview that I placed in the fragment, how do I solve this? I'm passing cake and bread id and then setting the text in the setText(...) method of the TextView.

cakeAndBreadDetail.displayCakeAndBreadDetails(cakeAndBreadId);
fragmentTransaction.replace(R.id.cake_and_bread_detail_frame_layout_id, cakeAndBreadDetail);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
You are calling displayCakeAndBreadDetails(..) which calls displayCakeAndBreadDetails(..) which calls getView().
At that point you haven't inserted the fragment yet (happens after fragmentTransaction.commit();) so there is no view associated with the fragment. Hence getView() returns null.

#Kiskae is correct. You're calling cakeAndBreadDetail.displayCakeAndBreadDetails(cakeAndBreadId), when the fragment isn't ready which will result in a NullPointerException. Try:
public class CakeAndBreadActivity extends Activity implements CakeAndBreadDetailFragment.onCakeAndBreadDetailFragmentListener {
public void displayCakeAndBreadDetails(){
Intent cakeAndBreadIntent = getIntent();
int cakeAndBreadId = Integer.valueOf(cakeAndBreadIntent.getIntExtra("cakeAndBreadNumber", 0));
CakeAndBreadDetailFragment cakeAndBreadDetail = CakeAndBreadDetailFragment.newInstance(cakeAndBreadId);
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.cake_and_bread_detail_frame_layout_id, cakeAndBreadDetail);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
}
public class CakeAndBreadDetailFragment extends Fragment {
private static final String ARG_CAKE_AND_BREAD_ID = "ARG_CAKE_AND_BREAD_ID";
public CakeAndBreadDetailFragment() {
}
public static CakeAndBreadDetailFragment newInstance(int cakeAndBreadId) {
CakeAndBreadDetailFragment fragment = new CakeAndBreadDetailFragment();
Bundle args = new Bundle();
args.putInt(ARG_CAKE_AND_BREAD_ID, cakeAndBreadId);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_cake_and_bread_detail, container, false);
if (getArguments != null) {
int cakeAndBreadId = getArguments.getInt(ARG_CAKE_AND_BREAD_ID, -1);
if (cakeAndBreadId != -1) {
displayCakeAndBreadDetails(cakeAndBreadId);
}
}
return view;
}
public void displayCakeAndBreadDetails(int id){
...
}
}

Related

Fragment null object reference

So,im trying to call some methods of an extended fragment class into mainActivity and somehow i cant get the variable to reference the actual fragment.
It says im referencing a null object when im calling the frag.method() line.
Is it because of wrong id in findFragmentByid() inside of the onCreate() in mainActivity?
Ive tried using the id of the linear and constraint layout ('yes' and 'paint'),still get the error.
Main activity
public class MainActivity extends AppCompatActivity {
public ViewGroup.LayoutParams params;
private Path path=new Path();
private Paint brush = new Paint();
private PaintView paintView;
FirstFragment frag=new FirstFragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
frag = (FirstFragment) getSupportFragmentManager().findFragmentById(R.id.paint);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar2);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
toolbar.setMinimumWidth(20);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
switch (id){
case R.id.eraser:
frag.eraser();
return true;
case R.id.brush:
frag.brush();
return true;
}
return super.onOptionsItemSelected(item);
}
}
FirstFragment
public class FirstFragment extends Fragment {
public FirstFragment() {}
private PaintView paintView;
#Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState
) {
View rootView=inflater.inflate(R.layout.fragment_first,container,false);
LinearLayout Rl= (LinearLayout) rootView.findViewById(R.id.paint);
paintView=new PaintView(getActivity());
Rl.addView(paintView);
// Inflate the layout for this fragment
return rootView;
}
public void onViewCreated(#NonNull View view, Bundle savedInstanceState) {
paintView.brush();
super.onViewCreated(view, savedInstanceState);
/*
view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
NavHostFragment.findNavController(FirstFragment.this)
.navigate(R.id.action_FirstFragment_to_SecondFragment);
}
});
*/
}
public void eraser()
{
paintView.eraser();
}
public void brush(){
paintView.brush();
}
}
first_fragment.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:id="#+id/yes"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".FirstFragment" >
<LinearLayout
android:id="#+id/paint"
android:layout_width="409dp"
android:layout_height="0dp"
android:layout_marginStart="1dp"
android:layout_marginTop="1dp"
android:layout_marginEnd="1dp"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"></LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Error
Process: com.example.myapplication, PID: 29743
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.myapplication.FirstFragment.eraser()' on a null object reference
at com.example.myapplication.MainActivity.onOptionsItemSelected(MainActivity.java:50)
at android.app.Activity.onMenuItemSelected(Activity.java:4137)
at androidx.fragment.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:436)
at androidx.appcompat.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:196)
at androidx.appcompat.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:109)
at androidx.appcompat.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:109)
at androidx.appcompat.app.ToolbarActionBar$2.onMenuItemClick(ToolbarActionBar.java:64)
at androidx.appcompat.widget.Toolbar$1.onMenuItemClick(Toolbar.java:204)
at androidx.appcompat.widget.ActionMenuView$MenuBuilderCallback.onMenuItemSelected(ActionMenuView.java:781)
at androidx.appcompat.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:840)
at androidx.appcompat.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:158)
at androidx.appcompat.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:991)
at androidx.appcompat.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:981)
at androidx.appcompat.widget.ActionMenuView.invokeItem(ActionMenuView.java:625)
at androidx.appcompat.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:151)
at android.view.View.performClick(View.java:7125)
at android.view.View.performClickInternal(View.java:7102)
at android.view.View.access$3500(View.java:801)
at android.view.View$PerformClick.run(View.java:27336)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
29743-29743/com.example.myapplication I/Process: Sending signal. PID: 29743 SIG: 9
Welp,the problem was caused by the fact that there was no fragment in the respective layout since the layout(yes,paint) was INSIDE the fragment i was trying to call,so basically id mismatch.Stupid me.

null object reference of TextView in Fragment

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.

Cannot setText() of an EditText field (Android) - NullPointerException [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
textView setText() NullPointerException
(3 answers)
Closed 5 years ago.
When I try to setText() on an EditText I keep getting this error, I can't see where I'm going wrong. I'd like to understand the logic behind this error. I'm sure it's something small but it's really bugging me now.
01-25 10:20:44.267
14325-14325/com.example.gregsquibbs.greg_squibbs_todoapp3
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.gregsquibbs.greg_squibbs_todoapp3, PID: 14325
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.example.gregsquibbs.greg_squibbs_todoapp3/com.example.gregsquibbs.greg_squibbs_todoapp3.EditTodo.EditTodoActivity}:
java.lang.NullPointerException: Attempt to invoke virtual method 'void
android.widget.EditText.setText(java.lang.CharSequence)' on a null
object reference
at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at
com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual
method 'void android.widget.EditText.setText(java.lang.CharSequence)'
on a null object reference
at
com.example.gregsquibbs.greg_squibbs_todoapp3.EditTodo.EditTodoFragment.setMessage(EditTodoFragment.java:56)
at
com.example.gregsquibbs.greg_squibbs_todoapp3.EditTodo.EditTodoActivity.onCreate(EditTodoActivity.java:41)
at android.app.Activity.performCreate(Activity.java:6975)
at
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) 
at android.app.ActivityThread.-wrap11(Unknown Source:0) 
at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593) 
at android.os.Handler.dispatchMessage(Handler.java:105) 
at android.os.Looper.loop(Looper.java:164) 
at android.app.ActivityThread.main(ActivityThread.java:6541) 
at java.lang.reflect.Method.invoke(Native Method) 
at
com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
This is where I create the etMessage and use setText()
public class EditTodoFragment extends Fragment implements EditTodoContract.View {
private EditTodoContract.Presenter presenter;
private EditText etMessage;
public EditTodoFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.edit_todo_fragment, container, false);
System.out.println("Step 2 - Fragment check");
etMessage = (EditText) view.findViewById(R.id.etMessage);
return view;
}
public void setPresenter(EditTodoContract.Presenter todoPresenter) {
this.presenter = todoPresenter;
}
public String getMessage() {
String message = etMessage.getText().toString();
return message;
}
public void setMessage(String message) {
etMessage.setText(message);
}
}
Here is the XML file
<FrameLayout 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"
tools:context="com.example.gregsquibbs.greg_squibbs_todoapp3.EditTodo.EditTodoActivity">
<EditText
android:id="#+id/etMessage"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:background="#drawable/rect"
android:ems="10"
android:gravity="top"
android:inputType="textShortMessage" />
<Button
android:id="#+id/bSave"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:onClick="saveButtonClicked"
android:layout_gravity="center_horizontal|bottom"
/>
Here is where setMessage() gets called in the activity
public class EditTodoActivity extends AppCompatActivity {
private String message;
private int position;
private EditTodoFragment editTodoFragment;
private EditTodoPresenter editTodoPresenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.edit_todo_activity);
System.out.println("Step 1");
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.contentFrameContainer);
if (fragment == null){
editTodoFragment = new EditTodoFragment();
fm.beginTransaction()
.add(R.id.contentFrameContainer, editTodoFragment)
.commit();
editTodoPresenter = new EditTodoPresenter(editTodoFragment);
}
message = getIntent().getStringExtra(IntentConstants.INTENT_MESSAGE_DATA);
position = getIntent().getIntExtra(IntentConstants.INTENT_ITEM_POSITION, -1);
editTodoFragment.setMessage(message);
}
public void saveButtonClicked(View v) {
if(editTodoFragment.getMessage().equals("")) {
} else {
String changedMessage = (editTodoFragment.getMessage());
Intent intent = new Intent();
intent.putExtra(IntentConstants.INTENT_CHANGED_MESSAGE, changedMessage);
intent.putExtra(IntentConstants.INTENT_ITEM_POSITION, position);
finish();
}
}
}
Edit: On this line in the fragment
etMessage = (EditText) view.findViewById(R.id.messageField);
When I hover over the casting (EditText) it says
Casting 'view.findViewById(R.id.messageField)' to 'EditText' is redundant less... (⌘F1)
This inspection reports unnecessary cast expressions.
I don't know whether that has anything to do with it or not.
There is no garrenty that editTodoFragment.setMessage(message); will be called after your EditText initialized by this line
etMessage = (EditText) view.findViewById(R.id.etMessage);
In your case your code is setting text to EditText before it's initialized.
Best practice is send data via Bundle to Fragment and set Text after EditText is initialized.
Check this answer
Sample Code:
In EditTodoActivity
message = getIntent().getStringExtra(IntentConstants.INTENT_MESSAGE_DATA);
if (fragment == null){
editTodoFragment = new EditTodoFragment();
//
Bundle bundle = new Bundle();
bundle.putInt(key, message);
fragment.setArguments(bundle);
fm.beginTransaction()
.add(R.id.contentFrameContainer, editTodoFragment)
.commit();
editTodoPresenter = new EditTodoPresenter(editTodoFragment);
}
In EditTodoFragment onCreate
Bundle bundle = this.getArguments();
if (bundle != null) {
message = bundle.getString(key, defaultValue);
}
In EditTodoFragment onCreateView
etMessage = (EditText) view.findViewById(R.id.etMessage);
etMessage.setText(message);
Probably the error is that you have defined etMessage in other file than edit_todo_fragment. That's why you are not getting a compilation error, since the reference to etMessage exists, but it does not exists in your inflated view so thus you got the NPE.
As I understood from logs you're calling setMessage method from onCreate method of your activity. But the problem is Activity's onCreate is called earlier than Fragment's onCreateView, so your EditText is not initialized at that moment.
first you have to define this EditText belong to witch view
then, after you inflate your view you should do this.
View view = inflater.inflate(R.layout.edit_todo_fragment, container, false);
etMessage = view.findViewById(R.id.etMessage);
etMessage.setText("your message...")
if you call set text before it, you see this error
or
this view (etMessage) is not in this layout (edit_todo_fragment)

NullPointerException when showing a ViewPager a second time

I am using a ViewPager fragment which has two fragments as children. This works great, however when I replace the ViewPager fragment by another fragment and replace this fragment by the ViewPager fragment my application crashes with the following NullPointerException:
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.util.ArrayList.size()' on a null object reference
at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:667)
at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:211)
at android.support.v4.view.ViewPager.onRestoreInstanceState(ViewPager.java:1319)
at android.view.View.dispatchRestoreInstanceState(View.java:13756)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2888)
at android.view.View.restoreHierarchyState(View.java:13734)
at android.support.v4.app.Fragment.restoreViewState(Fragment.java:468)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1094)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:517)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5294)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)
My ViewPager fragment consists of the following source code instanciating the two child fragments in case they are null. Furthermore, the ViewPagerAdapter implementation is instanciated and assigned to the ViewPager.
public class ConnectionPasswordViewPagerFragment extends Fragment
{
private ViewPager vpConnectionPassword;
private ConnectionPasswordViewPagerAdapter paConnectionPassword;
private ConnectionPasswordGeneratorMACAddress passwordGeneratorMACAddress;
private ConnectionPasswordGeneratorSerialNumber passwordGeneratorSerialNumber;
public ConnectionPasswordViewPagerFragment()
{
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if ((this.passwordGeneratorSerialNumber == null) && (this.passwordGeneratorMACAddress == null))
{
this.passwordGeneratorMACAddress = new ConnectionPasswordGeneratorMACAddress();
this.passwordGeneratorSerialNumber = new ConnectionPasswordGeneratorSerialNumber();
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_connection_password_view_pager, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
/*if (this.paConnectionPassword == null)
{*/
this.paConnectionPassword = new ConnectionPasswordViewPagerAdapter(this.getChildFragmentManager(), this.getActivity(), this.passwordGeneratorMACAddress, this.passwordGeneratorSerialNumber);
//}
this.vpConnectionPassword = (ViewPager) this.getActivity().findViewById(R.id.vpConnectionPassword);
this.vpConnectionPassword.setAdapter(this.paConnectionPassword);
}
}
The ViewPagerAdapter shown below implementation keeps the reference to the child fragments in an ArrayList and implements the metods getItem(), getCount() as well as getPageTitle(). The class ViewPagerFragment simply extends the support Fragment class and provides the abstract method getPageTitleStringID() implemented by the child fragments.
public class ConnectionPasswordViewPagerAdapter extends FragmentStatePagerAdapter
{
private static final byte NUMBER_OF_FRAGMENTS = (byte) 2;
private ArrayList<ViewPagerFragment> childFragments;
private Activity displayActivity;
public ConnectionPasswordViewPagerAdapter(FragmentManager fragmentMgm, Activity displayAct, ConnectionPasswordGeneratorMACAddress generatorMACAddress, ConnectionPasswordGeneratorSerialNumber generatorSerialNumber)
{
super(fragmentMgm);
this.childFragments = new ArrayList<>(ConnectionPasswordViewPagerAdapter.NUMBER_OF_FRAGMENTS);
this.setDisplayActivity(displayAct);
if (generatorMACAddress != null)
{
this.childFragments.add(generatorMACAddress);
}
if (generatorSerialNumber != null)
{
this.childFragments.add(generatorSerialNumber);
}
}
public Activity getDisplayActivity()
{
return this.displayActivity;
}
public void setDisplayActivity(Activity value)
{
this.displayActivity = value;
}
#Override
public Fragment getItem(int position)
{
return this.childFragments.get(position);
}
#Override
public int getCount()
{
return ConnectionPasswordViewPagerAdapter.NUMBER_OF_FRAGMENTS;
}
#Override
public CharSequence getPageTitle(int position)
{
return this.getDisplayActivity().getString(this.childFragments.get(position).getPageTitleStringID());
}
}
Thanks for your help!
I fixed the issue by simply creating the fragment containing the view pager every time I call the support fragment manager's replace method.
public void onSwitchToConnectionPasswordGenerator(View clickedView)
{
this.fragConnectionPassword = new ConnectionPasswordViewPagerFragment();
this.getSupportFragmentManager().beginTransaction().replace(R.id.flFragmentContainer, this.fragConnectionPassword).commitAllowingStateLoss();
}
I think your Viewpager is in Fragment, and this fragment have setRetainInstance set to true (i have this error too when i try to retain the parent fragment)
Better way is to you can check for FragmentManager to get Fragment if its there, if not then create a new instance as follows:
FragmentManager manager = getSupportFragmentManager();
Fragment fragment = manager.findFragmentByTag("YourFragmentName");
if(fragment == null)
fragment = new YourFragment();
FragmentTransaction fragmentTransaction = manager.beginTransaction();
fragmentTransaction.replace(Your_Fragmnet_Container_Layout_id, fragment, fragment.getClass().getSimpleName());
fragmentTransaction.commit;

IllegalArgumentException caused by binary XML file (Android)

i have a basic navigation with 3 tabs. One of them contains a fragment with google maps in it. However the navigation isn't good, it keeps crashing after i select the tab for the second time.
It says it is because of the XML file of the maps which in my opinion doesn't have anything wrong. Can anyone see my error which i am blinded for right now?
Logcat :
android.view.InflateException: Binary XML file line #7: Error inflating class fragment
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:719)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:761)
at android.view.LayoutInflater.inflate(LayoutInflater.java:498)
at android.view.LayoutInflater.inflate(LayoutInflater.java:398)
at com.example.dell.animalz.MapsFragment.onCreateView(MapsFragment.java:22)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1504)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:942)
at android.support.v4.app.FragmentManagerImpl.attachFragment(FragmentManager.java:1297)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:672)
at
android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1484)
at
android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:482)
at
android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1073)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:555)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:514)
at android.support.v4.view.ViewPager.setCurrentItem(ViewPager.java:495)
at com.example.dell.animalz.HomeActivity.onTabSelected(HomeActivity.java:67)
at com.android.internal.app.ActionBarImpl.selectTab(ActionBarImpl.java:674)
at com.android.internal.app.ActionBarImpl$TabImpl.select(ActionBarImpl.java:1217)
at
com.android.internal.widget.ScrollingTabContainerView$TabClickListener.onClick(ScrollingTabContainerView.java:976)
at android.view.View.performClick(View.java:4637)
at android.view.View$PerformClick.run(View.java:19422)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5586)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalArgumentException: Binary XML file line #7: Duplicate id 0x7f070067, tag null, or parent id 0x0 with another fragment for com.google.android.gms.maps.SupportMapFragment
at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:297)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:691)
            
HomeActivity.java
public class HomeActivity extends FragmentActivity implements ActionBar.TabListener {
ViewPager mViewPager = null;
private TabsMenuAdapter mAdapter;
private ActionBar actionBar;
private String []tabs = {"News", "Animalz", "Maps"};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home_layout);
mViewPager = (ViewPager)findViewById(R.id.viewpager1);
actionBar = getActionBar();
mAdapter = new TabsMenuAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
for(String tab_names : tabs){
actionBar.addTab(actionBar.newTab().setText(tab_names).setTabListener(this));
}
mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener(){
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
mViewPager.setCurrentItem(tab.getPosition());
}
}
Maps.java
public class MapsFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.maps_layout, container, false);
return rootView;
}
}
Maps.xml
<?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">
<fragment
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment"/>
</RelativeLayout>
Any help would be appreciated, thanks in advance !
You have to remove the MapFragment in the onDestroyView() method of the Fragment that contains the map, with referring to this answer, you must do the following:
// override the onDestroyView of the fragment
#Override
public void onDestroyView() {
super.onDestroyView();
MapFragment f = (MapFragment) getFragmentManager()
.findFragmentById(R.id.the_map);
if (f != null)
getFragmentManager().beginTransaction().remove(f).commit();
}
Every time check your parent view empty or not. If yes then remove. Change your Maps.java.
private static View view;
#Override
public View onCreateView(LayoutInflater inflater,ViewGroup group,Bundle bundle)
{
if(view!=null)
{
ViewGroup parent =(ViewGroup)view.getParent();
if(parent!=null)
parent.removeView(view);
}
try{
view=inflater.inflate(R.layout.maps, group, false);
........
}
catch(Exception e)
{
Log.e("ERROR", ""+e);
}
return view;
}

Categories