Fragment Will Animate Again After App Return Back From Background Android
Update note: Aaqib Hussain updated this tutorial for Kotlin and Android Studio 3.iii. Huyen Tue Dao wrote the original tutorial.
A fragment is an Android component that holds part of the behavior and/or UI of an activity. Every bit the name would propose, fragments are non independent entities, but are tied to a single activeness. In many means, they have functionality similar to activities.
Imagine for a moment that you're a super villain. You take a lot to exercise, so you might employ a few minions to run around and do your laundry and taxes in commutation for lodging and nutrient. That'due south kind of like the human relationship between activities and fragments.
In the same way that yous don't actually need an army of niggling helpers to exercise your bidding, you lot don't take to utilise fragments. However, if you use them well, they tin provide:
- Modularity: Dividing complex activeness code across fragments for meliorate organization and maintenance.
- Reusability: Placing beliefs or UI parts into fragments that multiple activities can share.
- Adaptability: Representing sections of a UI as different fragments and utilizing unlike layouts depending on screen orientation and size.
In this tutorial, you'll build a mini-encyclopedia of dogs which displays a list of dog breeds arranged in a grid. When the user selects a breed, the app displays information about it. Through building this app you'll learn how to:
- Create and add together fragments to an activeness.
- Let your fragments ship information to an action.
- Add and replace fragments past using transactions.
Annotation: This tutorial assumes y'all're comfy the basics of Android programming and understand what the activeness lifecycle means. If yous're brand new to Android, you should work through both the Android Tutorial for Beginners and the Introduction to Activities showtime.
This tutorial utilizes an Android RecyclerView
. If you've never used RecyclerView
or need a refresher, you should also await at the Android RecyclerView Tutorial.
Time to get started!
Getting Started With Android Fragments
Employ the Download Materials push button at the top or bottom of this tutorial to download and extract the Starter Project.
In the Welcome to Android Studio dialog, select Import projection (Eclipse ADT, Gradle, etc.).
Check out the project El Dogo app. You'll find some resource files: strings.xml, activity_main.xml, drawable and layout files. There are also some boilerplate layouts for your fragments, non-fragment code that you'll need and a fragment class that you'll employ later to write your own.
The MainActivity
will host all of your wee fragments and DogListFragment
contains code to brandish a list of dog breeds content so that you can focus on fragments.
Build and run the project. You'll see that it'south pretty quiet in in that location.
Merely don't worry! You'll fix that…soon!
Android Fragment Lifecycle
Like an activity, a fragment has a lifecycle with events that occur when the fragment's status changes. For instance, an event happens when the fragment becomes visible and active, or when the fragment becomes unused and is removed. You lot can also add code and behaviors to callbacks for these events as you would for an activity.
Here's a fragment lifecycle diagram from the official Android Developer documentation:
The following lifecycle events come into play when you add a fragment:
-
onAttach
: The fragment attaches to its host activity. -
onCreate
: A new fragment instance initializes, which ever happens later information technology attaches to the host. Fragments are a flake like viruses. :] -
onCreateView
: A fragment creates its portion of the view hierarchy, which is added to its activity'south view hierarchy. -
onActivityCreated
: The fragment's action has finished its ownonCreate
consequence. -
onStart
: The fragment is visible. A fragment starts simply later its activeness starts and frequently starts immediately after its activity does. -
onResume
: The fragment is visible and interactable. A fragment resumes only later on its activity resumes and ofttimes resumes immediately after the activity does.
But look, the fragment isn't washed! These lifecycle events happen when you lot remove a fragment:
-
onPause
: The fragment is no longer interactable. This occurs when either the fragment is about to exist removed or replaced or when the fragment'southward activeness pauses. -
onStop
: The fragment is no longer visible. This occurs either after the fragment is about to be removed or replaced or when the fragment's activeness stops. -
onDestroyView
: The view and related resources created inonCreateView
are removed from the activity's view bureaucracy and destroyed. -
onDestroy
: The fragment does its final clean up. -
onDetach
: The fragment is detached from its activity.
As you can see, the fragment's lifecycle intertwines with the activeness's lifecycle. But information technology has extra events that are particular to the fragment's view hierarchy, state and attachment to its activity.
The V4 Support Library
In Android, when using fragments, there are 2 alternative fragment implementations you lot can use.
One type is the fragment that is provided by the platform version. A platform version corresponds to the version of Android that a user is running. For case, a device running Android 6.0, SDK Version 23, would be running platform version 23 of the library.
The second type is a support library fragment. When you lot include a back up library, it is added to your project in the same fashion as any third-party library.
Using the support library has ii benefits when developing applications for multiple versions of Android.
First, it ensures that you lot have consistency in your code and functionality beyond unlike devices and platform versions. This means that bugs and fixes will be more consequent across different versions of Android using these libraries.
Second, when they add together new features to the latest version of Android, the Android team volition oftentimes back-port these features via the support library in social club for developers to utilise on older versions of Android.
So, which library should yous use?
Android has deprecated platform fragments in Android 9.0, SDK Version 28. And then you should always go with the v4 support library when using fragments.
Creating a Fragment
Eventually, El Dogo will evidence a listing of dogs breeds on launch and borer on whatever of the items will display details about that particular breed. To offset, y'all'll work backwards and kickoff create the particular page.
Open up the starter project in Android Studio and notice fragment_dog_details.xml under app ▸ src ▸ main ▸ res ▸ layout. This XML file lays out the dog item display. Information technology also displays i of the drawable resources and the associated String
resource.
Locate the DogDetailsFragment.ky file in the project. This class will exist responsible for displaying details for a selected breed.
In DogDetailsFragment.kt, the code now looks like this:
import android.os.Package import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup //one grade DogDetailsFragment : Fragment() { //2 companion object { fun newInstance(): DogDetailsFragment { return DogDetailsFragment() } } //3 override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_dog_details, container, false) } }
This code:
- Declares
DogDetailsFragment
every bit a subclass ofFragment
. Observe theimport android.support.v4.app.Fragment
: This is from the v4 back up library mentioned before. - Provides a method for creating new instances of the fragment, a factory method.
- Creates the view for the fragment.
Activities use setContentView()
to specify the XML file that defines their layouts, but fragments create their view bureaucracy in onCreateView()
. Here you called LayoutInflater.inflate
to create the bureaucracy of DogDetailsFragment
.
The third parameter of inflate
specifies whether the inflated fragment should exist added to the container
. The container is the parent view that will agree the fragment's view bureaucracy. Yous should always set this to false
when inflating a view for a fragment: The FragmentManager
volition take care of adding the fragment to the container.
Using a factory method
There's a new child in town here: FragmentManager. Each activity has a FragmentManager that manages its fragments. It also provides an interface for y'all to access, add and remove those fragments.
You'll notice that while DogDetailsFragment
has a factory instance method, newInstance()
, it does not have any constructors.
Wait, why do you need a factory method but not a constructor?
Outset, because you did non define any constructors, the compiler automatically generates an empty, default constructor that takes no arguments. This is all that you should have for a fragment: no other constructors.
Second, you probably know that Android may destroy and later copy an action and all its associated fragments when the app goes into the background. When the action comes back, its FragmentManager
starts re-creating fragments by using the empty default constructor. If information technology cannot find one, you get an exception.
For this reason, information technology is best exercise to never specify any not-empty constructors. In fact, the easiest thing to practice is to specify none as yous did hither.
What if you need to laissez passer information or data to a Fragment? Hang on, yous'll get the answer to that later!
Adding a Fragment
Here's where you get to add together a fragment using the simplest approach — adding it to the activity's XML layout. This is likewise sometimes chosen Adding a Fragment Statically.
To do this, open up activity_main.xml, select the Text tab and add the post-obit inside of the root FrameLayout:
<fragment android:id="@+id/details_fragment" class="com.raywenderlich.android.eldogo.DogDetailsFragment" android:layout_width="match_parent" android:layout_height="match_parent"/>
Note: You lot could also employ android:name="com.raywenderlich.android.eldogo.DogDetailsFragment"
instead of course="com.raywenderlich.android.eldogo.DogDetailsFragment"
.
In this footstep, y'all're placing a <fragment>
tag inside of the activeness layout and specifying the blazon of fragment the class
attribute should inflate. FragmentManager
requires the view ID of the <fragment>
. By including this in the XML, the FragmentManager
knows to add this fragment to the activity automatically.
Build and run. You will see the fragment:
Adding a Fragment Dynamically
Outset, open activity_main.xml over again and remove the <fragment>
you inserted. Embrace the Zen of deleting code! You'll replace it with the list of dog breeds.
Open DogListFragment.kt, which has all the listing code. You tin see that the DogListFragment
has no explicit constructors and a newInstance()
.
The list lawmaking in DogListFragment
depends on some resource. You lot have to ensure that the fragment has a valid reference to a Context
for accessing those resource. That's where onAttach()
comes into play.
In DogListFragment.kt and add together these imports directly below the existing imports:
import android.bone.Parcel import android.support.v7.widget.GridLayoutManager
The GridLayoutManager
helps in positioning items in the breed list. The other import is for standard fragment overrides.
Inside of DogListFragment.kt, add the following method to a higher place the definition of the DogListAdapter
:
override fun onAttach(context: Context?) { super.onAttach(context) if (context != null) { // Get dog names and descriptions. val resources = context.resources names = resources.getStringArray(R.assortment.names) descriptions = resources.getStringArray(R.array.descriptions) urls = resources.getStringArray(R.array.urls) // Get domestic dog images. val typedArray = resources.obtainTypedArray(R.array.images) val imageCount = names.size imageResIds = IntArray(imageCount) for (i in 0 until imageCount) { imageResIds[i] = typedArray.getResourceId(i, 0) } typedArray.recycle() } }
onAttach()
contains code that accesses the resource such as breed names and descriptions you need via the Context
to which the fragment is fastened. Because the lawmaking is in onAttach()
, you can rest assured that the fragment has a valid Context
.
Add this method correct subsequently the onAttach()
:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Packet?): View? { val view: View = inflater.inflate(R.layout.fragment_dog_list, container, faux) val action = activeness as Context val recyclerView = view.findViewById<RecyclerView>(R.id.recycler_view) recyclerView.layoutManager = GridLayoutManager(activity, 2) recyclerView.adapter = DogListAdapter(activity) render view }
In onCreateView()
, you inflate the view hierarchy of DogListFragment
, which contains a RecyclerView
, and perform some standard RecyclerView
setup.
If y'all take to inspect a fragment's view, onCreateView()
is a good place to starting time because it generates the view.
Next open MainActivity.kt and add the post-obit to the bottom of onCreate()
:
// i if (savedInstanceState == nil) { // ii supportFragmentManager // 3 .beginTransaction() // 4 .add(R.id.root_layout, DogListFragment.newInstance(), "dogList") // 5 .commit() }
At this indicate, to get DogListFragment
into MainActivity
. You ask your new friend, FragmentManager
, to add it.
Here y'all:
- Check that the
savedInstanceState
isnaught
. This is a style to see if information technology'southward an initial open of the screen. - Grab the
FragmentManager
by referencingsupportFragmentManager
as opposed tofragmentManager
, since yous are using support fragments. - Ask that
FragmentManager
to first a new transaction by callingbeginTransaction()
— you probably figured that out yourself. - Specify the add together operation that you want past calling
add
and passing in:- The view ID of a container for the fragment's view hierarchy in the activity's layout. If you take a look at
activity_main.xml
, you'll detect@+id/root_layout
. - The fragment instance you desire to add.
- A cord that acts as a tag/identifier for the fragment instance. This allows the
FragmentManager
to afterward retrieve the fragment for yous.
- The view ID of a container for the fragment's view hierarchy in the activity's layout. If you take a look at
- Finally, ask the
FragmentManager
to execute the transaction past callingcommit()
.
In the code above, an if
block contains the code that displays the fragment and checks that the activity doesn't take saved land. When an activity saves, all of its active fragments are too saved. If you don't perform this check, this could happen:
And you may feel like this:
The lesson: Always keep in mind how the saved state affects your fragments.
And with that, you've added the fragment!
Build, run and you'll see a dog list once the app launches:
FragmentManager
helped achieve this awesomeness through FragmentTransactions
, which are basically fragment operations such as add and remove.
Data Binding
While poking effectually the project y'all may have noticed a few things:
- A file called
DataBindingAdapters
. - A reference to
dataBinding
in the app modulebuild.gradle
:dataBinding { enabled = truthful }
- A data department in the
recycler_item_dog_model.xml
layout file.<layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="dogModel" blazon="com.raywenderlich.android.eldogo.DogModel"/> </data> ... </layout>
- A
DogModel
data class.
If you haven't used information binding earlier you may be like…
Permit'due south take a quick walkthrough.
Commonly, if you want to set up the value of properties in your layout, you'd use something similar the following in your fragments and activities:
developer.name = "a purr programmer" view.findViewById<TextView>(R.id.name).setText(programmer.name)
The problem with that is that if you change the value of name
for programmer
, you would need to do a subsequent setText
to the TextView
in club to update the item. Imagine having a tool where you could bind a variable from your fragments and activities to your view and allow for changes to the variable to automatically update in the View. That is what data binding does for you.
Looking at our El Dogo app, the enabled=truthful
in the build.gradle
enables data binding in the awarding. Your information class contains information that you want to use in your fragment and display in your view. The information field contains variables consisting of proper noun and type options which specify the type and name of the variable beingness bound.
This information is used in the view using {@}
notation. For example, the post-obit would set a text field to the value held by the name field of the dogModel variable. You can run into this in the TextView
with the ID name
:
tools:text="@{dogModel.name}"
At present that you have your view gear up, you need to access your view and bind the variables to it. This is where the information bounden magic comes in!
Whenever a view has a data
field, the framework automatically generates a bounden object. Information technology creates the name of the object by converting the snake case proper name of the view into camel case and adding bounden to the proper name. For case, a view called recycler_item_dog_model.xml
would have a respective binding chosen RecyclerItemDogModelBinding
. You can meet this in DogListAdapter
in DogListFragment.kt:
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder { val recyclerDogModelBinding = RecyclerItemDogModelBinding.inflate(layoutInflater, viewGroup, false) val dog = DogModel(imageResIds[position], names[position], descriptions[position], urls[position]) recyclerDogModelBinding.dogModel = dog
Yous can then inflate the view via the inflater method on the bounden object and set backdrop via standard property access mechanisms.
Data binding follows a Model-View-ViewModel (MVVM) blueprint. MVVM consists of three components:
- View: The layout file.
- Model: The information class
- View Model/Binder: The motorcar-generated binding files.
For further reading on the MVVM, and other design patterns, refer to the tutorial Mutual Design Patterns for Android. You'll run into more than on data biding later on.
Communicating With the Activity
Fifty-fifty though fragments attach to an activity, they don't necessarily all talk to one another without some further encouragement from y'all.
For El Dogo, you lot'll need DogListFragment
to let MainActivity
know when the user has made a selection so that DogDetailsFragment
can display the selection.
To kickoff, open DogListFragment.kt and add the post-obit Kotlin interface at the lesser of the class:
interface OnDogSelected { fun onDogSelected(dogModel: DogModel) }
This defines a listener interface for the activity to listen to the fragment. The activity will implement this interface and the fragment will invoke the onDogSelected()
when the user selects an item, passing the pick to the activity.
Add this new field below the existing ones in DogListFragment
:
private lateinit var listener: OnDogSelected
This field is a reference to the fragment's listener, which volition exist the action.
In onAttach()
, add the post-obit direct below super.onAttach(context)
:
if (context is OnDogSelected) { listener = context } else { throw ClassCastException( context.toString() + " must implement OnDogSelected.") }
This initializes the listener reference. Look until onAttach()
to ensure that the fragment really fastened itself. Then verify that the activity implements the OnDogSelected
interface via is
.
If it doesn't, it throws an exception since yous tin't go along. If information technology does, fix the activity as the listener
for DogListFragment
.
Note: At present you can remove the if (context != null)
line in onAttach()
if you like.
Okay, I lied a picayune: The DogListAdapter
doesn't have everything you need! In the onBindViewHolder()
method in DogListAdapter
, add together this code to the bottom.
viewHolder.itemView.setOnClickListener { listener.onDogSelected(dog) }
This adds a View.OnClickListener
to each canis familiaris breed so that it invokes the callback on the listener, the activeness, to pass forth the selection.
Open up MainActivity.kt and update the course definition to implement OnDogSelected
:
class MainActivity : AppCompatActivity(), DogListFragment.OnDogSelected {
You will go an error request y'all to make MainActivity
abstruse or implement the abstract method onDogSelected(dogModel: DogModel)
. Don't fret withal, you'll resolve information technology soon.
This code specifies that MainActivity
is an implementation of the OnDogSelected
interface.
For now, you'll prove a toast to verify that the code works. Add the following import below the existing imports so that you tin can employ toasts:
import android.widget.Toast
Then add the following method below onCreate()
:
override fun onDogSelected(dogModel: DogModel) { Toast.makeText(this, "Hey, you selected " + dogModel.name + "!", Toast.LENGTH_SHORT).evidence() }
The error is gone! Build and run. Once the app launches, click one of the domestic dog breed. You should meet a toast message naming the clicked particular:
Now y'all've got the action and its fragments talking. You're like a main digital diplomat!
Fragment Arguments and Transactions
Currently, DogDetailsFragment
displays a static Drawable
and set up of Strings
. But what if you want information technology to brandish the user'southward selection?
First, supersede the unabridged view in fragment_dog_details.xml
with:
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <information> <variable name="dogModel" type="com.raywenderlich.android.eldogo.DogModel" /> </data> <ScrollView xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" tools:ignore="RtlHardcoded"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="vertical"> <TextView android:id="@+id/name" style="@style/TextAppearance.AppCompat.Title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/dog_detail_name_margin_top" android:layout_marginBottom="0dp" android:text="@{dogModel.name}" /> <ImageView android:id="@+id/dog_image" imageResource="@{dogModel.imageResId}" android:layout_width="wrap_content" android:layout_height="@dimen/dog_detail_image_size" android:layout_marginTop="@dimen/dog_detail_image_margin_vertical" android:layout_marginBottom="@dimen/dog_detail_image_margin_vertical" android:adjustViewBounds="true" android:contentDescription="@null" android:scaleType="centerCrop" /> <TextView android:id="@+id/description" style="@style/TextAppearance.AppCompat.Body1" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginLeft="@dimen/dog_detail_description_margin_left" android:layout_marginTop="0dp" android:layout_marginRight="@dimen/dog_detail_description_margin_right" android:layout_marginBottom="@dimen/dog_detail_description_margin_bottom" android:autoLink="spider web" android:text="@{dogModel.text}" /> </LinearLayout> </ScrollView> </layout>
This is about the aforementioned as the layout was before except with data binding added. At the acme you'll see that you've added a variable for our DogModel. The text for name and clarification is bound to the variables of the same name in the DogModel object. Then, you're using this variable to set values on the views.
Binding Adapters
On the ImageView
for the canis familiaris image you'll notice the following tag:
imageResource="@{dogModel.imageResId}"
This corresponds to a binding adapter in the DataBindingAdapters.kt
file.
@BindingAdapter("android:src") fun setImageResoruce(imageView: ImageView, resource: Int) { imageView.setImageResource(resources) }
A binding adapter allows yous to perform actions on an element which are non supported by default data binding. In your case, y'all are storing a resource integer for the epitome to display, but information binding does not provide a default mode to display an image from an ID.
To fix that, you have a BindingAdapter that takes a reference to the object from which it was invoked, along with a parameter. It uses that to phone call setImageResource
on the imageView
that displays the epitome of the dog.
At present that your view is set up, replace newInstance()
in DogDetailsFragment
with the code shown beneath:
individual const val DOGMODEL = "model" fun newInstance(dogModel: DogModel): DogDetailsFragment { val args = Parcel() args.putSerializable(DOGMODEL, dogModel) val fragment = DogDetailsFragment() fragment.arguments = args return fragment }
A fragment tin can take initialization parameters through its arguments, which y'all access via the arguments
holding. The arguments are really a Bundle
that stores them as key-value pairs, like the Bundle
in Activity.onSaveInstanceState
or the Activity extras from intent.extras
.
Y'all create and populate the arguments' Bundle
, set the arguments
and, when you need the values later, you reference arguments
property to retrieve them.
Equally you lot learned earlier, when a fragment is re-created, the default empty constructor is used— no parameters for y'all.
Because the fragment tin recall initial parameters from its persisted arguments, you can utilize them in the re-cosmos. The in a higher place code also stores information virtually the selected breed in the DogDetailsFragment
arguments.
Add together the following import to the top of DogDetailsFragment.kt:
import com.raywenderlich.android.eldogo.databinding.FragmentDogDetailsBinding
Update note: You may need to rebuild the project for FragmentDogDetailsBinding
to be available
At present, replace the contents of onCreateView() with the post-obit:
// one val fragmentDogDetailsBinding = FragmentDogDetailsBinding.inflate(inflater, container, fake) // ii val model = arguments!!.getSerializable(DOGMODEL) as DogModel // three fragmentDogDetailsBinding.dogModel = model model.text = String.format(getString(R.string.description_format), model.description, model.url) render fragmentDogDetailsBinding.root
Breaking it down:
- Inflate the view using
FragmentDogDetailsBinding
. Since yous want to dynamically populate the UI of theDogDetailsFragment
with the pick, you grab the reference to theFragmentDogDetailsBinding
. - Become the
DogModel
from thearguments
. - Next, yous demark the view
dogModel
with theDogModel
that you've passed toDogDetailsFragment
.
Finally, you need to create and display a DogDetailsFragment
when a user clicks an item, instead of showing a toast. Open MainActivity and replace the logic inside onDogSelected
with:
// 1 val detailsFragment = DogDetailsFragment.newInstance(dogModel) supportFragmentManager .beginTransaction() // ii .supervene upon(R.id.root_layout, detailsFragment, "dogDetails") // 3 .addToBackStack(null) .commit()
Y'all'll discover this code is similar to your starting time transaction which added the listing to MainActivity
, but there are also some notable differences. In this code yous:
- Create a fragment instance that includes some dandy parameters.
- Call
replace()
, instead ofadd
, which removes the fragment currently in the container and then adds the new Fragment. - Phone call some other new friend: the
addToBackStack()
ofFragmentTransaction
. Fragments have a back stack, or history, like Activities.
Navigating the Fragment Back Stack
The fragment back stack is non independent of the activity back stack. Recall of it as an actress stack of history on height of that of the host activity.
When yous navigate betwixt activities, each one gets placed on the action back stack. Whenever you commit a FragmentTransaction
, y'all have the option to add together that transaction to the dorsum stack.
Then, what does addToBackStack()
practise? It adds the replace()
to the back stack so that when the user hits the device's back push information technology undoes the transaction. In this example, hitting the back button sends the user back to the full list.
The add together()
transaction for the listing omits calling addToBackStack()
. This means that the transaction is office of the same history entry as the unabridged action. If the user hits the back button from the list, it backs the user out of the app.
Now, build and run and yous should see details about each breed when you tap on them:
With that you're done! You now have an app El Dogo that displays details well-nigh the dogs breeds.
Where To Go From Here?
You can find the Final Projection for this tutorial by clicking the Download Materials button at the top or bottom of this tutorial.
There is a lot more to learn and exercise with fragments. Like whatever kind of tool or characteristic, consider whether fragments fit your app'southward needs and, if they practice, endeavor to follow best practices and conventions.
To accept your skills to the next level, here are some boosted things to explore:
- Utilize fragments inside a
ViewPager
. Many apps, including the Play Store, apply a swipeable, tabbed content structure viaViewPagers
. You can learn more in our ViewPager tutorial - Use a more powerful, advantageous
DialogFragment
instead of a plain vanilla dialog orAlertDialog
. - Play with how fragments interact with other parts of an Action, similar the app bar.
- Create adaptive UIs with fragments. In fact, you should run through Adaptive UI in Android Tutorial.
- Employ fragments as part of the implementation of a high-level behavioral architecture. You tin can take a look at Common Blueprint Patterns for Android as a skilful starting betoken to go the architecture ball rolling.
- To learn more than about Data Binding check this reference.
.
We hope that you've enjoyed this tutorial. If you lot have any questions or comments, please join the forum word below!
Source: https://www.raywenderlich.com/1364094-android-fragments-tutorial-an-introduction-with-kotlin
0 Response to "Fragment Will Animate Again After App Return Back From Background Android"
Postar um comentário