Topic: 5 Understanding Variables in Android

This is our fifth topic from learn android from basic to advance series

Β·

11 min read

Topic: 5 Understanding Variables in Android

Hello Devs, Today we will discuss Variables in our series and I know I know devs that I want to cover this topic first but I am also a human, and as you all know mistakes only happen by humans. OK moving on to the topic. So in this topic, we talk about why it is important and how we use this in development.

Variables

Variables are like containers they store different kinds of data. This is a fundamental component of every programming language. There are different types of variables available in programming.

Types of Variables

  1. Primitive Variables:

    • These are the basic building blocks for storing simple data types like integers, floating-point numbers, characters, and boolean values. In Android, you'll often use these primitives to store simple data such as user input, numeric values, or flags.

        int age = 25;
        float weight = 65.5f;
        char grade = 'A';
        boolean isActive = true;
      
  2. Reference Variables:

    • In Android, you'll frequently work with objects and collections. Reference variables store memory addresses that point to objects or collections rather than the actual data. For instance, when dealing with UI elements like TextViews or Buttons, you'll often use reference variables to interact with them programmatically.

        TextView textView = findViewById(R.id.textView);
        Button button = new Button(context);
        ArrayList<String> stringList = new ArrayList<>();
      
  3. Instance Variables:

    • These are variables declared within a class but outside of any methods. In Android development, instance variables are commonly used to represent the state of an object or to store data that needs to persist throughout the object's lifecycle. For example, in an Activity or Fragment class, you might use instance variables to store UI components or data fetched from a database.

        public class MyActivity extends AppCompatActivity {
            private String username;
            private int score;
      
            // Constructor, methods, and lifecycle callbacks...
        }
      
  4. Static Variables (Class Variables):

    • Static variables are associated with the class rather than with any particular instance of the class. In Android, static variables are less common but can be useful for storing global configuration values or constants that are shared across multiple instances of an Activity or Application.

        public class Constants {
            public static final String API_KEY = "your_api_key";
            public static final int DEFAULT_TIMEOUT = 5000;
      
            // More constants...
        }
      
  5. Local Variables:

    • Local variables are declared within a method or block of code and are accessible only within that method or block. In Android, you'll use local variables to perform temporary calculations, store intermediate results, or pass values between different parts of your code.

        public void calculateTotal(int a, int b) {
            int total = a + b;
            System.out.println("Total: " + total);
        }
      
  6. Final or Constant Variables:

    • These variables hold values that cannot be changed once they are assigned. In Android development, constants are often used for things like defining key names for Intent extras, specifying request codes for permissions, or setting default values for configuration parameters.

        public class Constants {
            public static final String INTENT_KEY_USER_ID = "user_id";
            public static final int REQUEST_CODE_PERMISSION = 1001;
      
            // More constants...
        }
      
  7. Parameter Variables:

    • Parameter variables are used to pass data into methods or functions. In Android, you'll frequently use parameter variables to pass information between different components of your app, such as passing data from one Activity to another via Intent extras or passing callback listeners to asynchronous tasks.

        public void sendMessage(String message) {
            // Logic to send message...
        }
      
        // Example of passing data between activities using Intent extras
        Intent intent = new Intent(this, NextActivity.class);
        intent.putExtra(Constants.INTENT_KEY_USER_ID, userId);
        startActivity(intent);
      

As you see in the example I wrote something like Int, float, etc. So what is this? it's a Data type. Basically, Data types are used to check what kind of data is stored in variables. Let's explore the Data Types.

Types of Data Type

