Skip to content

Latest commit

 

History

History
948 lines (655 loc) · 36.6 KB

README.md

File metadata and controls

948 lines (655 loc) · 36.6 KB

Android Interview Essentials

Language Basics, Architecture In-depth, Android Vitals, Performance, Memory Optimizations and More



Native Android Interview Basics

Contents

1 2 3 4 5 6
Android Basics Android Specifics: Native Android Specifics: Cross-Platform Android Intermediate Android Advanced Resources & Learning Guides

Android Basics

What are the core 4 app components? What elements/tags do we use to declare them in the Manifest file?

There are four different types of app components:

  • Activities
  • Services
  • Broadcast receivers
  • Content providers

To declare all app components, we use the following elements:

  • <activity> elements for activities.
  • <service> elements for services.
  • <receiver> elements for broadcast receivers.
  • <provider>elements for content providers.
What's Context? Context is the Interface to global information about an application environment
What's an Activity? An Activity is an application component that provides a screen, with which users can interact in order to do something
What's a Fragment? What's its relationship with Activity? A Fragment represents a behavior or a portion of user interface in an Activity. A fragment has to live inside the activity. Fragments do not need to be declared in the manifest.
What's the use of Fragment? Fragments are used for its re-usability. For multi-pane layouts you have to use fragment that you can't achieve with activity. Use fragment only when you’re working with UI components or behavior that you’re going to use across multiple activities
What's a Service? A service is a component that runs in the background to perform long-running operations without needing to interact with the user and it works even if application is destroyed
What's an Intent? How many types of intent are in Android? Briefly explain their respective use cases.

An Intent is a messaging object you can use to request an action from another app component.

Use Cases: Starting an Activity or a Service, Delivering a broadcast.

  • Explicit intents are used to start components in your own application. Use Case: You might start a new activity within your app in response to a user action, or start a service to download a file in the background.
  • Implicit intents are most commonly used to communicate with components from other third party applications. Use Case: If you want to show the user a location on a map, you can use an implicit intent to request that another capable app show a specified location on a map.
What's a PendingIntent? How many types of intent are in Android? Briefly explain their respective use cases.

A PendingIntent object is a wrapper around an Intent object. The primary purpose of a PendingIntent is to grant permission to a foreign application to use the contained Intent as if it were executed from your app's own process.

Use Cases:

  • Notification: Android system's NotificationManager executes the Intent
  • App Widget: Home screen app executes the Intent
  • A specified future time: Android system's AlarmManager executes the Intent
What is the functionality of Intent filters? Point out a frequently-used scenario.

This element is used in the Manifest file to declare the capabilities of an app component (i.e. an Activity)

Use Case: When we declare an Activity in the Manifest, we can include intent filters so it can respond to intents from other applications like the following:

<manifest>
    ...
    <application>
        <activity android:name="com.example.SendEmailActivity">
            <intent-filter>
                <action android:name="android.intent.action.SEND" />
                <data android:type="*/*" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
</manifest>
What are the core components of RecyclerView?
  • RecyclerView.Adapter
  • RecyclerView.ViewHolder
  • RecyclerView.LayoutManager
  • RecyclerView.ItemAnimator
What are the functionalities/use cases of using Guideline & Barries in a ConstraintLayout?

Link to the resources with graphical explanation:

Which method is called only once in a fragment life cycle? onAttached()

Android Specifics: Native

Android Specifics: Kotlin

How many visibility modifiers are there in kotlin? Explain their scope

There are 4 visibility modifiers in Kotlin:

  • Public: Visible everywhere
  • Protected: Not available for top-level declarations
  • Internal: Visible everywhere in the same module (a module is a set of Kotlin files compiled together: IntelliJ IDEA, Gradle source set etc)
  • Private: Only visible inside the file containing the declaration
class EventViewModel internal constructor()

In the previous code snippet, internal makes class available to public, but constructor only to inside module

What are Companion Objects?

