I've been trying to change my textViews text in a fragmentActivity based on whether or not user has clicked the button in the first main activity. I have 2 xml files and 2 .java files and the code at the moment crashes when the app starts.
This is the button code
public void getNum(View view) {
buttonCheck = 1;
}
And this is the code from FragmentTab
public class FragmentTab extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_layout, container, false);
TextView tv = (TextView) v.findViewById(R.id.text);
tv.setText("nothing has been input yet");
if (FirstActivity.buttonCheck == 1){
tv = (TextView) v.findViewById(R.id.text);
tv.setText("value");}
FirstActivity.buttonCheck = 0;
return v;
}
The first error i get from my code from logcat is: "java.lang.NullPointerException
at com.ezentertainment.dietabialkowa.FragmentTab.onCreateView(FragmentTab.java:23)" and line 23 is tv.setText("nothing has been input yet");
any help at all is greatly appreciated, I have been fighting with this issue for quite some time now..
tl;dr how to change fragment value based upon input from mainActivity?
edit: here is the fragment_layout.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#eaecee">
<TextView
android:id="#+id/textResult"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="value"
android:textAppearance="?android:attr/textAppearanceMedium" />
Your textview id is
android:id="#+id/textResult"
So, that's why you're getting a null pointer exception.
Also, it's probably a good idea to do a null check when finding a view by ID, just in case something isn't instantiated yet, so it doesn't kill your app. Something like:
TextView tv = (TextView) v.findViewById(R.id.textResult);
if (tv != null){
tv.setText("nothing has been input yet");
} else {
// log something if you want.
}
How about using setArguement:
In Activity:
Bundle bundle = new Bundle();
bundle.putString("email", email);
FragmentA fragment = new FragmentA();
fragment.setArguments(bundle);
getSupportFragmentManager().beginTransaction().add(container, fragment, tag).addToBackStack(tag).commit(); //please input container and tag yourself
In FragmentA:
String email;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle arguments = getArguments();
if (arguments != null)
email = bundle.getString("email");
...
}
Related
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.
EDIT 4 Alright, so I've changed my example code to exactly what was suggested, with a null check.
now in the public class MainActivity extends AppCompatActivity I've got
private templateFragment1 fragTest;
and then in onCreate I've got
final FragmentManager fragMan = getFragmentManager();
fragTest = (templateFragment1) fragMan.findFragmentByTag("1");
onSave.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
if(fragTest != null) {
String editTestText = fragTest.editTextGetter();
Toast.makeText(getApplicationContext(), editTestText, Toast.LENGTH_SHORT).show();
}
}
});
And in templateFragment1 I've got
privateEditText text;
which I've binded in onCreateView like this
text = (EditText) getActivity().findViewById(R.id.editTextTest);
then I have the method underneath onCreateView
public String editTextGetter(){
String value1 = text.getText().toString();
return value1;
}
And now what happens..is nothing. I hit the save button and there's no Toast, no error message. So I guess this means it's returning null?
EDIT 3 Here's a couple videos demonstrating the bug.
https://www.youtube.com/watch?v=w60Vljd2R4M&feature=youtu.be
https://www.youtube.com/watch?v=xqpVGBAHw0w&feature=youtu.be
I understand that there are several questions similar to this already, but none seem to address my specific issue here.
Inside my main activity I have a button that adds instances of fragments. Each time it does it also assigns them a tag of "1", "2", etc. Just to see if it's possible, I'm only trying to call a method from the first one.
In my main activity I have:
// initializing button that will call the fragment's method
Button onSave = (Button) findViewById(R.id.saveButton);
FragmentManager fragMan = getFragmentManager();
// calling my first created fragment
final templateFragment1 fragTest = (templateFragment1) fragMan.findFragmentByTag("1");
// my button that should call the frag's method and then display it as a toast
onSave.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
// here I'm assigning the fragment's method to a string
String editTestText = fragTest.editTextGetter();
// display as toast
Toast.makeText(getApplicationContext(), editTestText, Toast.LENGTH_SHORT).show();
}
});
In my fragment:
public String editTextGetter(){
EditText text = (EditText) getActivity().findViewById(R.id.editTextTest);
String value1 = text.getText().toString();
return value1;
}
editTextGetter() is below the onCreateView method if that matters.
Now what happens is just an app crash upon clicking the main activity's button.
EDIT: Here's my commit code as requested:
addDay.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
++fragIdCount;
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
String fragString = Integer.toString(fragIdCount);
templateFragment1 frag2 = new templateFragment1();
fragmentTransaction.add(R.id.templateFragmentLayout, frag2, fragString);
fragmentTransaction.commit();
}
});
As you can see, I'm incrementing a number from 0 (fragIdCount) and then converting it to a string. I then assign that as the tag of the fragment. So I'm trying to call my fragments with this assigned tag.
EDIT 2: OK guys, here's code that can copy+pasted into a new project. It replicates my issues, and I'd really appreciate if yall could take a look at it!
MainActivity.java
public class MainActivity extends AppCompatActivity {
int fragIdCount = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button addDay = (Button) findViewById(R.id.addDay);
Button removeDay = (Button) findViewById(R.id.removeDay);
// Here I'm making it so I have an instance of the fragment displayed on create
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
String fragString = Integer.toString(fragIdCount);
templateFragment1 frag2 = new templateFragment1();
fragmentTransaction.add(R.id.templateFragmentLayout, frag2, fragString);
fragmentTransaction.commit();
// My button that adds fragment. Obviously this can quickly generate a bunch of fragment instances
// I try to make that manageable by incrementing a fragment count to use as tags
addDay.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
++fragIdCount;
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
String fragString = Integer.toString(fragIdCount);
templateFragment1 frag2 = new templateFragment1();
fragmentTransaction.add(R.id.templateFragmentLayout, frag2, fragString);
fragmentTransaction.commit();
fragmentManager.executePendingTransactions();
}
});
// remove button. same concept as the add button
removeDay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
String fragString = Integer.toString(fragIdCount);
//Fragment f = getFragmentManager().findFragmentByTag(fragString);
if(fragIdCount != 0){
fragmentTransaction.remove(fragmentManager.findFragmentByTag(fragString)).commit();
--fragIdCount;
}
}
});
// initialize Save button (which SHOULD get the value of an editText from whichever
// fragment I specify)
Button onSave = (Button) findViewById(R.id.saveButton);
onSave.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
// Eventually I'll want to make this a for loop to perform this operation on all fragments created.
FragmentManager fragMan = getFragmentManager();
// this should get the fragment "1"
templateFragment1 fragTest = (templateFragment1) fragMan.findFragmentByTag("1");
// and this should run the method "editTextGetter()" inside of the previously specified fragment
String editTestText = fragTest.editTextGetter();
// just a quick way to show if I got the correct value, for debugging
Toast.makeText(getApplicationContext(), editTestText, Toast.LENGTH_SHORT).show();
}
});
}
}
activity_main.xml
<ScrollView
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"
>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.liftrpoc.scheduler1.pushpulldetails"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/templateFragmentLayout"
android:orientation="vertical">
</LinearLayout>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/addDay"
android:text="Add Day"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/removeDay"
android:text="Remove Day"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/saveButton"
android:text="Save"
/>
</LinearLayout>
</ScrollView>
templateFragment1.java
public class templateFragment1 extends Fragment {
public templateFragment1() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
LinearLayout view = (LinearLayout) inflater.inflate(R.layout.fragment_template_fragment1, container, false);
// a good bit of extra code that adds it's own instanced fragments, just like in the main activity.
// this shouldn't have anything to do with what we're trying to do though. It doesn't touch anything else.
return view;
}
// here's the editText method I'm trying to access from my main activity.
public String editTextGetter(){
EditText text = (EditText) getActivity().findViewById(R.id.editTextTest);
String value1 = text.getText().toString();
return value1;
}
}
fragment_template_fragment1.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="wrap_content"
android:background="#E3E3E3"
android:orientation="vertical"
android:id="#+id/ParentLinearLayout1"
>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/editTextTest"
/>
</LinearLay
Use an ArrayList and store each fragment you make in it.
then when you want to call an specific function in your fragment or get a view just get your desired fragment from the ArrayList and after that do your job.
Some areas of improvement to your code:
In your main activity, it's easier to just make fragTest a class property.
private templateFragment1 fragTest;
/** I believe these exists in your onCreate()? **/
// initializing button that will call the fragment's method
Button onSave = (Button) findViewById(R.id.saveButton);
FragmentManager fragMan = getFragmentManager();
// calling my first created fragment
fragTest = (templateFragment1) fragMan.findFragmentByTag("1");
if(fragTest == null) {
// Create fragTest
}
// my button that should call the frag's method and then display it as a toast
onSave.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
// Wrapping this with a null pointer check may be unnecessary
// but callbacks can be ... funny.
if(fragTest != null {
// here I'm assigning the fragment's method to a string
String editTestText = fragTest.editTextGetter();
// display as toast
Toast.makeText(getApplicationContext(), editTestText, Toast.LENGTH_SHORT).show();
}
}
});
/** End of onCreate **/
In your fragment, again, make text a class property and bind to it's view in onCreateView.
private EditText text;
// TODO In onCreateView, bind text to R.id.editTextTest
public String editTextGetter(){
String value1 = text.getText().toString();
return value1;
}
Other considerations
Orientation changes: you may want to add setRetainInstance(true) to the onCreate of you fragments. Full details here.
I tried to send a int value from current activity to the new one, here is the parts in current activity.
dialog.setPositiveButton("4 players", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "Start a new game!", Toast.LENGTH_SHORT).show();
// need send extra value to PlayerBoardActivity to decide how many buttons I should have
Intent intent = new Intent(MainActivity.this,
PlayBoardActivity.class);
intent.putExtra(PLAYER_NO, 4);
startActivity(intent);
}
});
dialog.setNegativeButton("2 players", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "Start a new game!", Toast.LENGTH_SHORT).show();
// need send extra value to PlayerBoardActivity to decide how many buttons I should have
Intent intent = new Intent(MainActivity.this,
PlayBoardActivity.class);
intent.putExtra(PLAYER_NO, 2);
startActivity(intent);
}
});
The problem is, I create 2 layout files for the new activity. When I press the negative button in the dialog for example, what I want is let the new activity (PlayerBoardActivity in my case) load the layout file corresponding to the value I have sent by "intent.putExtra(PLAYER_NO, 2); "
The code in the new activity is
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final String PLAYER_NO = "the number of players";
Bundle b = getIntent().getExtras();
int a = b.getInt(PLAYER_NO);
if (b != null) {
if (a == 2) {
setContentView(R.layout.two_player);
}
if(a == 4){
setContentView(R.layout.four_player);
}
}
}
I do want to know whether I can load different layout file in this way? Or is there any better solution for my problem.
Thank you all in advance.
If you use
intent.putExtra(PLAYER_NO, 2);
you should call following code to get values (without using "Bundle"):
getIntent().getIntExtra(PLAYER_NO, -1)
In your code, the problem is in your second activity to which you are calling.
You are trying to fetching the values from intent in incorrect way.
Try this in your second activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
int b = intent.getIntExtra(PLAYER_NO, 0);
if (b == 2) {
setContentView(R.layout.two_player);
}
if(b == 4){
setContentView(R.layout.four_player);
}
}
Ji Yang... it is fine..if both the layout content the same kind of structure and dealing with different resources of any layout in the same activity is not so difficult..
suppose layout two_player.xml is
<?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="wrap_content"
android:paddingTop="6dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:orientation="vertical">
<TextView
android:id="#+id/textview1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#777370"
android:textSize="16sp"
android:paddingLeft="5dp"
android:text="Dummy Text"
android:visibility="gone"
android:textStyle="bold"/>
</RelativeLayout>
and layout four_player.xml is something like that
<?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="wrap_content"
android:paddingTop="6dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:orientation="vertical">
<ImageView
android:id="#+id/iv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/order_content"
android:src="#drawable/order_next_sap"
android:layout_alignLeft="#+id/order_content"/>
<ImageView
android:id="#+id/iv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/order_content"
android:src="#drawable/order_next_sap"
android:layout_alignLeft="#+id/order_content"/>
</RelativeLayout>
means ...both layout of different defination.. than its difficult to use resource of both layout in same activity and its not good too..
The better solution in this case is to create fragment of both layout
class TwoPlayerFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v=inflater.inflate(R.layout.two_player, container, false);
return v;
}
}
class FourPlayerFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v=inflater.inflate(R.layout.four_player, container, false);
return v;
}
}
and use the fragment according to the intent value pass from dialog..
try this,
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final String PLAYER_NO = "the number of players";
Intent b = getIntent();
int a = b.getExtras().getInt(PLAYER_NO);
if (b != null) {
if (a == 2) {
setContentView(R.layout.two_player);
}
if(a == 4){
setContentView(R.layout.four_player);
}
}
}
You are doing very wrong way. You should use fragment for this. You should create two fragment in which you can inflate different different layout. But this is your call.
From PlayBoardActivity you are sending data like :
intent.putExtra(PLAYER_NO, 4);
So in new activity you need to retreive like:
int b=getIntent.getIntExtra(PLAYER_NO,defaulValue);
you are trying to get value from bundle which is wrong.
This is a canonical question for a problem frequently posted on StackOverflow.
I'm following a tutorial. I've created a new activity using a wizard. I get NullPointerException when attempting to call a method on Views obtained with findViewById() in my activity onCreate().
Activity onCreate():
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View something = findViewById(R.id.something);
something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}
Layout XML (fragment_main.xml):
<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="packagename.MainActivity$PlaceholderFragment" >
<View
android:layout_width="100dp"
android:layout_height="100dp"
android:id="#+id/something" />
</RelativeLayout>
The tutorial is probably outdated, attempting to create an activity-based UI instead of the fragment-based UI preferred by wizard-generated code.
The view is in the fragment layout (fragment_main.xml) and not in the activity layout (activity_main.xml). onCreate() is too early in the lifecycle to find it in the activity view hierarchy, and a null is returned. Invoking a method on null causes the NPE.
The preferred solution is to move the code to the fragment onCreateView(), calling findViewById() on the inflated fragment layout rootView:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
View something = rootView.findViewById(R.id.something); // not activity findViewById()
something.setOnClickListener(new View.OnClickListener() { ... });
return rootView;
}
As a side note, the fragment layout will eventually be a part of the activity view hierarchy and discoverable with activity findViewById() but only after the fragment transaction has been run. Pending fragment transactions get executed in super.onStart() after onCreate().
Try OnStart() method and just use
View view = getView().findViewById(R.id.something);
or Declare any View using getView().findViewById method in onStart()
Declare click listener on view by anyView.setOnClickListener(this);
Try to shift your accessing views to the onViewCreated method of fragment because sometimes when you try to access the views in onCreate method they are not rendered at the time resulting null pointer exception.
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
View something = findViewById(R.id.something);
something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}
Agreed, this is a typical error because people often don't really understand how Fragments work when they begin working on Android development. To alleviate confusion, I created a simple example code that I originally posted on Application is stopped in android emulator , but I posted it here as well.
An example is the following:
public class ContainerActivity extends FragmentActivity implements ExampleFragment.Callback
{
#Override
public void onCreate(Bundle saveInstanceState)
{
super.onCreate(saveInstanceState);
this.setContentView(R.layout.activity_container);
if (saveInstanceState == null)
{
getSupportFragmentManager().beginTransaction()
.add(R.id.activity_container_container, new ExampleFragment())
.addToBackStack(null)
.commit();
}
getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener()
{
public void onBackStackChanged()
{
int backCount = getSupportFragmentManager().getBackStackEntryCount();
if (backCount == 0)
{
finish();
}
}
});
}
#Override
public void exampleFragmentCallback()
{
Toast.makeText(this, "Hello!", Toast.LENGTH_LONG).show();
}
}
activity_container.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"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/activity_container_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
ExampleFragment:
public class ExampleFragment extends Fragment implements View.OnClickListener
{
public static interface Callback
{
void exampleFragmentCallback();
}
private Button btnOne;
private Button btnTwo;
private Button btnThree;
private Callback callback;
#Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
try
{
this.callback = (Callback) activity;
}
catch (ClassCastException e)
{
Log.e(this.getClass().getSimpleName(), "Activity must implement Callback interface.", e);
throw e;
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_example, container, false);
btnOne = (Button) rootView.findViewById(R.id.example_button_one);
btnTwo = (Button) rootView.findViewById(R.id.example_button_two);
btnThree = (Button) rootView.findViewById(R.id.example_button_three);
btnOne.setOnClickListener(this);
btnTwo.setOnClickListener(this);
btnThree.setOnClickListener(this);
return rootView;
}
#Override
public void onClick(View v)
{
if (btnOne == v)
{
Toast.makeText(getActivity(), "One.", Toast.LENGTH_LONG).show();
}
else if (btnTwo == v)
{
Toast.makeText(getActivity(), "Two.", Toast.LENGTH_LONG).show();
}
else if (btnThree == v)
{
callback.exampleFragmentCallback();
}
}
}
fragment_example.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" >
<Button
android:id="#+id/example_button_one"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="30dp"
android:text="#string/hello"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"/>
<Button
android:id="#+id/example_button_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/example_button_one"
android:layout_alignRight="#+id/example_button_one"
android:layout_below="#+id/example_button_one"
android:layout_marginTop="30dp"
android:text="#string/hello" />
<Button
android:id="#+id/example_button_three"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/example_button_two"
android:layout_alignRight="#+id/example_button_two"
android:layout_below="#+id/example_button_two"
android:layout_marginTop="30dp"
android:text="#string/hello" />
</RelativeLayout>
And that should be a valid example, it shows how you can use an Activity to display a Fragment, and handle events in that Fragment. And also how to communicate with the containing Activity.
The view "something" is in fragment and not in activity, so instead of accessing it in activity you must access it in the fragment class like
In PlaceholderFragment.class
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_main, container,
false);
View something = root .findViewById(R.id.something);
something.setOnClickListener(new View.OnClickListener() { ... });
return root;
}
You are trying to access UI elements in the onCreate() but , it is too early to access them , since in fragment views can be created in onCreateView() method.
And onActivityCreated() method is reliable to handle any actions on them, since activity is fully loaded in this state.
Add the following in your activity_main.xml
<fragment
android:id="#+id/myFragment"
android:name="packagename.MainActivity$PlaceholderFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</fragment>
Since you have declared your View in the fragment_main.xml,move that piece of code where you get the NPE in the onCreateView() method of the fragment.
This should solve the issue.
in the posted code above in the question there is a problem :
you are using R.layout.activity_main in oncreate method, but the xml files name is "fragment_main.xml" , means you are trying to get the view of fragment_main.xml file which is not being shown so it gives null pointer exception. change the code like :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);// your xml layout ,where the views are
View something = findViewById(R.id.something);
something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}
You have to remember important thing is :
NullPointerException occurs when you have declared your variable and trying to retreive its value before assigning value to it.
Use onViewCreated() Method whenever using or calling views from fragments.
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
View v = view.findViewById(R.id.whatever)
}
I've got the same NullPointerException initializing a listener after calling findViewById() onCreate() and onCreateView() methods.
But when I've used the onActivityCreated(Bundle savedInstanceState) {...} it works. So, I could access the GroupView and set my listener.
I hope it be helpful.
Most popular library for finding views which is used by almost every developer.
ButterKnife
As I can their are enough answers explaining finding views with proper methodology. But if you are android developer and code frequently on daily basis then you can use butter-knife which saves a lot time in finding views and you don't have write code for it, With in 2-3 steps you can find views in milliseconds.
Add dependency in app level gradle:
implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
Add plugin for butter knife:
File -> Settings -> plugins->
Then search for Android ButterKnife Zelezny and install plugin and restart your studio and you are done with it.
Now just go to Oncreate method of your activity and right click on your layout_name and tap on generate button and select butterknife injection option and your views references will be automatically created like mention below:
#BindView(R.id.rv_featured_artist)
ViewPager rvFeaturedArtist;
#BindView(R.id.indicator)
PageIndicator indicator;
#BindView(R.id.rv_artist)
RecyclerView rvArtist;
#BindView(R.id.nsv)
NestedScrollingView nsv;
#BindView(R.id.btn_filter)
Button btnFilter;
I'm trying to implement marquee textview in a fragment at the runtime.
Problem #1: I get a null pointer exception at tv.setSelected(true); on the first fragment.
Everything works ok until I put the marquee code for the text view.
Problem #2: How can I move to a new fragment instead of a new intent in the list view for public void onItemClick ?
This is my code:
public static class FragmentOne extends Fragment {
ArrayList< String > ar;
ArrayAdapter< String > ad ;
ListView lv ;
TextView tv;
public FragmentOne() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
View rootView = inflater.inflate(R.layout.one, container, false);
tv = (TextView) rootView.findViewById(R.id.textView1);
tv.setSelected(true);
ar = new ArrayList<String>();
lv = (ListView) rootView.findViewById(R.id.listView1);
for (int i = 0 ; i< 10 ; i++){
ar.add("My Item " + String.valueOf(i));
}
ad = new ArrayAdapter<String>
(getActivity().getApplicationContext(), android.R.layout.simple_dropdown_item_1line,
ar);
lv.setAdapter(ad);
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast t = Toast.makeText(getActivity(), "Message",
Toast.LENGTH_SHORT);
t.show();
Intent i = new Intent(getActivity(), tst.class);
startActivity(i);
}
});
return rootView;
}
}
this is the xml code :
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="#+id/mywidget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="94dp"
android:layout_marginTop="145dp"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:lines="2"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:text="صور أندلسية ..... صفحة الأندلس ....معارك أندلسية ..... الأندلس في سطور
..... الأندلس : "
android:textColor="#ff4500"
android:focusable="false" />
</RelativeLayout>
Null pointer Exceptions usually happens when you didn't initialized
the object Or initialized to null.
Answering your 1st issue here - I strongly suggest posting 2 separate questions.
If the NPE is thrown at:
tv.setSelected(true);
(would need a LogCat to make sure)
... then your TextView is null.
In turn, this means that rootView.findViewById(R.id.textView1); did not return a valid TextView, likely because no child with such id (or of that type) was found in your R.layout.one xml.
Make sure your R.layout.one xml contains a TextView node with id textView1.
Edit
If the layout you posted correponds to R.layout.one, it's pretty trivial: the TextView 's id there is mywidget.
You'll need to change that.
Also make sure that layout is not used somewhere else, otherwise changing the id in the layout might pose problems.
You may want to change the id reference in your Fragment instead.
It happens because you don't have any TextView with the id textView1 in your XML.
EDIT
You will also have problem with the ListView, once you need a ListView in your XML with the id listView1