getting nullPointerException when trying to call fragment method in my Activity? - android

I am trying to do something relatively basic by drawing a circle on a fragments layout when the app user presses down on the screen. essentially drawing a small circle on the area of the screen where a user presses. So i started with a basic project with a fragment in the main layout.I have a gestures class that extends simpleOnGestureListener. this returns the coordinates for my circle to the main activity. this works fine. but in my onTouchEvent method in the main activity when i call frag.drawCircle() i get a nullpointerexception and I am not too sure why this is. below is the code for my MainActivity. i think I am doind everything correctly including getting the fragment using the fragmentmanager and using its "tag" to retrieve the fragment? below is the code for my main class.
public class Circles extends Activity {
private GestureDetector detector;
private PlaceholderFragment frag;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_circles);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.activitylayout, new PlaceholderFragment(),"myfrag")
.commit();
}
detector = new GestureDetector(this, new Gestures());
FragmentManager manager = getFragmentManager();
frag = (PlaceholderFragment) manager.findFragmentByTag("myfrag");
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
boolean consumed = detector.onTouchEvent(event);
float x = Gestures.x;
float y = Gestures.y;
if(consumed)
{
Log.d("consumed? ", String.valueOf(consumed));
Log.d("x : ", String.valueOf(x));
Log.d("y : ", String.valueOf(y));
frag.drawCircle();
}
return super.onTouchEvent(event);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.circles, 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();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_circles, container, false);
return rootView;
}
public void drawCircle()
{
Log.d("stuff", "draw circle here!");
}
}
}
obviously the fragments isn't being instantiated properly. I am just not too sure why that is at present. any help is greatly appreciated.

Override onResume method and try moving this code in onResume
FragmentManager manager = getFragmentManager();
frag = (PlaceholderFragment) manager.findFragmentByTag("myfrag");

A better solution will be doing everything in onCreate(). Doing in onResume will just destroy the meaning of having onCreate and moreover just confuse the control flow if reference of that fragment is required before the execution of onResume.
Instread of putting everything in one statement, just break it and make it fit your need.
Here is the code
private PlaceholderFragment frag;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_circles);
if (savedInstanceState == null) {
frag = new PlaceHolderFragment();
getFragmentManager().beginTransaction()
.add(R.id.activitylayout, frag ,"myfrag")
.commit();
}else{
FragmentManager manager = getFragmentManager();
frag = (PlaceholderFragment) manager.findFragmentByTag("myfrag");
}
detector = new GestureDetector(this, new Gestures());
}
This way you wont have issue getting a null reference. Since if activity is recreated the Fragment will be in backstack so you can retrieve it by tag. But if activity is being created forthe first time then first get reference and then commit the transaction.

Related

Error. .commit() in Fragments in onCreate method