As we all know that we use two kinds of languages for developing applications in Android. Java and Kotlin so first we discuss about Java data type after that Kotlin data type.

  1. Java:

    • Primitive Data Types: In Java, primitive data types are predefined by the language and represent basic types of data. These include:

      • int: Used to store integers (whole numbers) such as 1, 2, -5, etc. This data type uses 4 bytes(32 bits) of memory storage.

          int number = 10;
        
      • float: Used to store floating-point numbers (numbers with decimal points) such as 3.14, 2.5, etc. This data type uses 4 bytes(32 bits) of memory storage.

          float floatValue = 3.14f;
        
      • double: Similar to float but with higher precision. This data type uses 8 bytes(64 bits) of memory storage.

          double doubleValue = 3.14;
        
      • boolean: Used to store true or false values. This data type uses 1 byte (8 bits) of memory storage.

          boolean isTrue = true;
        
      • char: Used to store single characters like 'a', 'b', 'c', etc. This data type uses 2 bytes(16 bits) of memory storage.

          char letter = 'A';
        
      • byte, short, long: Additional integer types with different ranges. byte uses 1 byte, short uses 2 bytes, and long uses 8 bytes of storage.

          //Byte
          byte byteValue = 100;
          //Short
          short shortValue = 1000;
          //Long
          long longValue = 1000000L;
        
    • Reference Data Types: These are non-primitive data types that are created using classes, arrays, interfaces, etc. This includes:

      • String: Represents a sequence of characters, such as "Hello, World!".

          String message = "Hello, World!";
        
      • Object: The root class for all other classes in Java.

          Object obj = new Object();
        
      • Arrays: Used to store multiple values of the same type in a single variable.

          int[] numbers = new int[10];
        
    • Reference data types (objects) consume memory dynamically based on their size and structure.

  2. Kotlin:

    • Primitive Data Types: Kotlin has similar primitive data types to Java, but it provides some additional features and improvements:

      • Int, Float, Double, Boolean, Char: Similar to their counterparts in Java.

          // Int
          val number: Int = 10
          // Float
          val floatValue: Float = 3.14f
          // Double
          val doubleValue: Double = 3.14
          // Boolean
          val isTrue: Boolean = true
          // Char
          val letter: Char = 'A'
        
      • Byte, Short, Long: Also available in Kotlin.

          // Byte
          val byteValue: Byte = 100
          // Short
          val byteValue: Byte = 100
          // Long
          val longValue: Long = 1000000L
        
    • Reference Data Types: Kotlin treats classes as reference types, and it provides several built-in classes for common data types, such as:

      • String: Represents a sequence of characters. Memory usage depends on the string's length.

          val message: String = "Hello, World!"
        
      • Array: Used to store multiple values of the same type. Memory usage depends on the size and type of elements.

          val numbers: IntArray = intArrayOf(1, 2, 3, 4, 5)
        
      • Collections (List, Set, Map): Kotlin provides a rich set of collection classes for storing and manipulating data. Memory usage varies based on the size and contents of the collection.

          // List
          val list: List<String> = listOf("apple", "banana", "orange")
        
          // Set
          val immutableSet: Set<String> = setOf("apple", "banana", "orange")
        
          // Map
          val immutableMap: Map<String, Int> = mapOf("apple" to 1, "banana" to 2, "orange" to 3)
        

As you see in the Kotlin example I used the keyword val. Let's talk about Val and other keywords.

Val

  • val is a keyword in Kotlin used to declare read-only variables, also known as immutable variables. Once assigned, the value of a val cannot be changed.

  • It is similar to declaring variables with the final keyword in Java.

  • val properties can be initialized at runtime.

  • val is typically used when the value of a variable should remain constant throughout its lifetime.

      val PI = 3.14
      val name = "John"
    

Var

  • var is another keyword in Kotlin used to declare mutable variables. Unlike val, the value of a var variable can be changed after it's initialized.

  • var is used when the value of a variable is expected to change during the program execution.

      var count = 10
      var message = "Hello"
    

Mutable

  • In Kotlin, mutable is a prefix used to indicate that a type is mutable, meaning its contents can be modified after creation.

  • It is commonly used with collection types like MutableList, MutableSet, and MutableMap, where elements can be added, removed, or modified.

      val mutableList: MutableList<String> = mutableListOf("Apple", "Banana", "Orange")
      mutableList.add("Mango")
    

Static

  • In Java, static is a keyword used to declare class-level variables and methods. It indicates that the variable or method belongs to the class itself, rather than to instances of the class.

      // Package-level function (placed within a utility class)
      public class Utils {
          public static void doSomething() {
              // Function body
          }
      }
    
      // Companion object (static inner class)
      public class MyClass {
          public static final int CONSTANT_VALUE = 10;
    
          public static void staticMethod() {
              // Method body
          }
      }
    
  • In Kotlin, there's no direct equivalent of the static keyword. Instead, Kotlin uses package-level functions and properties or companion object to achieve similar functionality.

      // Package-level function
      fun doSomething() {
          // Function body
      }
    
      // Companion object
      class MyClass {
          companion object {
              const val CONSTANT_VALUE = 10
              fun staticMethod() {
                  // Method body
              }
          }
      }
    

