Default fragment on Activity Launch - java

I'm trying to have a fragment loaded as the default view for the activity, but I just get a blank screen and huge memory leaks.
Activity file onCreate method:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
if (savedInstanceState == null) {
FragmentManager fragmentManager = getFragmentManager();
int fragmentTransaction = fragmentManager.beginTransaction()
.add(R.id.login_screen_fragment, new FragmentLogin())
.commit();
}
}
The XML for the activity:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LoginActivity">
<fragment
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/login_screen_fragment"
class="com.test.project.FragmentLogin"
/>
<fragment
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/forgotten_password_fragment"
class="com.test.project.FragmentForgottenPassword"
/>
</FrameLayout>
And the Fragment class (relevant parts):
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_login, container, false);
final Activity activity = getActivity();
... code ...
return view;
}
I followed instructions from a tutorial someone suggested earlier from a different question, but I must be doing something horribly wrong. Any ideas?

xml file
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/changeFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LoginActivity">
</FrameLayout>
your activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
if (savedInstanceState == null) {
FragmentLogin f1= new FragmentLogin();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.changeFragment, f1);
fragmentTransaction.commit();
}
}

I'm new to Android and I ran into the same problem. Here's how I fixed mine.
So in your onCreate method, use getSupportFragmentManager() from the FragmentManager class then declare FragmentTransaction separately. See below. I did this for my case and it worked.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
if (savedInstanceState == null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.login_screen_fragment, new FragmentLogin());
fragmentTransaction.commit();
}
Hope this helps solve your problem as well.
Sincerely,
sylvery

Just replace the fragment element with FrameLayout, then you can see your fragment.

If you wanted to add the Fragment programatically, then remove the <Fragment> in your Framelayout and add some ID unto it.
It should look like this:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/login_screen_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LoginActivity" />

Related

Can't call Fragment method in parent Activity

I simply want to call a method from a fragment in my MainActivity(parent).
But as soon as I try to call the method I get an NullPointerException.
Attempt to invoke virtual method 'void
com.example.fragmenttest.TestFragment.testMethod()' on a null object
reference
Here is what I do in the onCreate of the MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.containerView, new TestFragment()).commit();
TestFragment fragment = (TestFragment) fragmentManager.findFragmentById(R.id.testfragment);
fragment.testMethod();
}
and here is the fragment:
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView=inflater.inflate(R.layout.activity_fragment,container,false);
return rootView;
}
public void testMethod(){
Toast.makeText(getContext(), "Test", Toast.LENGTH_LONG).show();
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
tools:context=".MainActivity">
<FrameLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/containerView">
</FrameLayout>
</RelativeLayout>
and activity_fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<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"
tools:context="com.example.fragmenttest.MainActivity"
android:id="#+id/testfragment">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="50dp"
android:text="Fragment" />
</RelativeLayout>
Of course this is not my real project, I just created a new one to simplify my issue.
In my real project I want to call a method from my fragment as soon as the onRewardedVideoCompleted method gets called, which is in my MainActivity.
How do I call the method from my fragment without getting a null pointer exception and without using an interface? (Using an interface for this small problem seems unnecessary)
Thanks
commit() is asynchronous. This is why your project is crashing upon launch. Instead of using commit(), use commitNow(). Also, instead of using new TestFragment(), create a variable so you can call its methods.
TestFragment testFragment= new TestFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.containerView, testFragment).commitNow();
testFragment.testMethod();
Fragment transactions are asynchronous (unless you use executePendingTransactions()). Your transaction has likely not completed yet. You use runOnCommit on FragmentTransaction (in the support library) to execute code after it is done.
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
TestFragment yourFragment = newe TestFragment();
fragmentTransaction.replace(R.id.containerView, yourFragment).commit();
yourFragment.testMethod();
First of all, You must pass yourFragment to fragmentTransaction, then you can call any methods you want.

Replace Fragment with Button

