Android Interview Question: Part-1

1. “implements Runnable” vs “extends Thread” in Java which one. is better?

In the Runnable interface approach, only one instance of a class is being created and it has been shared by different threads. So the value of the counter is incremented for each and every thread access.

Whereas, Thread class approach, you must have to create a separate instance for every thread access. Hence different memory is allocated for every class instances and each has a separate counter, the value remains the same, which means no increment will happen because none of the object references is the same.

When to use Runnable?
Use the Runnable interface when you want to access the same resources from the group of threads. Avoid using Thread class here, because multiple objects creation consumes more memory and it becomes a big performance overhead.

A class that implements Runnable is not a thread and just a class. For a Runnable to become a Thread, You need to create an instance of Thread and passing itself in as the target.

In most cases, the Runnable interface should be used if you are only planning to override the run() method and no other Thread methods. This is important because classes should not be subclassed unless the programmer intends on modifying or enhancing the fundamental behavior of the class.

When there is a need to extend a superclass, implementing the Runnable interface is more appropriate than using the Thread class. Because we can extend another class while implementing the Runnable interface to make a thread.

2. What is Serializable and How It’s different from Parcelable

Serializable

Serializable is a standard Java interface. You can just implement Serializable an interface and add override methods. The problem with this approach is that reflection is used and it is a slow process. This method creates a lot of temporary objects and causes quite a bit of garbage collection. However, Serializablean the interface is easier to implement.

Parcelable

Parcelable process is much faster than Serializable. One of the reasons for this is that we are being explicit about the serialization process instead of using reflection to infer it. It also stands to reason that the code has been heavily optimized for this purpose.

Conclusion

  1. Parcelable is faster than Serializable interface
  2. Parcelable the interface takes more time to implement compared to Serializable interface
  3. Serializable the interface is easier to implement
  4. Serializable the interface creates a lot of temporary objects and causes quite a bit of garbage collection
  5. Parcelable the array can be passed via Intent in android.

3. Diff between let & Apply in Kotlin

Kotlin let:

let takes the object it is invoked upon as the parameter and returns the result of the lambda expression.
Kotlin let is a scoping function wherein the variables declared inside the expression cannot be used outside.

An example demonstrating kotlin let function is given below:-

fun main(args: Array<String>) 
{
var str = “Hello World”
str.let { println(“$it!!”) }
println(str)
}
//Prints
//Hello World!!
//Hello World

it keyword contains the copy of the property inside let.

let for null checks

Additionally, let is useful for checking Nullable properties as shown below.

var name : String? = "Kotlin let null check"
name?.let { println(it) } //prints Kotlin let null check
name = null
name?.let { println(it) } //nothing happens

The code inside the let expression is executed only when the property is not null. Thus let saves us from the if-else null checker too!

Kotlin run:

Kotlin run is another interesting function. The following example demonstrates its use cases.

var tutorial = "This is Kotlin Tutorial"
println(tutorial) //This is Kotlin Tutorial
tutorial = run {
val tutorial = "This is run function"
tutorial
}
println(tutorial) //This is run function

Kotlin's run expression can change the outer property. Hence in the above code, we’ve redefined it for the local scope.

  • Similar to the let function, the run function also returns the last statement.
  • Unlike let, the run function doesn’t support the it keyword

let and run

Let’s combine the let and run functions together.

var p : String? = null
p?.let { println("p is $p") } ?: run { println("p was null. Setting default value to: ")
p = "Kotlin"}
println(p)
//Prints
//p was null. Setting default value to:
//Kotlin

Kotlin also:

As the name says, also expressions do some additional processing on the object it was invoked.
Unlike let, it returns the original object instead of any new return data. Hence the return data has always the same type.
Like let, also uses it too

var m = 1 m = m.also { it + 1 }.also { it + 1 } 
println(m) //prints 1

Kotlin let vs also

Following code, snippet shows a great example to differentiate between let and also.

data class Person(var name: String, var tutorial : String)
var person = Person("Anupam", "Kotlin")
var l = person.let { it.tutorial = "Android" }
var al = person.also { it.tutorial = "Android" }

println(l)// Anupam Android
println(al) // Anupam Android
println(person)

In the above code, we’ve used Data classes.

The also expression returns the data class object whereas the let expression returns nothing (Unit) as we didn’t specify anything explicitly.

Kotlin apply

Kotlin apply is an extension function on a type. It runs on the object reference (also known as a receiver) into the expression and returns the object reference on completion.

