Saturday, October 5, 2024

StateFlow and SharedFlow seem similar, but they are designed for different use cases

 



StateFlow and SharedFlow seem similar, but they are designed for different use cases, and they should not be confused. Let's discuss the key differences and usages.


Let's start with how they work. SharedFlow resembles a broadcast channel—emitted values are delivered to all observers. It allows setting a replay parameter specifying how many past values should be emitted to new observers.

StateFlow behaves a lot like SharedFlow with reply = 1, but StateFlow must always have a value, so an initial value must be specified when a StateFlow is created. This value can be accessed or changed using value property.

But StateFlow was designed for a concrete use case: to represent an observable state. In Android, it is used to represent the state of our application, and views observe it and redraw whenever it changes. That is the key source of differences.

Redrawing view can be expensive, and state changes can be frequent. That is why two optimizations were introduced. First, updates are only emitted when they are different from the previous state. This behavior can be achieved on SharedFlow using distinctUntilChanged.

Second, StateFlow is conflated, meaning if observer is slower than value changes, it might lose some intermediate updates. That is appropriate for StateFlow, because we are not interested in drawing obsolete state.

StateFlow also have some tools for state update, like update function, that lets us safely update state, by creating a new one based on the current one.

That is why StateFlow should be used concretely to represent the observable state of our application. It should not be used as a "breadcast channel". For that we use SharedFlow.

Let's see an Android example: Things like a progress bar or data to display should be represented by StateFlow, but exceptions or messages to show to users as toasts should be represented as SharedFlow.

However, SharedFlow values are not completely safe to be used in view models, because updates made when there is no observer will not be observed (unless we use reply, but then the same values can be displayed again). So it is best to represent our state with StateFlow.

Now let's see a backend example. On a backend service, updates received from some websocket should be represented using SharedFlow, but an observable counter of application users can be represented using StateFlow.

To sum up, StateFlow and SharedFlow are similar, but they are designed for different use cases. StateFlow is for representing observable state, and SharedFlow is for broadcasting events. Use them accordingly.
Credits 
https://www.linkedin.com/posts/marcin-moskala_stateflow-and-sharedflow-seem-similar-but-activity-7244273218692202496-yej-?utm_source=share&utm_medium=member_desktop

Saturday, April 1, 2017

MVP : Event Bus pattern instead of Listener

This question more towards paradigm. Why is that we don't use Event Bus instead of listeners in an MVP environment ? Typically, the "P" part has dependency injection of view and model references. Sure this has an advantage of showing explicit contract between the view and model via presenter, which is more readable.
However, wouldn't it be a cleaner approach to have presenter listen to events from views and events carry the view payload (eg: json representation). Same is the case with presenter talking back to the view. View will listen for events from presenter. Major advantage is, we don't have to write interfaces for each contract between view and presenter. If you look at the code you will see that presenter is getting exposed to view details like Text Fields, which i believe is increasing coupling between view and presenter. Say, if i'm replacing front end JavaFx instead of Vaadin, i will have to alter presenter as well.
This class is an example from a live project. Here we have different types of events ie i don't create event class for different cases. Eg: LoginViewEvent , DashBoardEvent etc which i believe is a maintenance pain.
public class UrayEvent {

    public static enum EventType {

        SESSION_SELECTED(1),
        DOCUMENT_SELECTED(2),
        DOCUMENT_EDIT_COMPLETE(3),
        DOCUMENT_EDIT_CANCELED(4),
        SHOW_SESSION_TABLES(5),
        SHOW_SESSION_DOCUMENTS(6),
        SHOW_SESSION_COLLABORATORS(7),
        USER_REQUESTED_REFRESH(8),
        AUTO_REFRESH(9),
        TABLE_SELECTED(10),
        DETACHED(11),
        SCHEDULER_NAVIGATION(12),
        JIRA_USER_SELECTED(13),
        DOCUMENT_SAVE_SUCCESS(14),
        DOCUMENT_SAVE_FAILURE(14);

        private final int value;

        private EventType(int value) {

            this.value = value;
        }

        public int getValue() {

            return value;
        }
    }

    public static class Event {

        private final EventType type;
        private final Object payload;

        public Event(EventType type, Object eventPayload) {

            this.type = type;
            this.payload = eventPayload;
        }

        public EventType getEventType() {

            return type;
        }

        public Object getEventPayload() {

            return payload;
        }
    }

}
Simple enough, the view send the event  DOCUMENT_EDIT_COMPLETE .The presenter layer handles this event. I found this way, a better way to decouple views from presenter.
    @Subscribe
    public void handle(UrayEvent.Event event) {

        switch (event.getEventType()) {
            case DOCUMENT_EDIT_COMPLETE:
                  // event payload contains document model data
                  // like document id etc
                 saveDocument(event.getEventPayload);    
                break;
            default:
                break;
        }
    }
Advantage
  • Less boiler plate code, 
  • For n-views we don't need n-interfaces
  • New event means adding event element to enum and updating respective subscribe methods handling this event.
Disadvantage
  • Memory leak if we forget to unregister  from eventbus (faced it plenty of time)