I am trying to replace a fragment with a button. Basically I have this form (which is all the input views on helloFragment) and I want to click submit and show the form information on the next fragment (showFormFragment).
It renders the first fragment on my device, but the button won't replace it. It doesn't crash however.
activity_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:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/hello"
android:name="teaminfamous.com.fragments.helloFragment"
tools:layout="#layout/fragment_hello">
</FrameLayout>
</RelativeLayout>
My onCreate and Button listner:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentTransaction ft = fm.beginTransaction();
helloFragment hf = new helloFragment();
FormShow fs = new FormShow();
ft.replace(android.R.id.content, hf);
Button submitbtn = (Button) findViewById(R.id.submitButton);
submitbtn.setOnClickListener(submitForm);
}
EDIT:
In Fragment Class helloFragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_form_show, container, false);
Button submitbtn = (Button) view.findViewById(R.id.submitButton);
submitbtn.setOnClickListener(submitForm);
// Inflate the layout for this fragment
return view;
}
private View.OnClickListener submitForm = new View.OnClickListener() {
public void onClick(View v) {
//do handling here
final EditText nameField = (EditText) getView().findViewById(R.id.nameEdit);
final EditText originField = (EditText) getView().findViewById(R.id.originEdit);
String name = nameField.getText().toString();
String origin = nameField.getText().toString();
FragmentTransaction ft = fm.beginTransaction();
FormShow show = new FormShow();
ft.replace(R.id.hello, show, show.toString() ).addToBackStack(null).commit();
//final TextView nameText = (TextView) findViewById(R.id.nameShow);
// nameText.setText(name);
}
};
I hit submit and the onClickListner gets called and it shows a blank screen now
I'm pretty new to Android and a novice in Java, so an explanation for the usual pattern for doing something like this would also be helpful.
In order to replace fragment dynamically you have to add it at runtime. To do this you need a container that will host your fragment e.g. FrameLayout:
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Then you need an access the FragmentManager to begin transaction:
FragmentTransaction transaction = getFragmentManager().beginTransaction();
String tag = fragment.getClass().getSimpleName();
transaction.replace( R.id.fragment_container, new YourFragmentHere(), tag);
transaction.commit();
You should try to change your
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/hello"
android:name="teaminfamous.com.fragments.helloFragment"
tools:layout="#layout/fragment_hello">
</fragment>
to <FrameLayout>
Then, instead of this code:
ft.replace(android.R.id.content, hf);
use
ft.replace(R.id.hello, hf).commit();
and it should work

Click a button to open a Fragment?

I have a ViewPager in which I am able to view between 4 different tabs (which are fragments) I created. In one of my fragments, I want to have a button that will, after I click a button on that page, replace that view with another fragment. Now I don't want to swipe to another tab, I just merely want to replace the view of the current fragment when I press that button. Here is my attempt, but I'm not sure why when I click my button, nothing happens. If anyone could help me that would be great. Thanks!
This is the Fragment I call to create the view and the button I want to press.
ManualSelection.java
public class ManualSelection extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.activity_manual_selection, container, false);
intent = new Intent(getActivity(), ManualSelectionListView.class);
return rootView;
}
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Button listViewGenerated = (Button) getActivity().findViewById(R.id.manual_generate);
listViewGenerated.setOnClickListener(new View.OnClickListener() {
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
public void onClick(View v) {
FragmentManager fm = getActivity().getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.listView_manual, new ManualSelectionListView());
ft.commit();
}
});
}
}
And here is the Fragment I want to create
ManualSelectionListView.java
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class ManualSelectionListView extends Fragment {
static final String[] MOBILE_OS =
new String[] { "Android", "iOS", "WindowsMobile", "Blackberry"};
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.listview, container, false);
ListView lv = (ListView)rootView.findViewById(R.id.listview);
lv.setAdapter(new MobileArrayAdapter(getActivity(),MOBILE_OS));
return rootView;
}
}
And here are my XML files:
activity_manual_selection.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context="com.ecs160.homestay.ManualSelection"
android:id="#+id/fragmentTest">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Generate"
android:id="#+id/manual_generate"
android:layout_centerHorizontal="true"
android:onClick="generateListView"/>
And here is the XML file called listview.xml that contains R.id.listView_manual
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/listView_manual">
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/listview"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
I get nothing displayed when I hit "Generate." Any ideas? Thanks!
In your Activity you should create this:
public void generateListView(View v){
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.listView_manual, new ManualSelectionListView());
ft.commit();
}
The problem is that you are trying to get the Button id from your main activity which will return null
Button listViewGenerated = (Button) getActivity().findViewById(R.id.manual_generate);
Button manual_generate is located in your activity_manual_selection layout not in your Main activity's layout you cant get view from different layout or else it will return null
solution:
Get the Button's id from your fragment's layout
public class ManualSelection extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.activity_manual_selection, container, false);
intent = new Intent(getActivity(), ManualSelectionListView.class);
Button listViewGenerated = (Button) rootView.findViewById(R.id.manual_generate);
listViewGenerated.setOnClickListener(new View.OnClickListener() {
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
public void onClick(View v) {
FragmentManager fm = getActivity().getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.listView_manual, new ManualSelectionListView());
ft.commit();
}
});
return rootView;
}
remove onActivityCreated

Adding a New Fragment to a FrameLayout Yields IllegalStateException

