Categories
All

Stateful vs. stateless widget

Welcome to the widget class

Creating flutter UI can be demanding. But you’re in luck, you have your greatest helper, the Widget class, here to help you!

In the world of flutter UI, everything is a widget. Widget is the primary building block of the Flutter UI. Widget is an immutable description of part of a user interface, which means all their fields must be final. By themselves, widgets have no mutable state.

What are stateless and stateful widgets?

A stateful widget is a widget that has a mutable state associated with it. Associating a mutable state to a widget like this gives the app interactivity and responsiveness. Without stateful widgets, we wouldn’t be able to do something like this in the images below:

Here, we can change the border of the card and replace the text in it with a nice checkmark, pointing out that the card is selected.

On the one hand, stateless widgets don’t have a state associated with them. This means that when a stateless widget is built, it cannot be changed unless we create a whole new instance of that widget. On the other hand, stateful widgets can be rebuilt any number of times, just call setState, and in the body of setState put the code that affects the UI.

Stateless widgets when created look like this:

<code class="language-dart">
 class StatelessExample extends StatelessWidget {
                @override
                Widget build(BuildContext context) {
                               return Text("This is a stateless widget");
                }
 } 
</code>

… While stateful widgets look like this:

<code class="language-dart">
 class StatefulExample extends StatefulWidget {
                @override
                State createState() => _StatefulExampleState();
 }
  
 class _StatefulExampleState extends State&#60;StatefulExample&#62; {
                @override
                Widget build(BuildContext context) {
                               return Text("This is a stateful widget");
                }
 }
</code>

For example, if we wanted to implement the Selected functionality shown in the images above, we would need to have a variable in our stateful widget, _isSelected.

All that is left is for us to call setState in the onPressed method of the widget surrounding the card body (in this example, the surrounding widget is InkWell, but it can be done with GestureDetector):

<code class="language-dart">
 onPressed: () {
                setState((){
                               _isSelected= true;           
                });
 }
</code>

The other option is to do something in the lines of this:

<code class="language-dart">
 onPressed: () {
                _isSelected = true;          
                setState((){
                });
 }
</code>

I have to mention that the first way is better because it tells you exactly what’s going on and what you are changing when calling the rebuild method, setState. With that in mind, it should be used only to wrap the actual changes to the state, not any computation that might be associated with the change.

Flutter UI hierarchy and setState

Flutter’s UI hierarchy is based on a widget tree. Every time we create a new instance of a widget, it is added to the widget tree as a child of the widget from which it was instantiated. Because of this, calling setState can sometimes be really costly. When we call setState, it does call the build method of the widget, but it rebuilds the whole subtree beneath that widget. In other words, it calls the build method of all of its children, too. If the subtree beneath it is deep, that setState can end up being costly. That is why it’s good practice to always keep the whole widget tree relatively shallow, so you don’t have to worry about costly rebuilds.

To sum things up…

… If the main idea you got out of this article is that stateless widgets are used to create UI that does not depend on the input of the user and that stateful widgets are used for creating dynamic UI, you can give yourself a pat on the back! You did well and made the first step to understanding how flutter works!

Categories
Android

How to update fragments in the ViewPager?

Five indubitably easy steps

The problem described in the title below is found to be a very common problem Android developers face. As being so, I decided that is the problem I want to dedicate my first blog post to. In this quick read, I will show and explain to you a very simple solution.

When I was first encountered with this implementation, I failed to find much regarding it while searching the internet. What was offered in response either sounded like a very poor implementation or was quite complicated to deal with.

At that time I was on a project where I had to use EventBus library, and it proved to be a very good solution, with not so demanding implementation. That is why I decided to approach the solution in this way.

A sample project for this tutorial can be found on Github repository: https://github.com/Crystal-Pigeon/photo-manipulation.

To start the implementation, we need to add the following line of code to the build.gradle file:
<code class="language-kotlin">
implementation 'org.greenrobot:eventbus:3.2.0'
</code>

We start from the fact that we have one activity, in my case that was MainActivity. It contains a ViewPager with 3 tabs, which means that we have 3 fragments and a field for entering a query, which is going to be used for the search of the data from the aforementioned fragments. To display the data each of the fragments contains a RecyclerView.

Then we need to create an event that will be observed. We create a SearchEvent class that includes the following:
<code class="language-kotlin">
class SearchEvent(var query: String, var pageTitle: CharSequence?)
</code>
The next step is to create a Publisher that will broadcast the event itself.

In this case, the event is broadcasted every time something is entered in the search field. First, we create an object of class SearchEvent and broadcast the event to which we forward the created object.

<code class="language-kotlin">
et_search.doAfterTextChanged {
      val searchEvent = SearchEvent(
            et_search.text.toString(),
            searchViewPagerAdapter.getPageTitle(vp_search.currentItem)
      )
      EventBus.getDefault().post(searchEvent) //publish the event
}
</code>
Moving forward, it is necessary to register the Bus in fragments.

We will do this by overriding the onStart and onStop methods as follows:

<code class="language-kotlin">
override fun onStart() {
    super.onStart()
    if(!EventBus.getDefault().isRegistered(this)) {
        EventBus.getDefault().register(this)
    }
}

override fun onStop() {
    super.onStop()
    EventBus.getDefault().unregister(this)
}
</code>
In addition to this, it is necessary to create a Subscriber.

Specifically, we have to create a method that needs to be annotated with Subscribe, which, as a parameter takes in an object of the SearchEvent class, that we previously created. This method is executed after the broadcast of each event.

<code class="language-kotlin">
@Subscribe(threadMode = ThreadMode.MAIN)
fun onSearchEvent(searchEvent: SearchEvent) {
    // add here what needs to happen, for example display data on the screen
}
</code>

I hope you found this solution-based summary useful, and good luck with the forthcoming work.