If you need a function or a property to be tied to a class rather than to instances of it, you can declare it inside a companion object. If you declare a companion object inside your class, you'll be able to call its members with the same syntax as calling static methods in Java/C#, using only the class name as a qualifier. It is similar to static keyword in Java or @staticmethod in Python.

companion object {
@Volatile private var instance: EventRepository? = null

fun getInstance(eventDao:EventDao) =
  instance ?: synchronized(this) {
      instance ?: EventRepository(eventDao).also { instance = it }
  }
}
Give the output of the following code with nullable variables
var a: String = "abc"
a = null 
var b: String? = "abc"
b = null 
print(b)
  • a =null will produce a compilation error
  • b = null will not produce any error
What's a Safe call operator?
val a = "Kotlin"
val b: String? = null
println(b?.length) //prints null
println(a?.length) //prints 6
Explain !! VS ? in the following cases

A quick Overview of some possible cases:

1 2 3 4
a: String? a.length a?.length a!!.length
"cat" Compile time error 3 3
null Compile time error null NullPointerException

!! is an option for NPE-lovers. a!!.length will return a non-null value of a.length or throw a NullPointerException if a is null. And a?.length returns a.length if a is not null, and null otherwise:

val a: String? = null
print(a!!.length) // >>> NPE: trying to get length of null
val a: String? = null
print(a?.length) // >>> null is printed in the console
What's the ternary operator (condition ? expression1 : expression2;) of Java alternative in Kotlin? Unlike Java, there is no ternary operator in kotlin. You need to use if-else instead.
What's an Elvis Operator? Why is it a Smarter Type-Safe If
val list = mutableList ?: mutableListOf() 

is a shorter form of

val list = if (mutableList != null) mutableList else mutableListOf()

The name,howver, comes from the famous American singer Elvis Presley. His hairstyle resembles a Question Mark Ref

alt text

Given the 2 code snippets, choose which one is more preferred.

1st Code Snippet:

return if (x) foo() else bar()
return when(x) {
    0 -> "zero"
    else -> "nonzero"
}

2nd Code Snippet:

if (x)
    return foo()
else
    return bar()

when(x) {
    0 -> return "zero"
    else -> return "nonzero"
}

The above is preferable to the latter one.

What does the keyword/block init do?

Out Initialization code can be placed in initializer blocks, which are prefixed with the init keyword:

class InitOrderDemo(name: String) {
    val firstProperty = "First property: $name".also(::println)  //inits a val & also, prints the name

    init {
	println("First initializer block that prints ${name}")
	println("Second initializer block that prints ${name.length}")
    }
}
How to call a High Order Functions in Kotlin?
fun main() {
//both of the ways are correct!
    test( { println(it) } ) 
    test(::println)
}

fun test(block: (String) -> Unit ) {
    block("okay")
}
What does @Volatile mean?

@Volatile before a field means that writes to this field are immediately made visible to other threads.

Why do we need to use @Suppress("UNCHECKED_CAST")?

In Kotlin, there's no way to check the generic parameters at runtime in general case (like just checking the items of a List<T> or here in this ViewModelFactory, modelClass: Class<T> which is only a special case), so casting a generic type to another with different generic parameters will raise a warning, which needs to be suppressed

@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>) = EventViewModel(eventRepository, lifecycleOwner) as T
How to use Bitwise Operator in Kotlin?
val andResult  = a and b
val orResult   = a or b
val xorResult  = a xor b
val rightShift = a shr 2
val leftShift  = a shl 2
What's reified keyword in Kotlin?

Generic parameters are a great way to provide type safety, but can be limiting when accessing class info type. The reified keyword allows get type of generic variable in inline function.

inline fun <reified T> printType() {
	print(T::class.java)
}

fun printStringType() {
        //calling with String type  
	printType<String>()
}

Some rules to follow:

  • Reified can be used only with inline functions
  • Reified functions can not be accessed from Java, because Java doesn't support inlining

More on Reified and Inline functions on Kotlin Vocabulary