I'm attempting to implement a Navigation Drawer within an app I'm trying to create. Currently, the content of each Activity is being displayed within a Fragment. Since I can't use a static <fragment /> within the layout, I opted to use a dummy <FrameLayout /> instead. Here is my layout:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawerLayout_messages"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Main content view -->
<FrameLayout
android:id="#+id/messages_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- Drawer view -->
<ListView
android:id="#+id/messages_drawer_list"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:background="#F0F0F0"/>
</android.support.v4.widget.DrawerLayout>
Now, when trying to replace the <FrameLayout /> with a fragment, I guess this error:
java.lang.IllegalStateException: The specified child already has a
parent. You must call removeView() on the child's parent first.
This is the code I'm executing in order to add in the fragment:
public class MessagesActivity extends Activity {
public static final String TAG = Constants.PACKAGE + ".MessagesActivity";
private DrawerLayout drawerLayout;
private ActionBarDrawerToggle drawerToggle;
private ListView drawerItems;
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "Starting activity: " + TAG);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messages);
drawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout_messages);
String[] drawerItemsList = getResources().getStringArray(R.array.drawer_items);
drawerItems = (ListView) findViewById(R.id.messages_drawer_list);
drawerItems.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, drawerItemsList));
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.drawable.ic_drawer, R.string.title_app, R.string.title_messages) {
public void onDrawerClosed(View view) {
getActionBar().setTitle(R.string.title_messages);
invalidateOptionsMenu();
}
public void onDrawerOpened(View view) {
getActionBar().setTitle(R.string.title_app);
invalidateOptionsMenu();
}
};
drawerLayout.setDrawerListener(drawerToggle);
if (savedInstanceState == null) {
Log.d(TAG, "Setting fragment");
setFragment(0);
}
Log.d(TAG, TAG + "'s layout is initialized. Now starting service connection");
}
public void setFragment(int position) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.messages_content, new MessagesFragment());
transaction.addToBackStack(null);
transaction.commit();
drawerItems.setItemChecked(position, true);
drawerLayout.closeDrawer(drawerItems);
}
}
That Activity file is basically pulled directly from Google's developer resources, yet I'm still getting an error message. Am I forgetting to do something?
EDIT: Added my MessagesFragment code for you all.
public class MessagesFragment extends Fragment {
public MessagesFragment() {}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_messages, container);
}
}
return inflater.inflate(R.layout.fragment_messages, null);
Could you please try and use null instead of container.

Android 1.6 & Fragment & Tabhost

I'm working on upgrading an Android application (1.6 compatibility) which uses a TabHost to show 3 different tabs with nested activities.
At the time I used the ActivityGroup trick to show nested activities in a tab but I'm very unhappy with this method since it's a real pain to handle some features.
I heard about the Fragments API compatibility package for 1.6 and a Fragment looks perfect for what I want to do (show nested views / features within a tab with transition effects and stuff) but I can't make it work with a TabHost (It was meant to work with an Action Bar but it's not available in the compatibility package).
Did any of you guys found a way to create such a structure in your applications?
My error here is :
ERROR/AndroidRuntime(955): Caused by: java.lang.RuntimeException: Unable
to start activity
ComponentInfo{com.XXX}:
java.lang.IllegalArgumentException: No
view found for id 0x1020011 for
fragment MyFragment
CODE
main.xml
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:layout_weight="1" />
<TabWidget
android:id="#android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0" />
</LinearLayout>
</TabHost>
MainActivity.java
public class MainActivity extends TabActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Resources res = getResources();
final TabHost tabs = getTabHost();
TabHost.TabSpec spec;
Intent i;
i = new Intent(this, MyActivity.class);
spec = tabs.newTabSpec("MyActivity").setIndicator("MyActivity",res.getDrawable(R.drawable.tab)).setContent(i);
tabs.addTab(spec);
}
}
MyActivity.class
public class MyActivity extends FragmentActivity {
private static String TAG = "MyActivity";
private static FragmentManager fragmentManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ListeResultatFragment fragment = MyFragment.newInstance();
fragmentTransaction.add(android.R.id.tabcontent, fragment, "MyFragment");
fragmentTransaction.commit();
}
}
MyFragment.java
public class MyFragment extends Fragment {
public static MyFragment newInstance() {
MyFragment instance = new MyFragment();
return instance;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment, container, false);
}
}
The problem is that your MyActivity tries to reach out to the enclosing MainActivity by using android.R.id.tabcontent as a container id. This is not possible. Instead, MyActivity needs to have its own layout (e.g. a FrameLayout) which can be used as the parent for the Fragment. In this layout, there must exist a view that can be referenced by id.
Let's say you have a layout called activity_layout.xml which contains a FrameLayout with the id 'framelayout'. You can then modify the onCreate method in MyActivity to something like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View parent = getLayoutInflater().inflate(R.layout.activity_layout, null);
setContentView(parent);
fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment fragment = MyFragment.newInstance();
fragmentTransaction.add(R.id.framelayout, fragment, "MyFragment");
fragmentTransaction.commit();
}
In other words, MyActivity needs to be able to work on its own. Try to make it work first, and then embed MyActivity in the MainActivity containing the TabHost.
Why don't you create your own tabbar. It's verry easy to build. Just add a LinearLayout with some buttons in it and set the onClickListener to switch fragments by using the FragmentManager. The Fragment manager can be obtained from a FragmentActivity.
FragmentManager fragmentManager = getSupportFragmentManager();
In the onClick handler you just do a transaction to the switch to the correct fragments.

Categories

Resources