Questions
1) This approach means, there would larger set enum elements as the application grow. Is this approach an anti pattern ?
2) As we saw it uses Event Bus extensively are there any drawbacks of using bus system instead of interface-listener pattern ?
Wanted your valuable suggestion on this regard. The main issue is, if i blindly apply this pattern extensively across the project i shouldn't regret doing so, what would be a possible pitfall in this approach.

Thursday, March 23, 2017

Android Internals : just what application developers needs to know

It is always good (not a must) to know the internals of a software platform, to be an efficient developer. After having exposed to the internals, many facts will make more sense to during the development, further you will get the clear picture of how each components connect and interact with each other.

Its been a while since the inception of the Android Mobile platform. Since then, there has been higher demand for android developers, not to mention how it made easy for existing Java developers to migrate. Statistics show, most mobile and embedded devices will default to Android soon or later.Learning this platform would be worth the time spend. 

This article, will explain only necessary internal details just enough for user-space developer. Once complete we will have a clear picture of entire android stack starting from the source tree organisation, architecture component interaction, start up sequence, to how an application is launched.

1. Architecture

  

Fig 1 Conceptual Architecture 
1.1 Kernel 

A the bottom most level, the host operating system, is the Linux kernel.
Theoretically it could be any host kernel, practically, however it is a difficult task to achieve. Though, Linux kernel is being used, there were many kernel specific patches those were added to support various user level android policies and drivers. 

Kernel patches (Details are skipped)
  • Wake Locks
  • Binder
  • Klogger                            
  • Anonymous Share Memory
  • Alarm Timers
  • Low Memory Killer
  • Network Security policy   
Other than the patches above, one has to keep in mind, the device manufactures do add custom patches to support their hardware, what is mentioned above are core kernel patches for a android system to work. 

Source Tree : kernel

1.2 Android Runtime 

Consist of the Dalvik virtual machine, which is just like JVM on tbe desktop, that executes the android applications we run, Java runtime, that comes from the Apache Harmony project, system daemons, the init binary  and various supporting binaries. Dalvik virtual machine executes dex files instead of class files. dex files are generated by post processing class files with dx utility.   

Oracle Java    = Java Language    + class file + JVM    + JRE libs
Android Java = Java Language    + dex file   + DVM  + Apache Harmony Project 

Most of the java.* , org.w3c.* junit.* org.json.* in the android API comes from here, including the sql jdbc driver

Source Tree: libcore ,  dalvik , system 

1.3 Libraries 

This is where, the 3rd party native libraries (C/C++) are hosted, they act as a support layer for low level access from the java libraries, it consist of google developed C library called Bionic, it is stripped down library from BSD standard C library. Bionic isn't compliance with POSIX, so native (non java) application and library porting from POSIX system is a hurdle. Though only few libraries have been mentioned in the diagram, it consist of more, starting from libusb to webRTC, kindly see the source tree

The Application frame work access these libraries via JNI , one such example to site would be sqlite, we will see a source relation, check the links
   

So, in nutshell, these libraries are accessed by the application frame work via JNI.  

Source Tree:  external

1.4 Application Framework 

Ah, finally we are at the top, the android.* APIs you see in the Android API reference sprouts from here, this is what we mostly use while developing an android applications. Framework don't just consist of developer apis, but, various services and interfaces to communicate with them. Services are not directly accessible via framework , however, via kernel supported mechanism called Binder. In short andorid.*  APIs connected to service / system server via binder.  

Source Tree: framework

1.5 Applications 

There is were we have all the fun, we use the SDKs to access these framework APIs to develop the applications. Most of the application developers play here. There are other species of developers who hack the frameworks , android services and even the kernel subsystem to build custom roms, one such community is the CyanaogenMOD, we should say they are the first class android developers and us to be economy developers. ;-). Most android devices have set of default applications like dialers, mms, browsers you can find its source tree over here.

2. Android Hardware Abstraction Layer 

Kernel does provide HAL , however Google engineers felt it wasn't enough, one reason could be GPL license that the kernel has. So, in order to make device manufacturers implement non GPLed drivers in the user space, this may be a favorable choice. 

Libhardware provides interface for various devices and sensors, the device manufacturers can develop drivers in closed source environment, complying to these interfaces. Few of the interfaces are listed here. 
  • Audio (libaudio.so)                
  • Graphics (gralloc.so, copybit.so, libhgl.so)                
  • Camera (libcamera.so)          
  • GPS (libgps.so)                   
  • Sensors (libsensors.so)       
  • Radio Interface (libril-vendor-version.so)  
All that the manufacturer has to do is to put their library into /system/libs/hw

Case Study : If you like to know how RIL is used for receiving calls, sending sms, receving sms etc take a look into this answer.

3. Android File System 

Android though is Linux based doesn't strictly abide to the FHS , instead has a custom hierarchy

/system                    Immutable directory coming from the original build.
                                It contains native binaries and libraries, framework jar files, 
                                configuration files, standard apps, etc.