So, here's myActivity.java
Basically, I'm getting an error in onCreate method when I'm trying to use .commit()
So, just unsure of why is that. Could use some guidance. Thanks!
Also, a beginner with Fragments so, gets me a little puzzled from time to time.
It shows me that it "Cannot resolve method commit()".
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new ForecastFragment()
.commit();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.my, 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();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A Forecast fragment containing a simple view.
*/
public static class ForecastFragment extends Fragment {
private ArrayAdapter<String> mForecastAdapter;
public ForecastFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_my, container, false);
String[] forecastArray={
"Right Now - Hot. Grab a Lemonade!",
"Today - Boiling! Feels more like a Heat Furnace!",
"Tomorrow - Rains! Carry an Umbrella!",
"Tuesday - Hailstones!",
"Wednesday - Stormy",
"Thursday - Snowfall!",
"Friday - Rebecca Black",
"Saturday - Thunder!",
"Sunday - Just right." };
List<String>weekForecast=new ArrayList<String>(Arrays.asList(forecastArray));
mForecastAdapter = new ArrayAdapter<String>(
getActivity(),
R.layout.list_item_forecast,
R.id.list_item_forecast_textview,
weekForecast);
ListView listView=(ListView) rootView.findViewById(R.id.listview_forecast);
listView.setAdapter(mForecastAdapter);
return rootView;
}
}
}
This is wrong
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new ForecastFragment().
commit()); //<-----
}
commit() is a method on the FragmentTransaction, not on the Fragment. So change your code to this:
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new ForecastFragment())
.commit();
}
If you're getting confused with fragments confused you shouldn't be concatenating all these things, do em in seperate lines until you're fully comfortable:
getFragmentManager().beginTransaction()
.add(R.id.container, new ForecastFragment()
.commit();
becomes
ForecastFragment newFragment = new ForecastFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(R.id.container, newFragment );
transaction.addToBackStack(null);
transaction.commit();

Pressing back does not return to previous fragment

I have a problem with adding the fragment transactions to the back stack. I have a Main activity in which I populate my layout with a Menu Fragment:
public class MainActivity extends ActionBarActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getFragmentManager().beginTransaction().add(R.id.frag_container, new MainMenuFragment()).commit();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.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();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Then, inside the MainMenuFragment, the user chooses some option which results in replacing the menu fragment with some other fragment:
public class MainMenuFragment extends Fragment implements OnItemClickListener{
GridView grid;
FragmentManager manager;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.main_menu_fragment, container, false);
manager = getActivity().getFragmentManager();
grid = (GridView) root.findViewById(R.id.gridView1);
grid.setAdapter(new MenuTileAdapter(getActivity()));
grid.setOnItemClickListener(this);
return root;
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
FragmentTransaction trans = manager.beginTransaction();
if (position == 0){
trans.replace(R.id.frag_container, new BasicSettingsFragment());
trans.addToBackStack(null);
trans.commit();
}
}
}
For what i understand, this should make it so that when the user presses back button on their device, they will be brought back to the menu fragment, but instead this quits the app. What am i doing wrong?
In your Activity overwrite:
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
And probably you need to use in every commited fragment transaction:
FragmentTransaction.addToBackStack(null);
Your code is a mixup, you use ActionBarActivity from appcompat and not using getSupportFragmentManager() and the fragments import should be the appcompat one if you decide to use it. If not, use Activity instead of ActionBarActivity and the simple Fragment import with FragmentManager
Add this to your activity android:configChanges="keyboardHidden|orientation|screenSize"
This will stop your activity from restarting when you rotate.
use setRetainInstance(true) on fragments.
You are not adding the MainMenuFragment to the back stack. You can try this one on your activity:
getFragmentManager().beginTransaction().add(
R.id.frag_container, new MainMenuFragment()).
addToBackStack(null).commit();
When you add or replace a fragment with the FragmentManager, you need to manually add the old fragment to the backstack with addToBackStack() before calling commit().

How to send data from main activity to fragment

public class MyActivity extends Activity implements ButtonFragement.OnFragmentInteractionListener, TextFragment.OnFragmentInteractionListener,Communicator {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
ButtonFragement btnfrg=new ButtonFragement();
TextFragment txtfrg= new TextFragment();
FragmentManager fm=getFragmentManager();
FragmentTransaction ft=fm.beginTransaction();
ft.add(R.id.my_activity,btnfrg,"Fragment");
ft.add(R.id.my_activity,txtfrg,"Second Fragment");
ft.commit();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.my, 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();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onFragmentInteraction(Uri uri) {
}
#Override
public void respond(String data) {
FragmentManager fm=getFragmentManager();
TextFragment f1= (TextFragment) fm.findFragmentById(R.id.textfrg);
f1.changeText(data);
}
}
This is my main_Activity code, here i am trying to send a data over the fragment but it gives me error at f1.changeText(data).Basic structure of my project is , on main Activity , i created two fragment. One with button and another with text. I want to show how many times the button was clicked on second fragment using a communicator interface. Here in "data" counter shows a how many times button was clicked but i am not able to transfer it over second fragment.
Complete Code for the Program---
public interface Communicator {
public void respond(String data);
}
In TextFragment class i added this method----
public void changeText(String data)
{
txt.setText(data);
}
In ButtonFragment class i added and modified following method
public class ButtonFragement extends Fragment implements View.OnClickListener{
int counter=0;
private OnFragmentInteractionListener mListener;
Button btn;
Communicator comm;
#Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
comm= (Communicator) getActivity();
btn= (Button) getActivity().findViewById(R.id.button);
btn.setOnClickListener(this);
}
#Override
public void onClick(View view) {
counter++;
// comm.respond("The button was clicked "+counter+" times");
comm.respond("hi");
}
Here, i just added which i added in my program. My program get crash at...MainActiviy f1.changeText(data);
But why i am not getting it.Can anyone Help me fixed this bug?
Bundle bundle = new Bundle();
bundle.putString("key", value);
// set Fragmentclass Arguments
YourFragment ff= new YourFragment ();
ff.setArguments(bundle);
transaction.add(R.id.my_activity, ff);
Using Bundle
From Activity:
Bundle bundle = new Bundle();
bundle.putString("message", "Hello!");
FragmentClass fragInfo = new FragmentClass();
fragInfo.setArguments(bundle);
transaction.replace(R.id.fragment_single, fragInfo);
transaction.commit();
Fragment:
Reading the value in the fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
String myValue = this.getArguments().getString("message");
...
...
}
You have no fragment with id R.id.textfrg.
You are for some reason adding two fragments with id R.id.my_activity. One with tag "Fragment" and another with tag "Second Fragment".
So you are getting error.
Your idea is rigth.
This may be helpfull
TextFragment f1= (TextFragment) fm.findFragmentByTag("Second Fragment");
DO this way:
On Activity Side.
Fragment fragment = new GridTemplate();
Bundle bundle = new Bundle();
bundle.putInt("index",your value);
fragment.setArguments(bundle);
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).commit();
here R.id.frame_container is a frame Layout or Relative Layout In which you have to add the fragment.
On Fragment Side.
int index = getArguments().getInt("index");
hope this wil solve your problem. Thanks

