How can i start a Fragment in the AboutAndHelpActivity instead of the Activity itself or how can i put the Fragment in startActivity()?
//if it is the first start of the app, open HelpFragment once.
Boolean isFirstRun = getSharedPreferences("PREFERENCE", MODE_PRIVATE)
.getBoolean("isFirstRun", true);
if (isFirstRun) {
startActivity(new Intent(MainActivity.this, AboutAndHelpActivity.class));
Toast.makeText(MainActivity.this, "First Run", Toast.LENGTH_LONG)
.show();
}
getSharedPreferences("PREFERENCE", MODE_PRIVATE).edit()
.putBoolean("isFirstRun", false).commit();
Before you want to think about activity and fragment
I will suggest you to read about it
So that you will get idea
Please check the link for fragment information
https://developer.android.com/guide/components/fragments.html
You can add, remove or replace the fragment in the activity
You should manage fragment life cycle.
Otherwise you might get some unexpected UI or app issues
You are completely misunderstand what is Activities and Fragments. Read about them again.
tl;dr: Activity - base unit. Fragment - part. Fragment can be only hosted in some activity, and can't be displayed other way.
Here how you can display fragment in activity:
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_holder,new MyFragment())
.addToBackStack(MyFragment.class.getSimpleName())
.commit();
If I understood you correctly, AboutAndHelpActivity is supposed to be started on the app's first run and house a Fragment.
If so, the starting the Activity part is already solved in you initial question, so what remains is showing the Fragment. Two options make sense to me:
In case AboutAndHelpActivity's only job is to house the Fragment and won't be started for any other purpose, the Fragment can be added to its layout xml.
Otherwise, the Fragment needs to be added dynamically based on an Intent extra as already pointed out by #Ekalips.
Related
I'm operating in a fragment, and one of the options is to delete the thing I'm looking at. Upon confirming the delete action, I want it to just back out to the home screen, or MainActivity, and I don't want to go through the backstack, since that will attempt to traverse over the thing I just deleted.
You can use below code to clear all previous stack, Launch the same main activity.
Intent i = new Intent(OldActivity.this, MainActivity.class);
// set the new task and clear flags
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(i);
You can also use ActivityCompat.finishAffinity() to clear all child activities.
You can consider calling finish() or getActivity().finish() method to close the parent activity before you start the downstream activities.
I don't think the problem is how to restart the Activity to circumvent data loading. The question should be why your program can't allow returning MainActivity by rolling back the stack and reload data?
Sending a new Intent can really solve your problem, but I think this may not be the most elegant approach.
Generally speaking, elegantly, your data can be shared. After deleting the data, other locations are automatically synchronized; or you are allowed to reload the data and work normally.
There are so many ways to do so.
You can clear your FragmentManager's back-stack completely.
OR just restart that activity with
if (getActivity() != null) {
Intent intent = getActivity().getIntent();
getActivity().finish();
startActivity(intent);
}
jitesh mohite's answer has a drawback, if you'll start a new Activity, you'll end up losing all the data on the screen(if any). Launching a Fragment usually causes Activity to pause, and if re-launching an activity was the case, well why not use Activities is the first place?
A FragmentManager always consist of a list of Fragments in the BackStack
You can loop through all the Fragments and pop them out.
To clear the Fragments BackStack of a FragmentManager, you could iterate through all back stack items and call popBackStack()
FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {
fm.popBackStack();
}
But there is also more elegant solution:
// in my case I get the support fragment manager, it should work with the native one too
FragmentManager fragmentManager = getSupportFragmentManager();
// this will clear the back stack and displays no animation on the screen
fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Is there a way to know which Fragment is currently displayed in a given <fragment> container of an Activity without keeping track of all the changes via the onAttachFragment callback?
Is it even possible to know which fragments are displayed when fragment transactions can take place when the user presses the back key? In this latter case, i.e. when a Fragment is re-displayed due to a back, the onAttach is not called.
In my experience, the only way to know for sure which fragment is being displayed is to keep track of that carefully yourself.
For example, you could make a variable in your Activity:
Fragment mCurrentDisplayedFragment;
and then whenever the user requests a different fragment do:
mCurrentFragment = (Fragment) userRequestedFragment;
fragmentManager.replace(container, mCurrentFragment, tag);
Then, whenever you needed to do things to the currently displayed fragment, you could triage it by try/catching a cast or with instanceof.
You could also handle the back pressed behavior by overriding that method in the activity:
#Override
public void onBackPressed() {
int stackSize = fragmentManager.getBackStackEntryCount();
// This counts up from the bottom so the most recent fragment is the biggest number/size
backFragId = fragmentManager.getBackStackEntryAt(stackSize);
// Get a handle on the fragment that is about to be popped
mCurrentFragment = fragmentManager.findFragmentById(backFragId);
super.onBackPressed();
}
Also, are you sure that onAttach is not called when a fragment is popped off the stack? I seem to remember that it will be, and you can call through the interface created there (if you have one and the activity implements it) to register the fragment as the current fragment in the activity at the time.
But to directly answer your question, there isn't a built in way to just know what fragment is currently displayed (and there could be more than one!). The implementation details of that are up to you. Hopefully I've given you some ideas of how it could be handled though. You might also find the FragmentManager documentation helpful.
Each time when you add/replace fragment to the container, use tag for it:
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.container, fragment, tag).commit();
then you can find out the fragment is current visible or not:
Fragment fg = getFragmentManger().findFragmentByTag(tag);
if(fg.isVisible())
//fg is the current visible fragment
Hope this help!
I've found a lot of questions about that, but none of these can help me.
I have a "MainActivity" which have 4 fragments.
I need to access to one of these fragments, called "my_fragment", in an other simple activity, let's call "SecondActivity".
So, I try to put a property android:tag="my_fragment" in the LinearLayout markup XML of "my_fragment".
And after that, I do that in "SecondActivity":
Fragment frg = getFragmentManager().findFragmentByTag("my_fragment");
... in order to get my fragment. But frg is always null.
I try a lot of others ways, but in vain. This one seems better and easier to do, but perhaps I'm wrong.
Any help would be appreciate. Thank you in advance.
Fabien
EDIT
Since your answers that indicate that's isn't possible, I want to specify what I need.
I just want to get this fragment for reload it. I found something like that on an other subject on Stackoverflow:
frg= getFragmentManager().findFragmentByTag(my_fragment);
final FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.detach(frg);
ft.attach(frg);
ft.commit();
By the way, I just try to get the fragment in the fragment himself and it's still return null. With the method :
findFragmentById(R.layout.my_fragment)
it's the same result.
And after, I did :
findFragmentById(this.getId())
But it's make an infinite looper, I don't understand the reason...
EDIT2
Alright, let’s give some details :
I have MainActivity with ViewPager with 4 fragments. It’s not fragments at the xml sense. Sorry if I’m confused, I was training to Android very recently and somethings are not clear for me again. So, before yesterday and the read of #Bruce edit, I was thinking that fragments were the components of a ViewPager. So, #Bruce, this is why I can’t use your solution. I was trying to use findFragmentByTag with the tag applicate on my principal LinearLayout markup of my fragment - that is not, I repeat, an xml markup fragment.
This is my approach :
In my MainActivity, I click on the third fragment. I make a research for find some points around me. After an action of the user, still from the third fragment, I open the SecondActivity for authentification and on the user connection, I close this SecondActivity. Now, I need to reload the fourth fragment that will adapt his components in terms of the user situation, while keeping the same state on the third fragment, with points loaded. It’s why can’t use your solution #menion.asamm : I can’t reinstantiate the MainActivity, even if I simulate a click on the third fragment because it will come back in his initial state, without points loaded.
Thank you both of you #Bruce and #menion.asamm for your time in helping me !
Fragments are always owned by one activity, so you cannot directly access a different activity's fragments. The call you are making is looking for fragments within your SecondActivity.
Why do you want to do this? Once some UI is off screen (MainActivity), you usually don't want to do anything with those UI objects, because Android may have removed them from memory. If there is data in "my_fragment" that is needed by SecondActivity, one approach might be to save the data in SharedPreferences or a database in my_fragment, and then load it in SecondActivity.
EDIT
I'm not sure you're getting that it is important which activity you are running in. Here are two options for how to proceed:
If you just want to run the SAME instance of your fragment that was already running inside MainActivity, then maybe what you want to do is finish your SecondActivity to return to MainActivity.
If you want a NEW copy of the same fragment inside SecondActivity, then you can include the fragment inside SecondActivity's layout (or add it to some container later).
Also, notice that for your call to findFragmentById, the ID needs to be the ID that was specified in the layout file as the value of android:id (not the R.layout.my_fragment). It might be better to use a fragment tag, which you can either specify in your layout file or when you add the fragment.
Mainly I think you need to read Google's guide on fragments.
EDIT2:
Ah, I see, I have a similar fragment-refresh situation in my app. You basically need to get data from SecondActivity back to the fragment inside MainActivity. The approach I use is this:
Save the data from SecondActivity in storage (DB or SharedPreferences).
Finish SecondActivity so that MainActivity and your fragment are shown again.
Override onResume in your fragment to fetch the data you saved in SecondActivity.
Another option is to launch SecondActivity using startActivityForResult, and then process the results in MainActivity, passing them to its fragment.
Regarding how to find the fragment by tag, you first need to set the fragment's tag. If you are declaring your fragment in a layout XML, then you can do it there (and you can also declare
<fragment class="com.xyz.MyFragment"
android:tag="MyFragment"
android:id="#+id/my_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
Now from inside MainActivity you can either do findFragmentById(R.id.my_fragment) or findFragmentByTag("MyFragment").
If you are NOT declaring the fragment in XML, but adding it directly, you can set the fragment's tag as part of the add call:
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.frag_parent, new MyFragment(), tag);
EDIT3: Ah, you're using ViewPager to hold fragments. Now I understand better. They're still fragments, but getting access to them is indeed tricky, because Android constructs a fragment tag in some internal code. Here is another SO question on this issue:
Retrieve a Fragment from a ViewPager
Hmm if you really need just refresh of fragment attached to different activity, I suggest:
first activity start second activity with
startActivityForResult(intent, MY_CODE);
second activity when wants to refresh fragment in first activity, finish it's state with
Intent data = new Intent();
data.putExtra("REFRESH_FRAGMENT", true);
setResult(RESULT_OK, data);
finish();
back in first activity, you may catch this result by
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// check request code
if (requestCode == MY_CODE) {
// check result
if (resultCode == RESULT_OK) {
// check data
if (data != null && data.getBooleanExtra("REFRESH_FRAGMENT", false)) {
refreshFragment();
}
}
}
}
Possible?
Hi All I want to open the "Text-To-Speech output" fragment of Settings from my application. I think first I need to open the settings activity and then its fragment. I tried setting the ComponentName but it was unable to locate the activity.
Should I use FragmentManager; I couldn't find anything specific to my needs. Can somebody give me some link which might explain it well.
You are right, First You need to start the Activity than set the current Fragment in FragmentPager / Manager... Their is no such way to start some foreign fragment from your Activity that would be dangerous see that will lead to zombie fragments floating around the App (or May be I am not aware of that..)
You call the Activity Intent with some parameter for the Fragment name, you want to start i.e. interger, boolean etc...
Intent intent = new Intent(this,SecondActivity.class);
intent.putExtra("fragmentNumber",1); //for example
startActivity(intent);
You check the passed value inside OnCreate of the Second Acitivty and set the desired fragment on top.. inside OnCreate
if(getIntent().getIntExtra("fragmentNumber",0)==1){
//set the desired fragment as current fragment to fragment pager
}
However, I am not getting the problem "It was unable to locate the activity." Have you entered the Activity in manifest file than what was the problem you were facing? Please post the full stack trace.
You can use the following:
Intent ttsSettings = new Intent("com.android.settings.TTS_SETTINGS");
ttsSettings.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(ttsSettings);
I need to refresh my activity. I have bunch of question regrading the same which advice me to finish current activity and restart the current activity. OR again provide value to each widget. To avoid transition I used this code
Intent intent = getIntent();
overridePendingTransition(0, 0);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
this.finish();
overridePendingTransition(0, 0);
startActivity(intent);
But in my case In my activity I have four tabs, and I need to refresh all four tabs.
There are few more problems regarding the same
1) With above code, if I am on other screen, I come back to this screen when above piece of code runs.
2) Activity sequence gets disturb.
3) Maintaining selected tab will also be a part of problem
Even if I try to refresh each tab seperatley, One of my tab have webview. how to refresh that as webview.loadData() can't be called unless there is view and since I am not on that tab there will no view.
What can be the ideal way to tackle this problem. Any help will be appreciated.
It depends a bit on your use case. You may setContentView() again to inflate the layout every time. If you are just displaying a list, then you may just call the adapter to display the list. You have to do this for every fragment in your TabActivity.
To reload a WebView I would just call loadUrl() again.
As to remembering the selected tab, you have to store it and then set the current tab in the TabHost.
Question was not much complicated but solution what I wanted got to be optimised. Finally I took the second way, ie refreshing each component. This approach overcomes the problem of disturbing the sequence of activity. For web view I am still using webView.loadData(...).
In total I have handeled each tab separately. If I include my entire code then it would become clumsy, but still trying to incorporate as many important feature.
In my activity class when I need to refresh my activity, I called this method.
private void onRefrash()
{
refreshCurrentActivity();
int selectedTab = getActionBar().getSelectedNavigationIndex();
switch (selectedTab)
{
case TAB1:
fragment1.update();
break;
case TAB2:
fragment2.update();
break;
case TAB3:
fragment3.update();
break;
}
Toast.makeText(this, getString(R.string.msg_case_updates_received), Toast.LENGTH_LONG).show();
}
}
Each fragment is earlier initialised, and update method is called for each tab in which I am updating the corresponding web view.