I implemented a bottom Navigation that should be filled with three different Fragment classes.
My Problem is that if i start the activity the first Fragment layout is not shown, only if i go to tab2 and return to tab1.
I think it is a Problem with the LifeCycle but i have no idea how i can fix it.
my bottom Navigation class that handle the Navigation:
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
fragment = new RequestFragment();
break;
case R.id.navigation_dashboard:
fragment = new ResponseFragment();
break;
case R.id.navigation_notifications:
fragment = new LogfileFragment();
break;
}
final FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.main_container, fragment).commit();
return true;
And my Fragment class:
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_request, container, false);
you should add the first fragment when activity start. you just set first fragment on onNavigationItemSelected() method and it never called even you click on navigation View. you should add these lines in onCreate() method:
fragment = new RequestFragment();
final FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.main_container, fragment).commit();
You have to initialize the fragment inside onCreate() method.
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_activity);
...
fragment = new RequestFragment();
final FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.main_container, fragment).commit();
}
This will display the fragment in the container inside the view when your activity starts. Keep your onNavigationItemSelected method as it is.
Related
I have 3 fragments, Home, Menu and orders they can be loaded by bottomnavigtioview items and the title shown by it as well
once navigate from Home to Orders then if you want to go back to Home From Orders the title still "Orders"
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment;
switch (item.getItemId()) {
case R.id.navigation_home:
toolbar.setTitle(getResources().getString(R.string.title_home));
fragment = new HomeFragment();
loadFragment(fragment);
return true;
case R.id.navigation_menu:
toolbar.setTitle(getResources().getString(R.string.fragment_title_menu));
fragment = new ProductFragment();
loadFragment(fragment);
return true;
case R.id.navigation_orders:
toolbar.setTitle(getResources().getString(R.string.title_orders));
fragment = new OrdersFragment();
loadFragment(fragment);
return true;
}
return false;
}
};
private void loadFragment(Fragment fragment) {
// load fragment
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
navigation = findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
// attaching bottom sheet behaviour - hide / show on scroll
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) navigation.getLayoutParams();
layoutParams.setBehavior(new BottomNavigationBehavior());
toolbar.setTitle(getResources().getString(R.string.title_home));
Fragment f = HomeFragment.newInstance();
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_container, f)
.commit();
}`
I have Also Tried this but its not working
`
fragmentmanger.addOnBackStackChangedListener -> public void onBackStackChanged() {
}`
Instead of calling toolbar.setTitle in your onNavigationItemSelected method, move it to onCreateView of each fragment. When you navigate back to a Fragment, onCreateView is executed again.
It worked for me when calling it in onResume like this in each fragment:
if(getActivity()!=null) {
((MainActivity)getActivity()).setActionBarTitle
(context.getResources().getString(R.string.YOUR_TITLE));
this is the function setActionBarTitle in MainActivity
public void setActionBarTitle(String title) {
toolbar.setTitle(title);
}
I need some help as I am a bit new in android, in my android app that I am working on, I am navigating between Fragments all the time. I use the code to navigate between Fragments.
private void displaySelectedScreen(int id){
Fragment fragment=null;
String fragment_tag="";
switch(id)
{
case R.id.nav_listen:
fragment=new ListenFragment();
fragment_tag="LISTENTAG";
break;
case R.id.nav_programs:
break;
case R.id.nav_stories:
break;
case R.id.nav_about:
break;
case R.id.nav_feedback:
break;
case R.id.nav_share:
shareTextUrl();
break;
}
if(fragment!=null){
FragmentTransaction ft=getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame,fragment,fragment_tag);
ft.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
}
I just need to check that if the fragment exists(loaded) before, containter should show the previously loaded fragment. However, if the Fragment was not loaded before the Fragment should be loaded for the first time.
Could anyone help me about making this happen?
Thank you very much.
Code inside my fragment:(ListenFragment.java)
public class ListenFragment extends Fragment
{
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
getActivity().setTitle("Listen Live");
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
final View InputFragmentView=inflater.inflate(R.layout.listen_layout,container,false);
return InputFragmentView;
}
You don't need to declare the variables reference to Fragment's instance. Instead, save your fragment by tag then get it. Like that:
Fragment fragment = getSupportFragmentManager().findFragmentByTag("fragment_tag");
if(fragment == null) {
fragment=new ListenFragment();
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment, fragment_tag);
ft.commit();
use below methods to get the Fragment:
getFragmentManager().findFragmentById(R.is.xyz)
getFragmentManager().findFragmentByTAG("XYZ")
then use to start Fragment :
supportFragmentManager.beginTransaction()
there is a similar question here it might help:
Check if a fragment exists and reuse it
I have a Fragment Class
and I have a linear layout clickable
and a button clickable.
So I want to know that when I click linear layout it should start fragment 1
and when I click button it should start fragment 2
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
LinearLayout l = (LinearLayout) rootView.findViewById(R.id.line1);
l.setOnClickListener(this);
Button b = (Button) rootView.findViewById(R.id.map_button);
b.setOnClickListener(this);
return rootView;
}
#Override
public void onClick(View v) {
Fragment frag = new Fragment1();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.frame_container, frag);
ft.addToBackStack(null);
ft.commit();
Fragment frag = new Fragment2();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.frame_container, frag);
ft.addToBackStack(null);
ft.commit();
Add a onClickListener on your button and try that to show your fragment when it is clicked.
#Override
public void onClick(View v) {
Fragment fragment = new Fragment1();
FragmentTransaction fragmentTr = getFragmentManager().beginTransaction();
fragmentTr .setCustomAnimations(android.R.animator.fade_in,
android.R.animator.fade_out);
if (fragment.isHidden())
fragmentTr.show(fragment);
}
Edit:
You can get which view is clicked with a switch case statement:
#Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.Button:
// show fragment x
case R.id.LinearLayout:
// show fragment y
}
}
your onClick method has to know what was clicked when you say setOnClickListener(this) you refer to the onClick method of the class .in your code it doesn't matter what the user clicks the whole onClick method will be executed . in order to specify the right block of code to be executed you can use Switch and case.
This question already has answers here:
Android application restarts on orientation change
(6 answers)
Closed 2 years ago.
My app contains fragments, and it's mainly a fragment application. I have only 3 activities, others are all fragments. But from any point of the app when I rotate the phone in landscape mode or portrait the application restarts and continues from the Start Point of the app, from the beginning.
I put the android:configChanges="orientation|keyboardHidden|keyboard" in the Manifest, but it seems it has no effect at all. I'm populating the fragments only with one web view. But I also change the actionbar color. That's all I do in the app. It's a static app, there is no user input. Here's a sample code of how my fragments look like:
public class CLASSNAME extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setRetainInstance(true);
}
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.LAYOUT, container, false);
ActionBar bar = getActivity().getActionBar();
bar.setBackgroundDrawable(new ColorDrawable(getResources().getColor(R.color.COLOR)));
bar.setTitle("TITLE");
final WebView wFirst = (WebView) view.findViewById(R.id.WEBVIEWID);
wFirst.getSettings().setJavaScriptEnabled(true);
wFirst.setBackgroundColor(0x00000000);
wFirst.loadDataWithBaseURL(LOADING DATA);
wFirst.setWebViewClient(new WebViewClient() {SETTING UP WEBVIEW CLIENT});
return view;
}
}
I read lots of posts that got answered with Save Instance State and those other methods, but in my case I have no idea what to save and how to keep my activity rolling even if the orientation is changed.
This is the MainActivity.class code:
public class MainActivity extends Activity
implements NavigationDrawerFragment.NavigationDrawerCallbacks {
/**
* Fragment managing the behaviors, interactions and presentation of the navigation drawer.
*/
private NavigationDrawerFragment mNavigationDrawerFragment;
private static CharSequence mTitle;
public static Context context;
public static Context getContext() {
return context;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = getApplicationContext();
mNavigationDrawerFragment = (NavigationDrawerFragment)
getFragmentManager().findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
}
#Override
protected void onDestroy() {
super.onDestroy();
android.os.Process.killProcess(android.os.Process.myPid());
super.onDestroy();
}
#Override
public void onBackPressed() {
super.onBackPressed();
finish();
}
#Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getFragmentManager();
switch (position) {
case 1:
fragmentManager.beginTransaction()
.replace(R.id.container, new AlgebraicGraphs())
.commit();
break;
case 2:
fragmentManager.beginTransaction()
.replace(R.id.container, new Logarithms())
.commit();
break;
case 3:
fragmentManager.beginTransaction()
.replace(R.id.container, new Polynomials())
.commit();
break;
case 4:
fragmentManager.beginTransaction()
.replace(R.id.container, new Powers())
.commit();
break;
case 6:
fragmentManager.beginTransaction()
.replace(R.id.container, new AreaFormulas())
.commit();
break;
case 7:
fragmentManager.beginTransaction()
.replace(R.id.container, new SurfaceAreaFormulas())
.commit();
break;
case 8:
fragmentManager.beginTransaction()
.replace(R.id.container, new PerimeterFormulas())
.commit();
break;
case 9:
fragmentManager.beginTransaction()
.replace(R.id.container, new VolumeFormulas())
.commit();
break;
case 11:
fragmentManager.beginTransaction()
.replace(R.id.container, new TrigonometryGraphsFormulas())
.commit();
break;
case 12:
fragmentManager.beginTransaction()
.replace(R.id.container, new HyperbolicIdentities())
.commit();
break;
case 13:
fragmentManager.beginTransaction()
.replace(R.id.container, new TrigonometricIdentities())
.commit();
break;
case 16:
fragmentManager.beginTransaction()
.replace(R.id.container, new IntegralIdentities())
.commit();
break;
case 17:
fragmentManager.beginTransaction()
.replace(R.id.container, new IntegralSpecialFunctions())
.commit();
break;
case 18:
fragmentManager.beginTransaction()
.replace(R.id.container, new TableOfIntegrals())
.commit();
break;
case 20:
fragmentManager.beginTransaction()
.replace(R.id.container, new DerivativeIdentities())
.commit();
break;
case 21:
fragmentManager.beginTransaction()
.replace(R.id.container, new TableOfDerivatives())
.commit();
break;
default:
fragmentManager.beginTransaction()
.replace(R.id.container, new DefaultLayout())
.commit();
break;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
if (!mNavigationDrawerFragment.isDrawerOpen()) {
// Only show items in the action bar relevant to this screen
// if the drawer is not showing. Otherwise, let the drawer
// decide what to show in the action bar.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
return super.onCreateOptionsMenu(menu);
}
#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_about) {
About about = new About();
about.show(getFragmentManager(), "about");
}
return false;
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
/**
* Returns a new instance of this fragment for the given section
* number.
*/
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
}
}
This is the log:
02-19 06:41:24.849 9788-9788/l.pocketformulas E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.IllegalStateException: Fragment Logarithms{4132f5d0} not attached to Activity
at android.app.Fragment.getResources(Fragment.java:828)
at l.pocketformulas.Logarithms$1.onPageFinished(Logarithms.java:71)
at android.webkit.CallbackProxy.handleMessage(CallbackProxy.java:444)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:155)
at android.app.ActivityThread.main(ActivityThread.java:5520)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1029)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:796)
at dalvik.system.NativeStart.main(Native Method)
In OnCreate() method of your main activity use this code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Or you can also set Orientation in manifest.xml like:
<activity
android:name="com.example.fragment.AppMainTabActivity"
android:configChanges="keyboardHidden|orientation"
android:screenOrientation="portrait"
android:theme="#style/AppTheme"
android:windowSoftInputMode="adjustPan" >
</activity>
Now your orientation will be set to portrait and will never change.
Update:
#Override
protected void onSaveInstanceState(Bundle outState) {
webView.saveState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
}
Now, your onCreate() implement like:
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.blah);
if (savedInstanceState != null)
((WebView)findViewById(R.id.webview)).restoreState(savedInstanceState);
}
These methods can be overridden on any activity, it just basically allows you to save and restore values each time an activity is created/destroyed, when the screen orientation changes the activity gets destroyed and recreated in the background, so therefore you could use these methods to temporary store/restore states during the change.
For an example go to this page :http://www.devahead.com/blog/2012/01/preserving-the-state-of-an-android-webview-on-screen-orientation-change/
I did solve this problem with a simple configuration on "AndroidManifest.xml":
<activity android:name=".MainActivity" android:configChanges="orientation|screenSize|screenLayout|keyboardHidden">
have you checked this?
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
Depending on your device you may need to include "screenSize" in confingChange. other wise your activity will restarted.
like this:
<activity
android:name="MyActivity"
android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
android:screenOrientation="sensor" />
I basically have a layout divided into two halves. On my left i have buttons that trigger the various fragments that are displayed in the layout on my right.
When i click on each button the respective fragment is loaded in the fragment display area. Some of the fragments for example Fragment A and Fragment D display complex data by querying a database or getting data from the internet etc. As long as the app is running this data will not change once it is loaded. My question is can i just revert the fragment to the previous state and display it. To be more clear -> i click Fragment A button, in the Fragment A class all the calculations are done and displayed, then i click Fragment B and fragment B is displayed and then C. Now when i click back on Fragment A button i just want it to load back the data, not redo calculation/connections/db queries.
Code being used :
public void onClick(View v) {
switch (position) {
case 0:
newContent = new FragmentA();
break;
case 1:
newContent = new FragmentB();
break;
case 2:
newContent = new FragmentC();
break;
case 3:
newContent = new FragmentD();
break;
case 4:
newContent = new FragmentE();
break;
default: break;
}
if (newContent != null){
mContent = newContent;
switchFragment(newContent);
}
}
public void switchFragment(Fragment fragment) {
mContent = fragment;
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.replacelayout, fragment)
.commit();
}
Fragment Code example
public class FragmentA extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragmenta, container, false);
}
#Override
public void onActivityCreated (Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
RUN ASYNTASKS TO CONNECT/QUERYDB AND DIPLAY THE DATA
}
}
Don't know how to go about it - using backStack ?? onResume() ?? because i am not sure what function is invoked when the .replace is invoked.
Thanks in Advance
Instead of using fragment.replace you can use fragment.show and fragment.hide fragmentByTagName. This will keep they're states in memory. It might look something like this.
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
//find the fragment by View or Tag
MyFrag myFrag = (MyFrag)fragmentManager.findFragmentByTag(TAG);
fragmentTransaction.hide(myOldFrag);
fragmentTransaction.show(myNewFrag);
fragmentTransaction.commit();
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Fragment newContent = null;
getSupportFragmentManager()
.beginTransaction()
.hide(mContent)
.commit();
switch (position) {
case 0:
getSupportFragmentManager()
.beginTransaction()
.show(home)
.commit();
mContent = home;
getSlidingMenu().showContent();
break;
case 1:
if(ifdownexsists == true){
getSupportFragmentManager()
.beginTransaction()
.show(download)
.commit();
mContent = download;
getSlidingMenu().showContent();}
else
{ download = new DownloadFile();
getSupportFragmentManager()
.beginTransaction()
.add(R.id.replacelayout, download)
.commit();
mContent = download;
ifdownexsists = true;
getSlidingMenu().showContent();
}
break;
case 2:
if(ifexsists == true){
getSupportFragmentManager()
.beginTransaction()
.show(oldCheckValue)
.commit();
mContent = oldCheckValue;
getSlidingMenu().showContent();}
else
{ oldCheckValue = new CheckValues();
getSupportFragmentManager()
.beginTransaction()
.add(R.id.replacelayout, oldCheckValue)
.commit();
mContent = oldCheckValue;
ifexsists = true;
getSlidingMenu().showContent();
}
break;
Works like a charm ... even keeps the progress of the progressbars in the background and shows them correctly when the fragment becomes visible again