Android, cardflip animation, fragments not displaying

I am having issues with the cardflip animation in Android. I am following their guide and also trying to pick a part the AnimationsDemo to try to understand this. But I have created all the card flip in and outs in XML and the card front and back layout in XML. I keep getting an error message when I try to add the fragment in onCreate. I'm not sure what is triggering the error as the code looks like the example code they use. I've included the error message and jave code below. Thanks for your time.
public class MainActivity extends ActionBarActivity {
/**
* Whether or not we're showing the back of the card (otherwise showing the front).
*/
private boolean mShowingBack = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getFragmentManager()
.beginTransaction()
.add(R.id.container, new CardFrontFragment())
.commit();
}else {
mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0);
}
/**
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
*/
}
private void flipCard() {
if (mShowingBack) {
getFragmentManager().popBackStack();
return;
}
// Flip to the back.
mShowingBack = true;
// Create and commit a new fragment transaction that adds the fragment for the back of
// the card, uses custom animations, and is part of the fragment manager's back stack.
getFragmentManager()
.beginTransaction()
// Replace the default fragment animations with animator resources representing
// rotations when switching to the back of the card, as well as animator
// resources representing rotations when flipping back to the front (e.g. when
// the system Back button is pressed).
.setCustomAnimations(
R.animator.card_flip_right_in, R.animator.card_flip_right_out,
R.animator.card_flip_left_in, R.animator.card_flip_left_out)
// Replace any fragments currently in the container view with a fragment
// representing the next page (indicated by the just-incremented currentPage
// variable).
.replace(R.id.container, new CardBackFragment())
// Add this transaction to the back stack, allowing users to press Back
// to get to the front of the card.
.addToBackStack(null)
// Commit the transaction.
.commit();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.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();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
return rootView;
}
}
/**
* A fragment representing the front of the card.
*/
public static class CardFrontFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.card_front, container, false);
}
}
/**
* A fragment representing the back of the card.
*/
public static class CardBackFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.card_back, container, false);
}
}
}
Error:
The method add(int, Fragment) in the type FragmentTransaction is not applicable for the arguments (int, MainActivity.CardFrontFragment) MainActivity.java /Lab6b/src/you/ca/mohawk/lab6b line 28 Java Problem
It seems issue should be with your Fragment import.
If you are using fragment support library then
import android.support.v4.app.Fragment;
and fragment manager instance should be get as
getSupportFragmentManager()
Else if your using the default Fragment then change the import as
import android.app.Fragment;

Can't keep fragments live through changing orientation or Saving fragment UI