What are the differences among flatMap(), map() and flatten() in Kotlin? Explain with code example.
  • flatMap() merges two collections into a single one
  • map() results in a list of lists
  • flatten() produces the same result as flatMap(). So flatMap() is a combination of the two functions: map() and then flatten()

The following code example with commented output illustrates their use cases:

class Data(val items : List<String>)

val dataObjects = listOf(
    Data(listOf("a", "b", "c")), 
    Data(listOf("1", "2", "3"))
)

val items: List<String> = dataObjects.flatMap { it.items } //[a, b, c, 1, 2, 3]
val items2: List<List<String>> = dataObjects.map { it.items } //[[a, b, c], [1, 2, 3]] 

val nestedCollections: List<Int> = listOf(listOf(1,2,3), listOf(5,4,3)).flatten() //[1, 2, 3, 5, 4, 3]

Android Specifics: Java

What's the access modifier of a method that no child class can extend/access/override?

final

What's the instantiation and initialization of an object?
  • Initialization: is the process of the memory allocation, when a new variable is created.
  • Instantiation: is the process of explicitly assigning definitive value to a declared variable.
Are static local variables allowed in Java?

No. In Java, a static variable is a class variable (for whole class). So if we have static local variable (a variable with scope limited to function), it violates the purpose of static. Hence compiler does not allow static local variable. So the following code throws a Error: Static local variables are not allowed:

class Test { 
   public static void main(String args[]) {  
     System.out.println(fun()); 
   } 
  
   static int fun() 
   { 
     static int x= 10;  //throws an error here
     return x--; 
   } 
}  
Can we access a non-static variable from a static method in Java? No. The concept of static is not associated with any instance. And non-static variable are associated with a specific instance of an object.
Can a static method be overridden in Java? No. Method overriding is based on dynamic binding at runtime and the static methods are bonded using static binding at compile time. We can declare static methods with the same signature in the subclass, but it is not considered overriding as there won't be any run-time polymorphism.
How to make a member variable not to be serialized inside a Serialized object?

Using Java keyword transient. This keyword, when applied to a field, tells the Java object serialization subsystem to exclude the field when serializing an instance of the class

What's the Parent class of Error & Exception? Throwable
What is a Generic in Java? Generics is parameterized types (Integer, String, … etc, and user-defined types) to methods, classes, and interfaces. Generics is used to create classes that work with different data types as such:
class Test<T> 
{ 
    T obj; 
    Test(T obj) {  this.obj = obj;  } 
    public T getObject()  { return this.obj; } 
} 

class Main 
{ 
    public static void main (String[] args) 
    { 
        Test <Integer> iObj = new Test<Integer>(15); 
        System.out.println(iObj.getObject()); 
	
        Test <String> sObj = new Test<String>("GeeksForGeeks"); 
        System.out.println(sObj.getObject()); 
    }
}
What is the difference between == and .equals()?
  • The equals() method compares two strings, character by character, to determine equality
  • The == operator checks to see whether two object references refer to the same instance of an object
Are String objects mutable? If so, why is that? Explain shortly. No. String objects are immutable. In the String constant pool, a String object is likely to have one or many references. If several references point to same String without even knowing it, it would be bad if one of the references modified that String value. That's why String objects are immutable.
When to use StringBuffer and when to StringBuilder?

StringBuffer and StringBuilder are classes used for String manipulation. These are mutable objects, which provide methods such as substring(), insert(), append(), delete() for String manipulation. They are similar, but StringBuilder is faster and preferred over StringBuffer for single threaded program. However, StringBuilder operations are not thread-safe are not-synchronized. So StringBuffer is preferred over StringBuilder when thread safety is required.

How many types of polymorphism is there in Java?

There are two types of polymorphism in Java:

  • Compile-time polymorphism: Compiler itself determines which method should call. Method overloading is an example of static/compile-time polymorphism.
  • Runtime polymorphism: Compiler cannot determine the method at compile time. Method overriding is an example of dynamic/run-time polymorphism
Which class is widely used to implement thread safe counters in Java?

AtomicInteger