data class Person(var name: String, var tutorial : String)
var person = Person("Anupam", "Kotlin")
person.apply { this.tutorial = "Swift" }
println(person)// Anupam Swift

apply vs also

data class Person(var n: String, var t : String)
var person = Person("Anupam", "Kotlin")
person.apply { t = "Swift" }
println(person)// Anupam Swift
person.also { it.t = "Kotlin" }
println(person)// Anupam Kotlin

Note: In apply it isn’t allowed. If the property name of the data class is unique in the function, you can omit this.

We should use also only when we don’t want to shadow this

Kotlin with

data class Person(var name: String, var tutorial : String)
var person = Person("Anupam", "Kotlin")
with(person)
{
name = "No Name"
tutorial = "Kotlin tutorials"
}// No name Kotlin tutorals

Again with is similar to apply except for a few differences.

Kotlin apply vs with

  • with runs without an object(receiver) whereas apply needs one.
  • apply runs on the object reference, whereas with just pass it as an argument.
  • The last expression of with function returns a result.
var xyz = with(person)
{
name = "No Name"
tutorial = "Kotlin tutorials"
val xyz = "End of tutorial"
xyz
}
println(xyz) //End of tutorial

4. What is Kotlin Detector?

5. How to execute Intent Service parallels?

IntentService does not run in parallel if it's from the same class. They will run sequentially. In other words, if you had an IntentService named DownloadService which downloads a file from a given URL, then you run it like so:

List<String> downloadUrls = getDownloadUrls();
Context ctx = getContext();
Intent baseIntent = new Intent(ctx, DownloadService.class);
for(String url : downloadUrls) {
Intent downloadService = new Intent(baseIntent);
downloadService.putString("downloadUrl", url);
ctx.startService(downloadService);
}

What would happen is the DownloadService would start once. Then, the first URL would be passed to it, and it would start downloading. Then, after that has finished, the DownloadService would use the second url. Then the third and so on. It all runs sequentially.

Now, you can have a second IntentService named UploadService which similarly would upload a file to a given URL. If you start this multiple times with different parameters, it will also run sequentially to every call. However, it will run parallel to DownloadService because they are two separate Service.

6. How checked and Unchecked Exception works?

Rule: An overriding method (the method of child class) can throw any unchecked exceptions, regardless of whether the overridden method (method of the base class) throws exceptions or not. However, the overriding method should not throw checked exceptions that are new or broader than the ones declared by the overridden method. The overriding method can throw those checked exceptions, which have less scope than the exception(s) declared in the overridden method.

Example 1: If the base class doesn’t throw any exception but child class throws an unchecked exception.
In this example class Room is overriding the method color(). The overridden method is not throwing any exception however the overriding method is throwing an unchecked exception (NullPointerException). Upon compilation, the code ran successfully.

class Building {  
void color()
{
System.out.println("Blue");
}
}
class Room extends Building{
//It throws an unchecked exception
void color() throws NullPointerException
{
System.out.println("White");
}
public static void main(String args[]){
Building obj = new Room();
obj.color();
}
}

Output:

White

Example 2: If the base class doesn’t throw any exception but child class throws a checked exception

import java.io.*;
class Building {
void color()
{
System.out.println("Blue");
}
}
class Room extends Building{
void color() throws IOException
{
System.out.println("White");
}
public static void main(String args[]){
Building obj = new Room();
try{
obj.color();
}catch(Exception e){
System.out.println(e);
}
}
}

Output:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
Exception IOException is not compatible with throws clause in Building.color()

The above code is having a compilation error: Because the overriding method (child class method) cannot throw a checked exception if the overridden method(method of the base class) is not throwing an exception.

Example 3: When base class and child class both throws a checked exception

import java.io.*;
class Building {
void color() throws IOException
{
System.out.println("Blue");
}
}
class Room extends Building{
void color() throws IOException
{
System.out.println("White");
}
public static void main(String args[]){
Building obj = new Room();
try{
obj.color();
}catch(Exception e){
System.out.println(e);
}
}
}

Output:

White

The code ran fine because color() method of child class is NOT throwing a checked exception with scope broader than the exception declared by color() method of base class.

Example 4: When child class method is throwing border checked exception compared to the same method of base class

import java.io.*;
class Building {
void color() throws IOException
{
System.out.println("Blue");
}
}
class Room extends Building{
void color() throws Exception
{
System.out.println("White");
}
public static void main(String args[]){
Building obj = new Room();
try{
obj.color();
}catch(Exception e){
System.out.println(e);
}
}
}