I have an app that uses SherlockActionBar and switches between dynamic fragments through ActionItems in the Action Bar.
The problem is that i can't save the fragment states and their UI data.
This is the FragmentActivity:
public class MainActivity extends SherlockFragmentActivity {
private LocationFragment locationFragement;
private HomeFragment homeFragment;
private SettingsFragment settingsFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayShowTitleEnabled(false);
locationFragement = new LocationFragment();
homeFragment = new HomeFragment();
settingsFragment = new SettingsFragment();
}
#Override
public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) {
getSupportMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
FragmentManager fragManager = getSupportFragmentManager();
FragmentTransaction fragTransaction = fragManager.beginTransaction();
switch (item.getItemId()){
case R.id.home:
fragTransaction.replace(android.R.id.content, homeFragment);
break;
case R.id.location:
fragTransaction.replace(android.R.id.content, locationFragement);
break;
case R.id.settings:
fragTransaction.replace(android.R.id.content, settingsFragment);
break;
}
fragTransaction.commit();
return true;
}
Firstly, I tried to call to a single instance of the fragments, only to encounter NullPointerExceptions every time i did in the onOptionsItemSelected switch block
fragTransaction.replace(android.R.id.content, myFragmentClassName);
while the fragment instantiation was under
if(savedInstanceState == null){
locationFragement = new LocationFragment();
homeFragment = new HomeFragment();
settingsFragment = new SettingsFragment();
}
The fragments would not have created under orientation change obviously, and i couldn't figure anyway i could keep them instantiated. So i decided to create them anew every onCreate (which is bad but i wanted something to work) and save the UI data just to pass it back to the fragment.
This is one of the fragments, the other 2 are the same:
public class LocationFragment extends SherlockFragment {
private View myView;
private CheckBox myCheckBok;
#Override
public void onCreate(Bundle savedInstanceState) {
setRetainInstance(true);
Log.d("LocationFragment", "onCreate running");
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d("LocationFragment", "onCreateView running");
myView = inflater.inflate(R.layout.map_fragment, container, false);
myCheckBok = (CheckBox) myView.findViewById(R.id.mapFragmentCheckBox);
if(savedInstanceState != null){
myCheckBok.setChecked(savedInstanceState.getBoolean("isChecked"));
}
return myView;
}
#Override
public void onResume()
{
Log.d("LocationFragment", "onResume running");
super.onResume();
}
#Override
public void onPause() {
Log.d("LocationFragment", "onPause running");
super.onPause();
}
#Override
public void onSaveInstanceState(Bundle outState) {
boolean isChecked = myCheckBok.isChecked();
outState.putBoolean("isChecked", isChecked);
Log.d("LocationFragment", "onSaved Instant running");
super.onSaveInstanceState(outState);
}
I'm saving the checkbox's state, when i pass through the icons the checkbox state is saved and also through orientation change. BUT, when i change orientation, press another icon (or press the same one) and return to my fragment, the state isn't saved. I realized this is caused due to onSavedInstanceState not running when i change to another fragment (thus not saving or passing the checkBox data).
I haven't found answers anywhere on how to save correctly UI data from fragments (just through savedInstanceState doesn't cut it for my purposes) or how to manage several fragment instantiations while changing them. I know that each time i change a fragment, all it's data
is saved automatically by the system, but can't seem to get it to work.
Please help.
It's not part of the problem but you should be aware that the use of onSaveInstanceState is not needed for saving a View state. Android does that for you already as long as there's an ID to the View.
Seems like the problem you are facing is that you are not restoring the fragments from their FragmentManager. The fragments are there, but you simply didn't go to the FragmentManager and brought them once the onCreate has happened again.
This code should go in the onCreate:
// Try and fetch the fragments from the manager
locationFragement = fragmentManager.findFragmentByTag(LOCATION_FRAGMENT_TAG);
homeFragment = fragmentManager.findFragmentByTag(HOME_FRAGMENT_TAG);
settingsFragment = fragmentManager.findFragmentByTag(SETTINGS_FRAGMENT_TAG);
// If the fragment weren't found - meaning it's the first time the activity was
// started, create them
if (locationFragement == null) locationFragement = new LocationFragment();
if (homeFragment == null) homeFragment = new HomeFragment();
if (settingsFragment == null) settingsFragment = new SettingsFragment();
And, whenever you are adding/removing/replacing a fragment, make sure to add him with the TAG, i.e.
// EXAMPLE HOW TO USE A REPLACE WITH A TAG
getSupportFragmentManager().beginTransaction().replace(android.R.id.content,
locationFragement, LOCATION_FRAGMENT_TAG);
Does that work?

Categories

Resources