Android Specifics: Cross-Platform

Android Specifics: Flutter

What is the difference between StatelessWidget and StatefulWidget?

If a widget can change when a user interacts with it, it’s stateful. If it can't, it's stateless.

  • StatelessWidget is an immutable class that acts as a blueprint for some part of the UI layout. You use it when the widget doesn’t change while displaying and, therefore, has no State
  • StatefulWidget is also immutable, but it’s coupled with a State object that allows you to rebuild the widget with new values whenever calling setState(). Use StatefulWidget whenever the UI can change dynamically
Give some frequently used Stateless and Stateful widgets
  • Stateless: Icon, IconButton, and Text
  • Stateful: Checkbox, Radio, Slider, InkWell, Form, and TextField
Explain the difference between hot reload and hot restart briefly
  • Hot reload maintains the app state while updating the UI almost instantaneously
  • Hot restart resets the app state to its initial conditions before updating the UI

Hot Restart takes a bit longer than Hot Reload, in comparison

What is BuildContext and how is it useful?

BuildContext is the widget's element in the Element tree. Every widget has its own BuildContext. It's used to get a reference to the theme or to another widget.

How to decrease/optimize the iterations of rebuilding stateful widgets?
  • Creating dedicated smaller widgets that updates states instead of handling states on larger widgets
  • Factoring out only the stateful part of a widget and passing a child argument to it
  • Using const widgets to cache and reuse
  • Avoiding frequent changes of the depth of the subtree since it requires rebuilding

More technique on official doc on Perfomance Considerations on Flutter

Name some of the steps of StatefulWidget lifecycle.
  • createState()
  • mounted == true
  • initState()
  • didChangeDependencies()
  • build()
  • didUpdateWidget()
  • setState()
  • deactivate()
  • dispose()
  • mounted == false

More in-depth analysis of every step on the following aticle

Android Intermediate

General Concepts

We know that when one activity starts another, they both experience lifecycle transitions. Briefly explain the order of operations that occur when Activity A starts Activity B.
  • Activity A's onPause() method executes.
  • Activity B's onCreate(), onStart(), and onResume() methods execute in sequence. (Activity B now has user focus.)
  • Then, if Activity A is no longer visible on screen, its onStop() method executes.
What type of stack does Android use for managing tasks?

Android manages tasks and the back stack, by placing all activities started in succession in the same task and in a Last In First Out (LIFO) stack

What are the 3 principal intent flags for managing tasks in Activity Back Stack?
  • FLAG_ACTIVITY_NEW_TASK
  • FLAG_ACTIVITY_CLEAR_TOP
  • FLAG_ACTIVITY_SINGLE_TOP

More explanation

On Android 10 or higher, how can an app start activities?

By displaying notifications. But there are some exceptions and apps running on Android 10 or higher can start activities only when one or more of these conditions are met.

How to retrieve NavController in Java and Kotlin?

You can retrieve a NavController by using one of the following methods:

  • Kotlin:
Fragment.findNavController()
View.findNavController()
Activity.findNavController(viewId: Int)
  • Java:
NavHostFragment.findNavController(Fragment)
Navigation.findNavController(Activity, @IdRes int viewId)
Navigation.findNavController(View)
What are the major components of Room?

3 major components in Room:

  • Database
  • Entity
  • DAO
What's Scoped Storage in Android 10?

Apps that use scoped storage have access only to their app directory on external storage plus any media the app created. More details on this article.

What's the improved data storage solution aimed at replacing SharedPreferences? Jetpack DataStore
When to use MutableLiveData & when to use LiveData? Explain a scenario. When you don't want your data to be modified use LiveData If you want to modify your data later use MutableLiveData. A scenario of fetching data from an API needs a MutableLiveData where there are changes in data. This fetched data then can be stored in a LiveData if there's no requirement to change it afterwards & just use cases of using it for the view purposes.
When do we need a Parcelables and when a Bundle? Explain a scenario. Parcelables and Bundles are usually used to transfer data between activities. To transfer primitive data types we use Bundle and for complex object types we use Parcelable. In a scenario of sending a String from one activity to another a Bundle object can be used. But in case of sending an ArrayList, Bundle can not be used. In this case we need to use Parcelable.
What are sealed classes in Kotlin? Explain a possible use case in any of the RecylcerView components for Android.