/system/app             All the pre-installed apps
/system/bin              Binaries installed on the system (toolbox, vold, surfaceflinger)
/system/etc               Configuration files
/system/fonts            Fonts installed on the system
/system/framework  Jar fi les for the framework
/system/lib               Shared objects for the system libraries
/system/modules      Kernel modules
/system/xbin            External binaries
/data                        changing content of the system are put: 
                                apps, data added by the user, data generated by all the apps at runtime, etc. 

/etc                         Symbolic link to /system/etc
/dev                       Mount point for tmpfs filesystem
/proc                      Mount point for procfs filesystem which provide access to kernel data structures 
/sbin                       Contains various daemons
/root                       As usual the root home directory
/mnt                       Mount point for external and internal filesystems 
                              and some security related filessytem

/sys                        Mount point for sysfs filesystem which has information on 
                              kernel's device objects
/sdcard                   Symbolic link to /mnt/sdcard
/cache                    Used by application to save data temporarily like Google Play Store download etc 
/d                           Symbolic link to /sys/kernel/debug  
/acct                      Mount point for the acct cgroup (control group), 
                              which provides for user accounting.
/vendor                  Symbolic link to /system/vendor 

4. Source Code Organisation Overview

bionic/            is where Android's standard C library is stored
bootable/        contains code samples regarding the boot of an Android device. In this folder, 
                       you will find the protocol used by all Android bootloaders and a recovery image
build/              holds the core components of the build system
cts/                 The Compatibility Test Suite
dalvik/            contains the source code of the Dalvik virtual machine
development/ holds the development tools, debug applications, API samples, etc
device/            contains the device-speci c components
external/         is one of the largest folders in the source code, it contains all the external 
                       projects used in the Android code
frameworks/   holds the source code of the various parts of the framework
hardware/       contains all the hardware abstraction layers
libcore/           is the Java core library
ndk/                is the place where you will nd the Native Development Kit, which allows to build native
                       applications for Android
packages/        contains the standard Android applications
prebuilt/          holds all the prebuilt binaries, most notably the toolchains
sdk/                is where you will nd the Software Development Kit
system/           contains all the basic pieces of the Android system: init, shell, the volume manager, etc.

5. System Startup

Fig 2. start up sequence 

Start up sequence till init is quite straight forward, this is similar usual x86 boot process, finally calling Init , however Android system differs starting from the init sequence. The init itself was written from scratch and not same as the one seen on Linux distribution.

Once the kernel start /init process, it reads the file name /init.rc and /init.(machine-name).rc , these rc script, first of all sets the environment variables,  mounts various file system to its respective mount points, starts various daemons like rild (radio interface layer daemon), adb , vold, netd etc. Init become mother of all the process created subsequently. The next core job of init is to start up the Zygote, which is the mother of all the android applications

Lets take a deeper view into Zygote start up,


Init runs the /system/bin/app_process and name it zygote
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

The entry above from ./init.rc that start the app_process to startup the zygote.

As seen in the source line 188 of app_main.cpp



188    if (zygote) {
189        runtime.start("com.android.internal.os.ZygoteInit",
190                startSystemServer ? "start-system-server" : "");
191    }


It start up the java implementation of Zygote , and 'start-system-server' flag is passed as the parameter. This is exactly what we had passed in the entry from the init.rc. The line 189 does many other tasks under the hood, the runtine.start() at line 839 start up up the Dalvik virtual machine, see line 443 of AndroidRuntime.cpp for more information.Ahead of zygote invocation, Dalvik runtime was setup and Dalvik virtual machine was initialized. ZygoteInit::main() get called at line 888 of AndroidRuntime.cpp , which start up the System Server this can be seen at line 544 of ZygoteInit.java, finally it runs runSelectLoopMode() and waits for future request to fork() new zygote instances which specialize into the android application.The System server is started in a two sequence process , first a libary is called to initialize the native services, which can be seen at line 1064 of SystemServer.java , then java based core services are run by ServerThread::run() which is seen at like 1067 of SystemServer.java. Check the source to find out the sequence of the services started, core services line the PowerManager, ActivityManager, Sensor Service etc and other non critical services are started this way. The main being the AcitivityManager, which handles the our Andorid Application.

 

501            /* Request to fork the system server process */
502            pid = Zygote.forkSystemServer(
503                    parsedArgs.uid, parsedArgs.gid,
504                    parsedArgs.gids,
505                    parsedArgs.debugFlags,
506                    null,
507                    parsedArgs.permittedCapabilities,
508                    parsedArgs.effectiveCapabilities);
509        } catch (IllegalArgumentException ex) {
510            throw new RuntimeException(ex);
511        }
512

544            if (argv[1].equals("start-system-server")) {
545                startSystemServer();
546            } else if (!argv[1].equals("")) {
547                throw new RuntimeException(argv[0] + USAGE_STRING);
548            }
Code Snippet Showing How System Server is started

Conclusion



Ah finally we have reached the end,  though this was quick introduction into the android internals, it is my humble opinion that , information above would be sufficient enough to get you started with griping the Android APIs. This introduction will hopefully help you understand the relations and component interaction, which would make android application programming more exiting. Where go from here ? Now you can start reading Application Fundamentals from the android main resource, trust me, many things will make more sense now.

Reference