Output:
Compilation error because the color() method of child class is throwing Exception which has a broader scope than the exception thrown by method color() of parent class.

7. If kotlin has two property in primary constructor then is possible to allow only one value?

So, we have seen that the primary constructor is used to initialize the member variables of a class. But we are not writing any code of initialization in the primary constructor, then how will our goal be achieved?

To achieve this task, we use an initializer block called init() to initialize the member variables with the constructor variables. This init() block is executed just after the creation of an object.

class Person(_name: String, _age: Int, _salary: Int) {
// Member Variables (Properties) of the class
var name: String
var age: Int
var salary: Int
// Initializer Block
init {
this.name = _name
this.age = _age
this.salary = _salary
println("Initialized a new Person object with Name = $name , age = $age and salary = $salary")
}
}

this keyword is used to refer to the variables of the class or any block. If you have the same variable name in the class property and in the constructor then by using this keyword you can remove the confusion of the compiler. If you are not using this keyword then your code will look like name = name. So, it is not clear that which name is referenced here. So, to avoid confusion, we use this keyword.

If you don’t want to use this keyword, then you can initialize the variables of the class as follows:

class Person(_name: String, _age: Int, _salary: Int) {var name: Stringvar age: Intvar salary: Intinit() {println("Initialized a new Person object with name = $name , age = $age and salary = $salary")}}

To create an instance of the Person class, you can use the following code:

val per = Person("Anonymous", 20, 50000)

As soon as the instance of the class is created, the constructor of the class will be called. In the above example, “Anonymous” will be passed as _name, 20 will be pass as _age and 50000 will be passed as _salary.

Default values in constructor

You need not pass all the parameters while declaring an object. You can put default values to parameters of the constructor as shown below:

class Person(var name: String = "Anonymous", var age: Int = 0, var salary: Int = 20000) {
// Initializer Block
init {
println("Initialized a new Person object with name = $name , age = $lastName" and salary = $salary)
}
}

Now, the following calls are valid:

//all the 3 values are passed
val person1 = Person("Pubg", 25, 100000)
//update name and take the default value of age and salary
val person2 = Person("John")
//take all default value
val person3 = Person()

8.If super class has exception but child classes not then what will be do?

If the Superclass method throws an exception, then the Subclass overriden method can throw the same exception or no exception, but must not throw parent exception of the exception thrown by the Superclass method.

It means, if the Superclass method throws the object of NullPointerException class, then the Subclass method can either throw the same exception or can throw no exception, but it can never throw the object of the Exception class (parent of NullPointerException class).

Example of Subclass overriden method with the same Exception

Method of a subclass can declare the same exception as declared in the superclass. See the below example.

import java.io.*;
class Super
{
void show() throws Exception
{ System.out.println("parent class"); }
}
public class Sub extends Super {
void show() throws Exception //Correct
{ System.out.println("child class"); }
public static void main(String[] args)
{
try {
Super s=new Sub();
s.show();
}
catch(Exception e){}
}
}

Output: child class

Example of Subclass overriden method with no Exception

It is optional to declare the exception in subclass during overriding. If the method of superclass declared an exception then it is up to the subclass to declare exception or not. See the below example.

import java.io.*;
class Super
{
void show() throws Exception
{ System.out.println("parent class"); }
}
public class Sub extends Super {
void show() //Correct
{ System.out.println("child class"); }
public static void main(String[] args)
{
try {
Super s=new Sub();
s.show();
}
catch(Exception e){}
}
}

Output: child class

Example of Subclass overriden method with parent Exception

It is not allowed to declare parent class exception in the subclass method, we get compile-time error if we try to compile that program. See the below example.

import java.io.*;
class Super
{
void show() throws ArithmeticException
{ System.out.println("parent class"); }
}

public class Sub extends Super {
void show() throws Exception //Compile time Error
{ System.out.println("child class"); }

public static void main(String[] args)
{
try {
Super s=new Sub();
s.show();
}
catch(Exception e){}
}
}

Output: Compile time error

9. What is blocking queue its class or interface and how its works

BlockingQueue interface in Java is added in Java 1.5 along with various other concurrent Utility classes like ConcurrentHashMap, Counting Semaphore, CopyOnWriteArrrayList etc. BlockingQueue interface supports flow control (in addition to queue) by introducing blocking if either BlockingQueue is full or empty. A thread trying to enqueue an element in a full queue is blocked until some other thread makes space in the queue, either by dequeuing one or more element or clearing the queue completely. Similarly it blocks a thread trying to delete from an empty queue until some other treads inserts an item. BlockingQueue does not accept null value. If we try to enqueue null item, then it throws NullPointerException.