Sealed classes are used for representing restricted class hierarchies, when a value can have one of the types from a limited set, but cannot have any other type.

They are, in a sense, an extension of enum classes: the set of values for an enum type is also restricted, but each enum constant exists only as a single instance, whereas a subclass of a sealed class can have multiple instances which can contain state.

A use case can be when to display a list of a specific type of object in a RecyclerView, where each object has its own ViewHolder.

sealed class Fruit {
    class Apple : Fruit()
    class Orange : Fruit()
}

class FruitAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    private val fruits = arrayListOf<Fruit>()
    override fun getItemCount() = fruits.size
        
    override fun getItemViewType(position: Int): Int {
        return when (fruits[position]) {
            is Fruit.Apple -> R.layout.item_apple
            is Fruit.Orange -> R.layout.item_orange
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
        return when (viewType) {
            R.layout.item_apple -> {
                val itemView = layoutInflater.inflate(R.layout.item_apple, parent, false)
                AppleViewHolder(itemView)
            }
            R.layout.item_orange -> {
                val itemView = layoutInflater.inflate(R.layout.item_orange, parent, false)
                OrangeViewHolder(itemView)
            }
            else -> throw UnknownViewTypeException("Unknown view type $viewType")
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
            val fruit = fruits[position]
            when (fruit) {
                is Fruit.Apple -> (holder as AppleViewHolder).bind(fruit)
                is Fruit.Orange -> (holder as OrangeViewHolder).bind(fruit)
            }
    }
}

Common App Architectures

What's the relation between using ViewModel and Memory Leak? While you're rotating the screen orientation or perform any changes in configruation, data may be lost (i.e. while filling up a google form activity & changing the rotation on device). ViewModel prevents memory leak, by hodling the data of UI.
What's the use of LiveData? Explain a use case While fetching data from some API, some data can come after the initilization of the activity & its view. LiveData, an observer class, detects & changes the data in the UI if there's any change. LiveData is a data wrapper class, which is observable within a Lifecycle of Activity, Fragment, meaning that the observers are going to be notified only when the Activity or Fragment it’s active. If A is a LiveData instance and B is observing it, anytime A’s data changes, B is notified about this change and gets the latest value of A’s data.
How is MVVM lifecycle aware & decoupled? Lifecycle awareness means that a LiveData will only update observers (such as Activities, fragments or services) which are in an active lifecycle state and thus, avoiding NPE. There is no reference to the View from a ViewModel so the communication between them must happen via a subscription. Hence, ViewModels expose events like openTaskEvent and views subscribe to them

Android Advanced

The last callback in the lifecycle of an activity is onDestroy(). The system calls this method on your activity as the final signal that your activity instance is being completely removed from the system memory. Usually, the system will call onPause() and onStop() before calling onDestroy(). Describe a scenario, though, where onPause() and onStop() would not be invoked. If you detect an error during onCreate() and call finish()
When a LayoutManager asks a RecyclerView to provide a View at position X”, explain briefly the internal processes that take place.
  • Searches changed scrap
  • Searches attached scrap
  • Searches non-removed hidden views
  • Searches the view cache
  • If Adapter has stable ids, searches attached scrap and view cache again for given id
  • Searches the ViewCacheExtension
  • Searches the RecycledViewPool
  • If it fails to find a suitable View in all of the aforementioned places, it creates one by calling adapter’s onCreateViewHolder() method. It then binds the View via onBindViewHolder() if necessary, and finally returns it
Give me a scenario when onCreateViewHolder() & onBindViewHolder() needs to get called in a RecylerView?

If a ViewHolder can not be found in Scrap, or Pool, or View Cache, RecyclerView calls its adapter's onCreateViewHolder() and then binds the created view by calling onCreateViewHolder() method.

Give me a scenario when onCreateViewHolder() & onBindViewHolder() does not get called in a RecylerView?

When a ViewHolder is in the view cache, we hope to to reuse it “as-is”, without rebinding, at the same position as the one it was at before it got into the cache.

Give me a scenario when only onBindViewHolder() gets called in a RecylerView? If a ViewHolder was found in pool, it is bound.
Suppose you have a News App that shows an Image with a text for each news article preview. It has 2 types of views implemented with RecyclerView. One view is a grid gallery of article previews & the other is a down-scroll feed of article previews. In which view may we need to extend RecyclerView's cache capacity?

With the given scenario, it's assumable that users would not scroll up/go back to previously read articles too often. So we may need to extend the capacity of the cache in the latter as the grid needs to be updated more frequently.

What method of a RecylerView do we need to call to detect if a certain View is present/visible on the device screen?

onViewAttachedToWindow() and onViewDetachedFromWindow() callbacks of the RecyclerView's Adapter

What's the difference between the activity lifecycle in a multi-windowed environment where multiple applications are running simultaneously in separate windows?

There's no difference becaused multi-window mode does not change the activity lifecycle.

Given a scenario of multiple apps running simultaneously in a multi-windowed environment, how to detect which of those application is on top of the other in the back stack of tasks?

When apps are running simultaneously in a multi-windowed environment, supported in Android 7.0 (API level 24) and higher, the system manages tasks separately for each window; each window may have multiple tasks. Since it's managed by the System as a per-window basis, 2 applications in 2 windows are not in the same back stack of tasks in any way.

What's the highest amount of data that you can keep as a savedInstanceState?

For the specific case of savedInstanceState, the amount of data should be kept small because the system process needs to hold on to the provided data for as long as the user can ever navigate back to that activity (even if the activity's process is killed). Less than 50k of data in saved state is recommended. Ref

Name some of the types of Observables & Observers in RxJava??

Types of Observables in RxJava:

  • Observable
  • Flowable
  • Single
  • Maybe
  • Completable

Types of Observers in RxJava:

  • Observer
  • SingleObserver
  • MaybeObserver
  • CompletableObserver
What's a Single, Maybe & Completable in RxJava??
  • A Single in RxJava is an Observable which emits only one item if completed or returns error.
  • A Maybe in RxJava is used when the Observable needs to emit a value or a no value or an error.
  • A Completable in RxJava is an Observable which just completes the task and does not emit anything if completed. It returns an error if anything fails. It is similar to reactive concept of runnable.
What's the difference between Observable & Flowbale? What's Backpressure & how is it related to them?

Backpressure is when your observable (publisher) is creating more events than your subscriber can handle. So you can get subscribers missing events, or you can get a huge queue of events which just leads to out of memory eventually.

Flowable takes backpressure into consideration. Observable does not.

What's the difference between Lazy and Lateinit in Kotlin? Explain a use case & a code example where you illustrate what to use when.

Comparison:

  • by lazy {...} delegate can only be used for val properties, whereas lateinit can only be applied to var types
  • lateinit var can be initialized from anywhere the object is seen from, wherease by lazy {...} can only be initialized from its initializer lambda
  • by lazy {...} is thread safe by default, it guarantees that the initializer is invoked at most once, whereas lateinit is not thread safe, the user is responsible for initialize in multi-thread inveronments

Use Cases:

  • If you want your property to be initialized from outside/externally in a way probably unknown beforehand, use lateinit.
  • If you want your property restrict to only using dependencies internal to your object, use by lazy {...}

Code example: A code snippet where lateinit is allowed or not:

lateinit var name: String       //Allowed
lateinit val name: String       //Not Allowed in val
lateinit var name: String?      //Not Allowed if nullable

Here's a resourceful thread on Stack Overflow

Resources and Learning Guides

Android Resources

Language/Framework Basics

UI Components

Best Practices/In-depth

LeetCode Resources