This is my first time using Fragments and I'm rather new to Android. I'm using Fragments to manage a settings menu for my app.
I have a MainActivity with a FragmentContainerView, the XML is like so:
<androidx.fragment.app.FragmentContainerView
android:visibility="gone"
android:id="#+id/main_activity_fragment_container"
android:background="#color/white"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
In the MainActivity.java File I have a method assigned to a button to make the FragmentContainerView visible, like so:
private void showFragments(FragmentContainerView fragmentContainerView) {
fragmentContainerView.setVisibility(View.VISIBLE);
// There is more to this method, but I don't think it is necessary for this example
}
I'm able to navigate all around the settings menu: inflate fragments, replace fragments, update Shared Preferences, use Browser Intent, etc. - everything I need to do for a settings menu.
What I haven't been able to figure out is how to closeout the Settings Menu (close the FragmentContainerView in the MainActivity) after a selection has been made (and thus return to the game). I can create a "close" button in every fragment - but I can't figure out a method to close (setVisibility to GONE) the MainActivity's FragmentContainerView.
Once I'm in a Fragment - is it even possible to access the FragmentContainerView the fragment resides inside of? I've tried a number of ways to access it and set the visibility to GONE, but I just get a crash.
Inside a fragment:
FragmentContainerView mainActivityFragmentContainer = (FragmentContainerView) view.findViewById(R.id.main_activity_fragment_container);
public void closeFragment(FragmentContainerView mainActivityFragmentContainer) {
mainActivityFragmentContainer.setVisibility(View.GONE);
// This causes a crash, the error log states:
// NullPointerException: Attempt to invoke virtual method 'void androidx.fragment.app.FragmentContainerView.setVisibility(int)' on a null object reference
}
I know a workaround where I don't have the fragmentContainerView fill up the entire screen and leave space for an external close button - but this solution seems inefficient.Any advice would be helpful!
Yes you can do it,
1- Create a public function in your MainActivity that closes the fragment container:
public void closeFragment() {
fragmentContainerView.setVisibility(View.GONE);
}
2- Call that function from your fragment when you need it:
// getActivity() will return the activity linked to that fragment so this fragment should be linked MainActivity
MainActivity activity = (MainActivity) getActivity();
acitvity.closeFragment();
Related
I got a idea yesterday and I wanted to ask you if this is working and how.
So I use a form to get user input and safe it into a database.
I use a activity for this task:
https://i.stack.imgur.com/zZMOi.png
Now I want to add another task with the same layout, but a different logic.
The user should be able to edit the data (same layout, but editing the information in database instead of creating a new object).
My idea:
A DataActivity should open, when the user wants to start the create or edit function.
The DataActivity holds two full screen fragments and should be able to start the right fragment.
Is it possible to link two full screen fragments to one activity?
You can do the following,
Add two buttons, save and edit with onClickListeners for opening a save_fragment and edit_fragment and in the edit_fragment make sure there's a Spinner which loads the entries off the database into the edit_fragment
phew that involves bit of coding
So a better way would be creating the database by using Room and in your respective Dao you can specify the replace conflict strategy for the update method which overrides/updates the old data with new one
#Dao
interface YourDao{
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(formData : FormData)
}
Check the official docs for more info about Room and onConflict Strategies
The simple answer to your question "Is it possible to link two full screen fragments to one activity?" is YES, you can attach as many fragments as you want to the same activity, as long as you handle those fragments properly within the host activity.
There are a lot of examples and usages related to this topic out there. I would recommend you to take a look at this guide: https://developer.android.com/guide/fragments so you can take a general idea of how fragments are used.
Below is a very simple code example related to the case you mentioned in your question:
MainActivity.kt
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
showProperFragment()
}
private fun showProperFragment() {
var fragmentToShow: Fragment
// todo: modify your condition here to decide whether showing fragment1 or fragment2
if (true) {
fragmentToShow = Fragment1.newInstance("something1", "something2")
} else {
fragmentToShow = Fragment2.newInstance("something1", "something2")
}
val transaction: FragmentTransaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.fragment_container, fragmentToShow)
transaction.addToBackStack(null)
transaction.commit()
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
and of course Fragment1 and Fragment2 are two example blank fragments.
I am building an application for android and I am not able to make that when I click on an item inside my Navigation drawer it opens a new activity pre established by me. can you help me?
I already tried some code using intents but when I click on the item it ends up closing the application.
case R.id.homepage: {
homepage();
break;
}
case R.id.pdefault: {
testdefault();
break;
}
private void homepage(){
startActivity(new Intent(getBaseContext(),MainActivity.class));
}
private void testdefault(){
startActivity(new Intent(getBaseContext(),testdefault.class));
}
The first case worked normally because I created a method for
start the activity, but I did the same for the second and it did not work.
The expected result is just a simple screen swap.
How did you create the activity? That name is not possible.
I recommend you to use right click - new - activity - empty activity. That will create the structure needed to recognize it as an activity.
Take into account that if you create it manually you will have to override from AppCompatActivity and declare the activity in the manifest as:
<activity android:name=".SomeActivity" />
It is not just creating a class. Make sure not to use underscores for activity names, keep the format of MainActivity
I have a Fragment that shows different view by a AdapterViewFlipper.
The AdapterViewFlipper is being set with MyCustomAdapter that contains 'View 1', 'View 2', 'View 3', and 'View 4', and its in a layout resource file that I inflated in my own Fragment "onCreateView()".
The Problem I'm facing is whenever I rotate my device, the current view in the AdapterViewFlipper goes back to the first view that was added in MyCustomAdapter.
For Example: if the current view in the AdapterViewFlipper is showing 'View 2' and the user rotates the device, it returns back to 'View 1'.
So what I'm trying to do is to restore the current view in the AdapterViewFlipper and its state in the Fragment whenever I rotate my device.
Although I found this method that says I should declare the android:configChanges attribute at the element in the AndroidManifest and it worked like a charm but when I was reading about it Android didn't recommend it.
But this works fine in Activity.
So is there a way I can go through this myself?
So the first thing you need to do, is to make sure you are retaining the fragment itself. And not place a new instance every time your activity is re-created.
You can establish that with a simple check in your onCreate() method.
You can either check if the savedInstance Bundle parameter to onCreate() is null, in that case only you need to replace your fragment OR check if your fragment is already added to your FragmentManager.
if (savedInstanceState == null) {
// This is a brand new activity, and not a re-creation due to config change
getSupportFragmentManager().beginTransaction().replace(id, yourFragmentInstnace, stringTag);
}
OR
if (getSupportFragmentManager().findFragmentByTag(fragmentTag) == null) {
// This is a brand new activity, and not a re-creation due to config change
getSupportFragmentManager().beginTransaction().replace(id, yourFragmentInstnace, fragmentTag);
}
And you also need to call setRetainInstance(true) in your fragment's onCreate() or something.
That will retain the same instance of your fragment during a configuration change.
This should automatically allow your AdapterViewFlipper to maintain its UI state, which is the current item it's showing.
You can find a nice example here
I have an application where there are: a splash screen, a main activity (started from the splash screen) where there's a navigationView that attach and detach some fragment.
In one fragment i need to download some information with an AsyncTask. The problem is that the AsyncTask is called in the splash screen (the splash screen survive for 3 seconds) and the download can takes more or less than 3 seconds. In the onPostExecute() in AsyncTask i want to call a function loadFeeback() (that is in the fragment class) only if the fragment is already loaded, if not i set a static variable downloaded to true.
public void onPostExecute(Feedback[] feedbacks){
Dati.feedbacks = feedbacks;
if(mainActivity != null) {
FragmentManager fragmentManager = mainActivity.getSupportFragmentManager();
FeedbackFragment feedbackFragment = ((FeedbackFragment) (fragmentManager.findFragmentById(R.id.nav_feedback)));
Dati.feedbackDownloaded = true;
if (feedbackFragment != null)
feedbackFragment.loadFeeback();
}
}
The problem is that i can't get the mainActivity reference and i can't pass the context to the AsyncTask because it is called from the splash screen.
Can anyone help me?
The Asynctask is tied to the splash activity,because it created it.
Maybe you can use a Headless Fragment( fragment without layout):
Create a fragment on precise in the onCreate function :
setRetainInstance(true)
In your splash activity create the fragment and save him with a tag :
HeadlessFragment headlessFragment = new HeadlessFragment()
getSupportFragmentMangager().beginTransaction().add(headlessFragment, "fragmenttag").commit();
Launch your asynctask in the fragment
And when your main activy is launched retrieved the fragment :
HeadlessFragment headlessFragment = getSupportFragmentMangager().findFragmentByTag("fragmenttag");
So the fragment will be attached to the main activity, and you should call whatever you need
Hope this helps.
Sorry for my poor english.
Normally In an Fragment, implicit intent can be used to start a brower component,if there are several brower component, the Android system will show an selection dialog ,the dialog just overlay the Fragment which send the intent.
but in my situation when selection dialog is shown ,the Fragment go to the background(disappeared) ,and the home screen can be seen.
does anyone encounter this problem ,how to make the Fragment not go to the backgoround.
in onPause method it just look like below in my fragment source
#Override
public void onPause() {
mLog.printMethodLifeCycle("onPause");
super.onPause();
}
and in activity I did not overide the onPause method
AndroidManifest.xml is too long ,can you tell me which part should I post or notice