Trying to Communicating FragmentA to FragmentB, doing is taking numeric value from fragmentA adding them and displaying result in fragmentB using interface, but I got nullpointerException, I have look many times in the code but seems everything is fine but getting nullpointerException showing line 34 in FragmentA
listener.setResult(result+" ");
Here's My FragmentA
public class FragmentA extends Fragment{
MyFragmentInterface listener;
Button buton;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view =inflater.inflate(R.layout.fragment_a,container,false);
final EditText editText= (EditText) view.findViewById(R.id.edit_text1);
final EditText editText2= (EditText) view.findViewById(R.id.edit_text2);
buton= (Button) view.findViewById(R.id.button);
buton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int num1=Integer.parseInt(editText.getText().toString());
int num2=Integer.parseInt(editText2.getText().toString());
int result=num1+num2;
listener.setResult(result+" ");
}
});
return view;
}
#Override
public void onAttach(Context context) {
listener= (MyFragmentInterface) context;
super.onAttach(context);
}
}
Here's my fragment_a.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/edit_text1"
android:inputType="number"
android:textSize="30sp"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:id="#+id/edit_text2"
android:textSize="30sp"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Calculate"
android:id="#+id/button"
android:background="#null"
android:textAllCaps="false"/>
</LinearLayout>
FragmentB.java
public class FragmentB extends Fragment {
TextView textView;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
textView= (TextView) getActivity().findViewById(R.id.textview);
return inflater.inflate(R.layout.fragment_b,container,false);
}
public void putresult(String r){
textView.setText(r);
}
}
fragment_b.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
android:id="#+id/textview"
android:text="Text will appear here"/>
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity implements MyFragmentInterface {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentA fragmentA=new FragmentA();
FragmentManager fragmentManager=getFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.linear1,fragmentA);
fragmentTransaction.commit();
FragmentB fragmentB=new FragmentB();
FragmentManager fragmentManager1=getFragmentManager();
FragmentTransaction fragmentTransaction1=fragmentManager1.beginTransaction();
fragmentTransaction1.addToBackStack(null);
fragmentTransaction1.replace(R.id.linear2,fragmentB);
fragmentTransaction1.commit();
}
#Override
public void setResult(String result) {
FragmentB fragmentnew=new FragmentB();
fragmentnew= (FragmentB) getFragmentManager().findFragmentById(R.id.linear2);
fragmentnew.putresult(result);
}
}
MyFragmentInterface.java
public interface MyFragmentInterface {
public void setResult(String result);
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="queendevelopers.com.communicate.MainActivity"
android:weightSum="2"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="#+id/linear1"
android:orientation="vertical" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="#+id/linear2"
android:orientation="vertical" />
</LinearLayout>
error log:
08-16 16:11:42.307 7630-7630/queendevelopers.com.communicate E/AndroidRuntime: FATAL EXCEPTION: main
Process: queendevelopers.com.communicate, PID: 7630
java.lang.NullPointerException: Attempt to invoke interface method 'void queendevelopers.com.communicate.MyFragmentInterface.setResult(java.lang.String)' on a null object reference
at queendevelopers.com.communicate.FragmentA$1.onClick(FragmentA.java:34)
at android.view.View.performClick(View.java:4832)
at android.view.View$PerformClick.run(View.java:19844)
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:5319)
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:1016)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:811)
To expand on the comment I made that solved the problem:
The original issue was not to do with your interface callback (this was not the root cause of the NullPointerException).
When the callback method setResult(String result) was invoked this line :
fragmentnew.putresult(result); was causing the null pointer because, in the method putresult in your fragment there is a null reference to your textView (textView.setText(r);).
For every Activity you can have an associated view heirarchy (your XML file), this is set by setContentView() in onCreate(). Now if you try and reference any #+id widgets from the XML layout you can cast relevant object type : TextView, EditText, ListView. Fragments (which are attached to a hosting Activity) can also have their own layouts, this is inflated in onCreateView(). Your final code should look something like this:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_b,container,false);
textView = (TextView) view.findViewById(R.id.textview);
return view;
}
Your view object now contains your view hierarchy for the inflated XML Layout, from which you can access all widgets.
The line of code that was incorrect was:
textView = (TextView) getActivity().findViewById(R.id.textview);
The reason being you are using the convenience method getActivity() this will return the hosting Activity reference - thus you now will have access to the hosting Activity - used a lot for gaining a Context of other purposes, however your view id reference is invalid because it is in the view hierarchy of your inflated layout in your fragment.
Try this method inside your Fragment
#Override
public void onAttach(Context context) {
super.onAttach(context);
listener = (MyFragmentInterface) getActivity();
}
try this
(((MyFragmentInterface)getActivity()).setResult(result+" ");
Change in Fragment A:
from:
buton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int num1=Integer.parseInt(editText.getText().toString());
int num2=Integer.parseInt(editText2.getText().toString());
int result=num1+num2;
listener.setResult(result+" ");
}
});
To
buton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int num1=Integer.parseInt(editText.getText().toString());
int num2=Integer.parseInt(editText2.getText().toString());
int result=num1+num2;
((MainActivity) getActivity()).setResult(result+" ");
}
});
Because I think your listener object is not initialised before being used so try this answer please.
Related
This question already has answers here:
Avoiding NullPointerException in Java
(66 answers)
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 7 months ago.
i'm working with fragments. I have created a List fragment and a Detail fragment.
when i click on an item in the list the app crashes and it gives the following null pointer exception.
Attempt to invoke virtual method 'void
android.widget.TextView.setText(java.lang.CharSequence)' on a null
object reference
I tried solutions of similar question but nothing works for me.
here is my Main Activity:
public class MainActivity extends AppCompatActivity implements ListFrag.ItemSelected {
TextView tvDescription;
ArrayList<String> descriptions;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvDescription = (TextView) findViewById(R.id.tvDescription);
descriptions = new ArrayList<>();
descriptions.add("Description for item 1");
descriptions.add("Description for item 2");
descriptions.add("Description for item 3");
}
#Override
public void onItemSelected(int index) {
tvDescription.setText(descriptions.get(index));
}
}
List Fragment:
public class ListFrag extends ListFragment {
ItemSelected activity;
public interface ItemSelected
{
void onItemSelected(int index);
}
public ListFrag() {
// Required empty public constructor
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
activity = (ItemSelected) context;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ArrayList<String> data = new ArrayList<>();
data.add("1.This is item 1");
data.add("2.This is item 2");
data.add("3.This is item 3");
setListAdapter(new ArrayAdapter<>( getActivity() , android.R.layout.simple_list_item_1,data));
}
#Override
public void onListItemClick(#NonNull ListView l, #NonNull View v, int position, long id) {
activity.onItemSelected(position);
} }
Detail Fragment:
public class DetailFrag extends Fragment {
public DetailFrag() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_detail, container, false);
}
}
activity_main layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="horizontal"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/listFrag"
android:name="com.example.fragmentspart1.ListFrag"
android:layout_width="8dp"
android:layout_height="match_parent"
android:layout_weight="1"
tools:layout="#layout/fragment_list" />
<androidx.fragment.app.FragmentContainerView
android:id="#+id/detailFrag"
android:name="com.example.fragmentspart1.DetailFrag"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="2"
tools:layout="#layout/fragment_detail" />
</LinearLayout>
fragment_list layout:
<?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:orientation="vertical"
android:background="#FFFFFF"
tools:context=".ListFrag">
<ListView
android:id="#+id/lvList"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
fragment_detail layout :
<?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:orientation="vertical"
android:background="#color/design_default_color_secondary"
tools:context=".DetailFrag">
<TextView
android:id="#+id/tvDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:layout_marginRight="20dp"
android:text="#string/textview"
android:textColor="#FFFFFF"
android:textSize="20sp"
android:textStyle="bold" />
</LinearLayout>
(TextView) findViewById(R.id.tvDescription);
returns null in MainActivity because your TextView tvDescription is in fragment_detail layout.
You must move this line to onViewCreated() of your DetailFragment and in onItemSelected() you must create a new instance of DetailFragmet and pass data as arguments to the DetailFragment instance.
After you start the DetailFragment you can do following in DetailFragment:
override onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
tvDescription = (TextView) findViewById(R.id.tvDescription);
// get your list item data from arguments
tvDescription.setText(descriptions.get(index));
}
I think I have same problem here but there is no answer.
I have an Activity with an ViewPager and a FrameLayout which will contain a Fragment. It look like this :
Activity
|— ViewPager
|-FragmentA
|— Framelayout
|— FragmentB
|— FragmentC (here I called fragmentC.setTargetFragment method).
When I rotate the device. I 'll get this error :
E/AndroidRuntime(10354): Caused by: java.lang.IllegalStateException: Fragment no longer exists for key android:target_state: index 1
E/AndroidRuntime(10354): at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:586)
E/AndroidRuntime(10354): at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:885)
E/AndroidRuntime(10354): at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1136)
E/AndroidRuntime(10354): at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1118)
E/AndroidRuntime(10354): at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:1922)
E/AndroidRuntime(10354): at android.support.v4.app.Fragment.performCreate(Fragment.java:1776)
E/AndroidRuntime(10354): at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:915)
E/AndroidRuntime(10354): at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1136)
E/AndroidRuntime(10354): at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1118)
E/AndroidRuntime(10354): at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:1922)
E/AndroidRuntime(10354): at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:266)
E/AndroidRuntime(10354): at com.example.android.animationsdemo.MyActivity.onCreate(MyActivity.java:20)
Everything work fine if I don't call fragmentC.setTargetFragment method or I don't set the Adapter for the Viewpager.
Here are my Code :
Activity :
public class MyActivity extends FragmentActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
ViewPager mViewPager = (ViewPager) findViewById(R.id.pager);
TabsAdapter tabsAdapter = new TabsAdapter(this);
mViewPager.setAdapter(tabsAdapter);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MyFragmentB fragmentA = new MyFragmentB();
getSupportFragmentManager().beginTransaction().add(R.id.flContainer, fragmentA,
"TAG").addToBackStack("back").commit();
}
});
}
public static class TabsAdapter extends FragmentPagerAdapter {
private final Context mContext;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(FragmentActivity activity) {
super(activity.getSupportFragmentManager());
mContext = activity;
TabInfo tabInfo = new TabInfo(MyFragmentA.class, null);
mTabs.add(tabInfo);
}
#Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
#Override
public int getCount() {
return mTabs.size();
}
}
}
The Activity layout :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="#+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add Fragment B"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="300dip"
android:id="#+id/flContainer" >
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="wrtadfa"/>
</FrameLayout>
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_below="#+id/rlContainer"
android:layout_width="match_parent"
android:layout_height="300dip" />
</LinearLayout>
And FragmentA :
public class MyFragmentA extends Fragment {
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_a, container, false);
return myFragmentView;
}
}
FragmentA layout :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment A" />
</LinearLayout>
FragmentB :
public class MyFragmentB extends Fragment implements MyFragmentC.CallBack {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_b, container, false);
myFragmentView.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MyFragmentC fragmentA = new MyFragmentC();
//This caused the problem
fragmentA.setTargetFragment(MyFragmentB.this, 0);
getChildFragmentManager().beginTransaction().add(R.id.flContainer2, fragmentA, "TAG").addToBackStack("back").commit();
}
});
return myFragmentView;
}
}
fragment_b.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#888888"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment B" />
<TextView
android:id="#+id/c_received"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="#+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add Fragment C"/>
<FrameLayout
android:id="#+id/flContainer2"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</LinearLayout>
FragmentC :
public class MyFragmentC extends Fragment {
public static interface CallBack{
//some call back
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if(getTargetFragment() != null){
CallBack callBack = (CallBack) getTargetFragment();
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_c, container, false);
return myFragmentView;
}
}
fragment_c.xml :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#888888"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="It's Fragment C" />
</LinearLayout>
I know that I can work around by let the Activity implement the MyFragmentC.CallBack instead of FragmentB implement it.
But I just curious why does it happen ???
If I don't set Adapter for the viewpager or don't call "setTargetFragment" in FragmentC. Then everything work fine.
So sorry because I don't know how to format the code well in here and it's a long post. Any help could be appreciate.
Please have a look into google's discussion thread where they are suggested to remove setTargetFragment() and instead use getParentFragment(). More detail is provided here : https://code.google.com/p/android/issues/detail?id=54520
I think it is about your getItem() method in your adapter. Rather then using FragmentPagerAdapter you can use FragmentStatePagerAdapter and put an if check for your getItem method. After pausing and resuming (in your case this is orientation change) probably your reference to the object get lost.
In google dev forums they also say not to use setTargetFragment method since it is buggy, you can try using getParentFragment for that reason.
I am new to the android platform so I know I am just missing something by here is what I have
<!-- activity_main -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.example_app.MainActivity"
tools:ignore="MergeRootFrame" >
<fragment
android:id="#+id/mainFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.example.example_app.MainFragment"
/>
</FrameLayout>
Then I created a fragment called MainFragment.java.
public class MainFragment extends Fragment {
public TextView displayTextView;
public MainFragment() { }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
this.displayTextView = (TextView)rootView.findViewById(R.id.displayTextView);
return rootView;
}
}
I add the fragment in the OnCreate function in the activity and it seems to be adding everything okay but when I click on the button nothing happens, I logged the function to see its being called but setting the textview doesn't do anything. What am I doing wrong?
<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="com.example.example_app.MainActivity$PlaceholderFragment" >
<Button
android:id="#+id/button10"
android:textColor="#ffffff"
android:textSize="34dp"
android:text="10%"
android:layout_below="#id/amountEditText"
android:background="#drawable/pct_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doSomething"
/>
<TextView
android:text="Blah Blah Blah"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/displayTextView"
></TextView>
</RelativeLayout>
And here is the click Event in the MainActivity.java
public void doSomething(View v) {
this.mainFragment.displayTextView.setText("Nothing to set for some reason!");
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
//
this.mainFragment = (MainFragment) getSupportFragmentManager().findFragmentById(R.id.mainFragment);
mainFragment = new MainFragment();
getSupportFragmentManager().beginTransaction().add(mainFragment, "mainFragment").commit();
}
}
Declaring onClick-Listeners via XML is possible if you work with Activities. According to the Google API, however, you need to declare OnClickListeners programmatically if you use Fragments.
[...] You can also declare the click event handler programmatically rather than in an XML layout. This might be necessary if you instantiate the Button at runtime or you need to declare the click behavior in a Fragment subclass.
Source:
http://developer.android.com/guide/topics/ui/controls/button.html
So you may want to use this instead:
public class MainFragment extends Fragment {
public TextView displayTextView;
public Button yourButton;
public MainFragment() { }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
this.displayTextView = (TextView)rootView.findViewById(R.id.displayTextView);
yourButton = (Button)rootView.findViewById(R.id.button10);
yourButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
displayTextView.setText("Nothing to set for some reason!");
}
});
return rootView;
}
}
The problem is the way you try to execute the button click. From your question i understand that Button and TextView is in Fragment view. So do why are Trying to access it in activity ?? It is wrong, then there is no point of using Fragments. Also this will lead to many serious issues later .
Fragments are Reusable components so all the functionalities of a fragment must stay inside the Fragment Class
Change Fragment code :
public class MainFragment extends Fragment {
public TextView displayTextView;
public Button yourButton;
public MainFragment() { }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
this.displayTextView = (TextView)rootView.findViewById(R.id.displayTextView);
yourButton = (Button)rootView.findViewById(R.id.button10);
//Setting click listener for button in fragment
yourButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
displayTextView.setText("Nothing to set for some reason!");
}
});
return rootView;
}
}
and remove android:onClick="doSomething" from XML
I am trying to do a very basic example with Fragments.
Structure : Fragment1 -> Fragment1Activity, Fragment2 -> Fragment2Activity.
Both activities have a STATIC Fragment in it.
Here are the XMLs:
activity_for_fragment_1.xml
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/fragment_1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.xx.fragmentstutorial1.Fragment1"
tools:context="com.xx.fragmentstutorial1.Fragment1Activity"/>
fragment1.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/textview_fragment_1"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="0.60"
android:text="This is Fragment 1"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText
android:id="#+id/edittext_fragment_1_text"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="0.20"
android:text="Type your message here..." >
<requestFocus />
</EditText>
<Button
android:id="#+id/button_fragment_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Click Me" />
</LinearLayout>
activity_for_fragment_2.xml
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/fragment_2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.xx.fragmentstutorial1.Fragment2"
tools:context="com.xx.fragmentstutorial1.Fragment2Activity"/>
fragment_2.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/textview_fragment_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="This is Fragment 2"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/textview_fragment_2_result"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="I will display text from \nFragment 1"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
Now, I have an Edittext and button in the fragment_1. When I click on the button, I want to get the text entered in EditText and set it to the textview(textview_fragment_2_result) in fragment_2
I was able to achieve this, but, I am not very convinced, that the approach I took was good enough. Please look at the java code below..
Fragment1Activity.java
public class Fragment1Activity extends SherlockFragmentActivity implements Fragment1.ButtonClickListener{
Fragment1 fragment1;
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_for_fragment_1);
System.out.println("onCreate Fragment1Activity");
fragment1 = (Fragment1) getSupportFragmentManager().findFragmentById(R.id.fragment_1);
}
#Override
public void onButtonClick(String message) {
System.out.println("onButtonClick Fragment1Activity");
startActivity(new Intent(this, Fragment2Activity.class).putExtra("message", message));
}
}
Fragment1.java
public class Fragment1 extends SherlockFragment {
EditText message;
Button clickme;
ButtonClickListener listener;
public interface ButtonClickListener{
public void onButtonClick(String message);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof ButtonClickListener)
listener = (ButtonClickListener) activity;
else {
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
System.out.println("onCreateView Fragment1");
View view = inflater.inflate(R.layout.fragment_1, container, false);
message = (EditText) view.findViewById(R.id.edittext_fragment_1_text);
clickme = (Button) view.findViewById(R.id.button_fragment_1);
clickme.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (!message.getText().toString().equalsIgnoreCase("")) {
System.out.println("Message in Fragment1 = "+message.getText().toString());
listener.onButtonClick(message.getText().toString());
} else {
Toast.makeText(getActivity(),
"Please enter some message...", Toast.LENGTH_LONG)
.show();
}
}
});
return view;
}
}
Fragment2Activity.java
public class Fragment2Activity extends SherlockFragmentActivity {
Fragment2 fragment2;
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_for_fragment_2);
fragment2 = (Fragment2) getSupportFragmentManager().findFragmentById(R.id.fragment_2);
fragment2.setMessage(getIntent().getExtras().getString("message").toString());
}
}
Fragment2.java
public class Fragment2 extends SherlockFragment {
String msg;
TextView textview;
public Fragment2() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_2, container, false);
textview = (TextView) view
.findViewById(R.id.textview_fragment_2_result);
textview.setText(msg);
return view;
}
public void setMessage(String message) {
msg = message;
textview.setText(msg);
}
}
I have set the text for textview in setMessage() of Fragment2.java, which I think is not a good approach. If i comment that out, I don't see any text in the textview of Fragment2.
Can someone help me out, on how to pass values between two static fragments correctly.
You should go with interface
Follow the Diagram Here :
Communication Between Two Fragment is Done Via Activity using Interface
Fragment A-------------------------->Activity-------------------->Fragment B
(defines Interface) (Implement interface) (pass it other Fragment B)
Hope this could help
Check This Out
What you have is mostly good. The part of transferring the data from Fragment1 to Activity1 is good. Once the data gets to Activity2, you are setting it in Fragment2. I would change this part a little.
In Activity2:
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_for_fragment_2);
fragment2 = (Fragment2) getSupportFragmentManager().findFragmentById(R.id.fragment_2);
fragment2.setArguments(getIntent().getExtras());
}
and in Fragment2.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Bundle bundle = getArguments();
String message = bundle.getString("message");
View view = inflater.inflate(R.layout.fragment_2, container, false);
textview = (TextView) view
.findViewById(R.id.textview_fragment_2_result);
textview.setText(message);
return view;
}
Your approach seems correct. The connection between your Fragment1 and Activity1 is just like in the fragments guideline. Your fragment1 shouldn't know about fragment2 therefore it's OK to pass the responsibility to the fragment's container/parent - activity1 - that knows what to do with the data. This time again your approach is correct - activity1 starts it's slave/child etc. and is responsible to start it with correct data (passed through the intent extras). And then again you have a correct approach - when your activity2 is created you populate it's views with the appropriate content/data (the message) that was meant to be displayed in this activity and given to it by the "parent" activity.
In a class i am adding a Fragment programatically.
This Fragment contains a Button, which i want to have an onClick implementation.
Here is the class i have:
public class ShareProduct extends SherlockFragmentActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.share_product);
FragmentManager fragmentManager = getSupportFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
ProductFragment1 fragment = new ProductFragment1();
fragmentTransaction.add(R.id.share_product_parent, fragment);
fragmentTransaction.commit();
Button done_button = (Button) fragment.getView().findViewById(
R.id.done_product_1);
done_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
ProductFragment2 fragment = new ProductFragment2();
fragmentTransaction
.replace(R.id.share_product_parent, fragment);
fragmentTransaction.commit();
}
});
}
}
and my ProductFragment1 class is:
public class ProductFragment1 extends SherlockFragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater
.inflate(R.layout.share_product_1, container, false);
return view;
}
}
and the layout my main class uses is:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/share_product_parent"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="right|center_vertical"
android:orientation="horizontal" >
</RelativeLayout>
and the layout my ProductFragment1 uses is:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/tv1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="25dp" />
<EditText
android:id="#+id/et1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#id/tv1"
android:textSize="25dp" />
<Button
android:id="#+id/done_product_1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#id/et1"
android:text="Done" />
</RelativeLayout>
The problem is:
I am getting a NullPointerException at this line in my main class:
Button done_button = (Button) fragment.getView().findViewById(R.id.done_product_1);
done_button.setOnClickListener ....
when i searched for what getView() on a fragment returns. I found out that it returns the view from onCreateView();
I checked it doesn't return null.
Thank You
You are on the wrong track here. You get the NPE because the Fragments views is not created yet. Fragments also have a lifecycle just like Activities.
What you should be doing is assigning the OnClickListener inside your Fragments onViewCreated() method. And from there... you should create a callback and notify your hosting Activity of the event.