Java provides several BlockingQueue implementations such as LinkedBlockingQueue, ArrayBlockingQueue, PriorityBlockingQueue, SynchronousQueue etc. Java BlockingQueue interface implementations are thread-safe. All methods of BlockingQueue are atomic in nature and use internal locks or other forms of concurrency control. Java 5 comes with BlockingQueue implementations in the java.util.concurrent package.

BlockingQueue Types

The BlockingQueue are two types-

  • Unbounded Queue: The Capacity of blocking queue will be set to Integer.MAX_VALUE. In case of unbounded blocking queue, queue will never block because it could grow to a very large size. when you add elements it’s size grow.
BlockingQueue blockingQueue = new LinkedBlockingDeque();

Bounded Queue: The second type of queue is the bounded queue. In case of bounded queue you can create a queue by passing the capacity of queue in queues constructor:

// Creates a Blocking Queue with capacity 5
BlockingQueue blockingQueue = new LinkedBlockingDeque(5);

10. What is heap memory?

Heap is a memory region allotted to every program. Unlike stack, heap memory can be dynamically allocated. This means that the program can ‘request’ and ‘release’ memory from the heap segment whenever it requires. Also, this memory is global, i.e. it can be accessed and modified from anywhere within a program and is not localized to the function where it is allocated. This is accomplished using ‘pointers’ to reference dynamically allocated memory which in turn leads to a small degradation in performance as compared to using local variables (on the stack).

The heap is an area of dynamically-allocated memory that is managed automatically by the operating system or the memory manager library. Memory on the heap is allocated, deallocated, and resized regularly during program execution, and this can lead to a problem called fragmentation. Fragmentation occurs when memory objects are allocated with small spaces in between that are too small to hold additional memory objects. The net result is a percentage of the heap space that is not usable for further memory allocations.

Heaps are also susceptible to overflow situations, although the results are typically not as dire as in a stack overflow. It’s not impossible for a hacker to disrupt the system through a heap overflow, but it’s particularly difficult.

11. Heap Space vs Stack — Memory Allocation in Java

Stack and a Heap ?

Stack is used for static memory allocation and Heap for dynamic memory allocation, both stored in the computer’s RAM .

Variables allocated on the stack are stored directly to the memory and access to this memory is very fast, and it’s allocation is dealt with when the program is compiled. When a function or a method calls another function which in turns calls another function etc., the execution of all those functions remains suspended until the very last function returns its value. The stack is always reserved in a LIFO order, the most recently reserved block is always the next block to be freed. This makes it really simple to keep track of the stack, freeing a block from the stack is nothing more than adjusting one pointer.

Variables allocated on the heap have their memory allocated at run time and accessing this memory is a bit slower, but the heap size is only limited by the size of virtual memory . Element of the heap have no dependencies with each other and can always be accessed randomly at any time. You can allocate a block at any time and free it at any time. This makes it much more complex to keep track of which parts of the heap are allocated or free at any given time.

You can use the stack if you know exactly how much data you need to allocate before compile time and it is not too big. You can use heap if you don’t know exactly how much data you will need at runtime or if you need to allocate a lot of data.

In a multi-threaded situation, each thread will have its own completely independent stack but they will share the heap. The stack is thread-specific and Heap is application-specific. The stack is important to consider in exception handling and thread executions.

--

--

--

Senior Software Engineer | Android | Java | Kotlin|Xamarin Native Android|Flutter

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

How to Fetch The Data In RecyclerView Using Kotlin For Beginners

Jetpack Compose with more complex Previews/ Live previews and ViewModels

From custom view to Jetpack Compose

Kotlin Coroutines — Are we there yet?

How to Get SHA1 Key of Your App in Flutter (VS Code)

Cricket Exchange Mod Apk 2022

A must know secret about Android View State storing mechanism!

Understand the behavior of startActivityForResult for Fragment and Activity

Get the Medium app

Abhishek Srivastava

Abhishek Srivastava

Senior Software Engineer | Android | Java | Kotlin|Xamarin Native Android|Flutter

More from Medium

Text Recognition App with Google ML Kit — Android

Easy-breezy layout — LinearLayout in android

Android interview with, Ivan Morgillo

Push project to github in android studio