Constant:

  • Constants are variables whose values cannot be changed once they are assigned. They are typically declared with the final keyword in Java or the const keyword in Kotlin.

  • const properties can be initialized at compile time.

  • Constants are often used for values that remain constant throughout the program's execution, such as configuration parameters or API keys.

      const val PI = 3.14
      const val API_KEY = "your_api_key"
    

Final:

  • In Java, final is a keyword used to declare constants, prevent method overriding, and make variables immutable.

      public final class MyClass {
          public final double PI = 3.14;
    
          public final void someMethod() {
              // Method body
          }
      }
    
  • In Kotlin, final is not a keyword but is implicitly applied to val variables, making them read-only.

      final class MyClass {
          final val PI = 3.14
          final fun someMethod() {
              // Method body
          }
      }
    

lateinit:

  • lateinit is nothing more than a promise. You promise Kotlin that you will initialize it before using it. It's like telling Kotlin, "Hey, I'll give you the value later, I promise!"

  • Late initialization applies only to var fields. This means lateinit applies only to reference types.

  • lateinit is handy when you need to delay initializing a variable until later in your code, but you're sure it'll be initialized before you use it. Just be cautious not to forget to initialize it, or you'll run into runtime errors!

lateinit var name: String

Now, you can use name without initializing it immediately. But remember, you must initialize it before accessing its value, otherwise, you'll get an exception.

name = "John" // Initialize the variable before using it

println(name) // Now you can use it safely

Lazy

  • Lazy initialization allows you to defer the initialization of a variable until the moment you first use it.

  • Imagine you have a task that takes a lot of time or resources to complete, but you don't want to do it until you absolutely have to. That's where lazy initialization comes in handy.

  • Lazy initialization applies only to val. This means lazy applies only to primitive types.

  • Lazy initialization is a useful technique when you want to delay the initialization of a variable until it's needed, improving performance and resource usage in your app.

val expensiveData: String by lazy {
    // This block of code will be executed only when 'expensiveData' is first accessed
    println("Initializing expensiveData...")
    "This is the expensive data"
}

// Somewhere else in your code
println("Do some other work first")
println(expensiveData) // This will trigger the lazy initialization

LiveData:

  • LiveData is an observable data holder class provided by the Android Architecture Components.

  • It's designed to hold and deliver data to other components, such as UI controllers (like Activities or Fragments), in a lifecycle-aware manner.

  • LiveData is typically used to represent data that needs to be observed for changes, such as data fetched from a database or network.

  • It ensures that UI components only update when they are in the active state, preventing issues like memory leaks and inconsistent UI states.

      val currentUser: LiveData<User> = userRepository.getCurrentUser()
      currentUser.observe(this) { user ->
          // Update UI with the current user data
      }
    

Memory Considerations:

  • Primitive vs. Reference Types: Primitive data types generally consume a fixed amount of memory, whereas reference data types (objects) consume memory dynamically based on their size and structure.

  • Memory Overhead: In addition to the actual data, objects in Java and Kotlin incur memory overhead for storing metadata, such as class information, synchronization locks, and garbage collection information.

  • Garbage Collection: Since Java and Kotlin use garbage collection to reclaim memory from unused objects, excessive memory usage can lead to increased garbage collection overhead and potential performance issues.

OK, Devs it's time to wrap up the topic. As you see some words like Memory Leak and garbage collection. So what is this? and how important it is for the application's performance. everything we discuss in our next blog and topic from the Learn Android from basic to advanced series. See you at the next blog devs.


Connect with Me:

Hey there! If you enjoyed reading this blog and found it informative, why not connect with me on LinkedIn? 😊 You can also follow my Instagram page for more mobile development-related content. πŸ“²πŸ‘¨β€πŸ’» Let’s stay connected, share knowledge and have some fun in the exciting world of app development! 🌟

Check out my Instagram page

Check out my LinkedIn

Β