Paramclasses Academy - Blog

Tutorials Details

←
Post 36 of 40
→

Android App Performance, Permissions and Security Best Practices

Android App Performance, Permissions and Security Best Practices

November 4, 2026

1. Introduction

Building an Android application is not only about creating screens and writing Java code. A professional Android application should also be fast, secure, reliable, and respectful of user privacy.

For example, consider a student management application. It should:

  • Open quickly and respond smoothly.

  • Avoid unnecessary background operations.

  • Request only the permissions it actually needs.

  • Protect user information.

  • Communicate with servers securely.

  • Handle errors without exposing sensitive data.

In this tutorial, we will learn three important areas of Android development:

  1. Application Performance Optimization

  2. Android Permissions Management

  3. Android Application Security

We will also create a practical Java application that demonstrates permission handling, input validation, and background processing.

2. What Is Android App Performance?

Application performance describes how efficiently an Android application uses device resources and responds to user actions.

A well-optimized application should:

  • Start quickly.

  • Display screens smoothly.

  • Respond to button clicks without delays.

  • Use memory efficiently.

  • Avoid unnecessary CPU usage.

  • Minimize battery consumption.

  • Handle network operations efficiently.

Common Performance Problems

Slow Application Startup: The application takes too long to display its first screen.

Application Not Responding (ANR): The application stops responding because the main thread is blocked for too long.

Memory Leak: Objects that are no longer needed remain in memory because they are still referenced.

Slow UI Rendering: Heavy operations or complex layouts cause delayed screen rendering.

Battery Drain: Excessive background work, network activity, or unnecessary wakeups consume battery power.

3. Understanding the Android Main Thread

Android applications use a main thread, also known as the UI thread, to handle user interface operations.

It is responsible for:

  • Drawing application screens.

  • Handling button clicks.

  • Updating TextViews.

  • Processing user interactions.

  • Managing UI-related events.

You should avoid performing long-running operations on the main thread.

For example, the following code is a bad practice:

Thread.sleep(5000);

If this runs on the main thread, the application interface can freeze for five seconds.

Similarly, database queries, file operations, and network requests should generally run outside the main thread when they may take significant time.

Correct Approach: Background Thread

Java provides ExecutorService for managing background tasks.

ExecutorService executor =
        Executors.newSingleThreadExecutor();

executor.execute(() -> {

    // Perform background work here

});

This executes the task on a background thread instead of blocking the UI thread.

When you need to update the user interface, return to the main thread:

runOnUiThread(() -> {

    // Update TextView or other UI elements here

});

Always shut down an executor when its owning component no longer needs it, and manage the component lifecycle carefully.

4. How to Improve Android App Performance

A. Optimize Application Startup

The first screen should appear quickly.

Best practices:

  • Avoid unnecessary initialization in onCreate().

  • Load non-essential data after the first screen is displayed.

  • Avoid performing network requests during startup when they are not necessary.

  • Initialize libraries only when required.

  • Use efficient layouts and resources.

Android applications can have cold, warm, and hot starts. A cold start requires the system to create the application process, so it is especially important to measure and optimize.

B. Optimize Images

Large images can increase memory consumption and slow down screen rendering.

Best practices:

  • Use appropriately sized images.

  • Prefer Vector Drawables for scalable icons.

  • Consider WebP for suitable image assets.

  • Avoid loading unnecessarily large bitmaps.

  • Use image-loading libraries for remote images when appropriate.

C. Optimize RecyclerView

RecyclerView is useful for displaying large lists efficiently.

Best practices:

  • Use ViewHolder patterns.

  • Reuse item views.

  • Avoid unnecessary layout nesting.

  • Update only the items that need to change.

  • Load images efficiently.

D. Avoid Memory Leaks

A memory leak occurs when an object remains reachable even though the application no longer needs it.

Common causes include:

  • Keeping unnecessary Activity references.

  • Forgetting to unregister listeners.

  • Retaining long-lived references to Views.

  • Keeping callbacks or tasks alive longer than their owners.

Use lifecycle-aware components and release resources when they are no longer needed.

E. Optimize Background Work

Use the appropriate Android background-work API.

  • ExecutorService: For application-managed Java background tasks.

  • WorkManager: For deferrable, guaranteed background work.

  • Foreground Service: For user-noticeable work that must continue according to Android's foreground-service rules.

Avoid unnecessary background polling and repeated network requests.

5. Android Studio Profiler

Android Studio provides profiling tools that help developers identify performance problems.

You can use the Profiler to inspect:

CPU Profiler: Helps identify CPU-intensive operations and execution activity.

Memory Profiler: Helps inspect memory usage, object allocations, and possible memory leaks.

Network Profiler: Helps inspect network activity when supported by the development environment and app configuration.

Power Profiling: Available power-related diagnostics depend on the Android Studio and device setup.

How to Open Android Studio Profiler

  1. Open your Android project.

  2. Run the application on an emulator or physical device.

  3. Open View.

  4. Select Tool Windows.

  5. Open Profiler.

  6. Select the running application process.

  7. Inspect CPU and memory activity while using the application.

For accurate optimization, first measure the problem, identify its cause, make a change, and measure again.

6. What Are Android Permissions?

Permissions control access to protected device features and user information.

For example:

  • Camera permission allows camera access.

  • Location permission allows access to device location.

  • Microphone permission allows audio recording.

  • Contacts permission allows access to contacts.

  • Notification permission controls certain notification behavior.

Android uses an application sandbox to isolate applications. Permissions provide controlled access to protected resources outside that sandbox.

Types of Android Permissions

Normal Permissions

These protect resources that present relatively low risk to user privacy.

They are generally granted automatically when declared in the manifest.

Example:

<uses-permission
    android:name="android.permission.INTERNET" />

Dangerous Permissions

These protect sensitive information or device features.

Examples include:

CAMERA
ACCESS_FINE_LOCATION
RECORD_AUDIO
READ_CONTACTS

These permissions generally require a runtime request on supported Android versions.

Special Permissions

Some powerful capabilities use separate system-managed settings or special access flows. They do not follow the ordinary runtime permission dialog.

Examples include certain all-files access and overlay capabilities.

7. How to Declare Permissions in AndroidManifest.xml

Before requesting a permission, declare the required permission in the application manifest when the feature needs it.

For example, if your application needs camera access, add:

<uses-permission
    android:name="android.permission.CAMERA" />

Open:

app/src/main/AndroidManifest.xml

Add the permission directly inside the manifest element, outside the application element.

Do not declare permissions that your application does not need.

8. What Is Runtime Permission?

A runtime permission is a permission that the application must request from the user while the application is running.

For example, when a user opens a camera feature, the application can explain why camera access is needed and then request permission.

The recommended permission workflow is:

  1. Check whether permission is already granted.

  2. If not granted, explain why the feature needs it when appropriate.

  3. Request permission when the user starts using that feature.

  4. Handle the user's response.

  5. Continue without that feature if permission is denied.

Do not assume that users will always grant permissions.

9. Practical Example: Request Camera Permission Using Java

Android recommends using Activity Result APIs for permission requests.

Step 1: Add Camera Permission

In AndroidManifest.xml, add:

<uses-permission
    android:name="android.permission.CAMERA" />

Step 2: Create a Permission Launcher

Open MainActivity.java.

Add these imports:

import android.Manifest;
import android.content.pm.PackageManager;
import android.widget.Toast;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.core.content.ContextCompat;

Inside your Activity class, declare:

private ActivityResultLauncher<String> cameraPermissionLauncher;

Initialize the launcher inside onCreate():

cameraPermissionLauncher =
        registerForActivityResult(
                new ActivityResultContracts.RequestPermission(),
                isGranted -> {

                    if (isGranted) {

                        Toast.makeText(
                                this,
                                "Camera permission granted",
                                Toast.LENGTH_SHORT
                        ).show();

                    } else {

                        Toast.makeText(
                                this,
                                "Camera permission denied",
                                Toast.LENGTH_SHORT
                        ).show();

                    }
                }
        );

Step 3: Check and Request Permission

Create this method:

private void requestCameraPermission() {

    if (ContextCompat.checkSelfPermission(
            this,
            Manifest.permission.CAMERA
    ) == PackageManager.PERMISSION_GRANTED) {

        Toast.makeText(
                this,
                "Camera permission already granted",
                Toast.LENGTH_SHORT
        ).show();

    } else {

        cameraPermissionLauncher.launch(
                Manifest.permission.CAMERA
        );
    }
}

Call this method when the user clicks a button that starts the camera feature.

Important: This example requests permission only. It does not capture an image. Camera access should be implemented separately after permission is granted.

If the user denies permission, your application should explain the limitation and allow them to continue using unrelated features.

10. Permission Best Practices

  • Request only the permissions your application needs.

  • Ask for permission when the related feature is used.

  • Explain why a permission is required.

  • Handle permission denial gracefully.

  • Check permission status before accessing protected resources.

  • Respect permission revocation.

  • Prefer privacy-friendly alternatives when available.

For example, if your application only needs a user-selected image, consider using Android's Photo Picker instead of requesting broad media access.

11. What Is Android Application Security?

Application security means protecting the application, its users, and their data from unauthorized access, misuse, and attacks.

Security is important because Android applications may handle:

  • Usernames and passwords.

  • Email addresses.

  • Mobile numbers.

  • Personal documents.

  • Payment information.

  • API responses.

  • Authentication tokens.

A secure application should protect sensitive data during storage, processing, and communication.

12. Important Android Security Best Practices

A. Use HTTPS for Network Communication

Always use HTTPS when communicating with production servers.

HTTPS protects data during transmission using TLS.

Example:

URL url = new URL(
        "https://example.com/api/students"
);

Avoid sending passwords, tokens, or personal information over plain HTTP.

Do not disable TLS certificate validation to fix connection errors.

B. Never Store Passwords in Plain Text

Do not store user passwords directly in SharedPreferences or SQLite.

For authentication, use a trusted authentication provider or a properly designed backend authentication system.

If your application needs to store sensitive local keys, use Android Keystore-backed solutions.

C. Protect API Keys

Never hardcode private API secrets inside Java source code or upload them to a public GitHub repository.

Important points:

  • Keep server-side secrets on the backend.

  • Use restricted API keys where supported.

  • Apply separate keys for development and production.

  • Configure API key restrictions.

  • Rotate exposed credentials.

Moving a secret from a Java file into another file packaged inside the APK does not make it truly secret.

D. Validate User Input

Never trust data entered by the user or received from an external server.

For example:

String email = "student@example.com";

if (email == null || email.trim().isEmpty()) {

    Log.e("Security", "Email is required");

}

Also validate data on the backend. Client-side validation alone cannot protect a server.

E. Use Prepared Statements for Database Operations

When communicating with a backend database, use parameterized queries instead of combining user input directly into SQL strings.

Example using PHP PDO:

$stmt = $pdo->prepare(
    "SELECT * FROM students WHERE email = :email"
);

$stmt->execute([
    ':email' => $email
]);

Prepared statements help prevent SQL injection when used correctly.

F. Secure Local Data

Use the right storage mechanism for the data:

  • SharedPreferences or DataStore for appropriate small preference data.

  • Room for structured local database records.

  • Android Keystore for cryptographic key protection.

  • Encrypted storage solutions when sensitive local data must be persisted.

Do not assume that ordinary local storage is automatically secure.

G. Avoid Unnecessary Logging

Never log sensitive information such as:

  • Passwords.

  • Authentication tokens.

  • Private user details.

  • Payment information.

Debug logs should not expose confidential information in production builds.

H. Secure Application Components

Review exported Activities, Services, Broadcast Receivers, and Content Providers.

Do not expose components to other applications unless required.

Use appropriate permissions and explicit intent handling to protect components that should not be publicly accessible.

13. Practical Project: Secure and Efficient Profile App

Now we will create a small application that demonstrates some of the practices learned in this tutorial.

Our project will contain:

  • Name input field.

  • Email input field.

  • Save button.

  • Result TextView.

  • Input validation.

  • Background processing.

  • Main-thread UI updates.

This example demonstrates safe UI-thread handling and basic validation. It is not a complete secure account system and does not store personal information on a server.

Step 1: Create a New Project

  1. Open Android Studio.

  2. Create a new project.

  3. Select Empty Views Activity.

  4. Set the project name to SecureProfileApp.

  5. Select Java.

  6. Finish the setup.

Step 2: Create the XML Layout

Open activity_main.xml and add:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="20dp">

    <EditText
        android:id="@+id/etName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Enter your name"
        android:inputType="textPersonName" />

    <EditText
        android:id="@+id/etEmail"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Enter your email"
        android:inputType="textEmailAddress" />

    <Button
        android:id="@+id/btnSave"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Save Profile" />

    <TextView
        android:id="@+id/tvResult"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="Profile status will appear here"
        android:textSize="18sp" />

</LinearLayout>

Step 3: Write MainActivity.java

Open MainActivity.java and add:

package com.example.secureprofileapp;

import android.os.Bundle;
import android.util.Patterns;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MainActivity extends AppCompatActivity {

    EditText etName, etEmail;
    Button btnSave;
    TextView tvResult;

    private ExecutorService executor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        etName = findViewById(R.id.etName);
        etEmail = findViewById(R.id.etEmail);
        btnSave = findViewById(R.id.btnSave);
        tvResult = findViewById(R.id.tvResult);

        executor = Executors.newSingleThreadExecutor();

        btnSave.setOnClickListener(v -> saveProfile());
    }

    private void saveProfile() {

        String name = etName.getText()
                .toString().trim();

        String email = etEmail.getText()
                .toString().trim();

        if (name.isEmpty()) {
            etName.setError("Name is required");
            return;
        }

        if (!Patterns.EMAIL_ADDRESS
                .matcher(email).matches()) {

            etEmail.setError("Enter a valid email");
            return;
        }

        btnSave.setEnabled(false);

        executor.execute(() -> {

            // Demonstration of background processing.
            // No network request or sensitive data storage here.

            String result = "Profile information validated";

            runOnUiThread(() -> {

                tvResult.setText(result);

                btnSave.setEnabled(true);
            });
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (executor != null) {
            executor.shutdownNow();
        }
    }
}

Replace the package declaration with the package name generated by your project.

Step 4: Understand the Code

Input Validation: The application checks whether the name is empty and whether the email has a valid format.

ExecutorService: Runs the demonstration task in the background.

runOnUiThread(): Updates the TextView and Button on the main thread.

setEnabled(false): Prevents repeated clicks while the task is running.

shutdownNow(): Requests cancellation of unfinished executor tasks when the Activity is destroyed.

For a real application, long-running work should be managed with lifecycle-aware patterns, and operations that must survive screen changes should use an appropriate architecture.

Step 5: Run and Test the Application

Run the project on an emulator or physical Android phone.

Test these cases:

Test 1: Empty Name

Leave the name field empty and enter a valid email.

Expected Result: The name field displays a validation error.

Test 2: Invalid Email

Enter a name and an invalid email.

Expected Result: The email field displays an error.

Test 3: Valid Information

Enter a valid name and email.

Expected Result: The application displays:

Profile information validated

This completes our practical example.

14. Performance vs Security vs Permissions

These three areas solve different problems.

Performance: Makes the application faster, smoother, and more efficient.

Permissions: Controls access to protected device features and user information.

Security: Protects application data, communication, and components from unauthorized access.

A professional Android application must consider all three areas during development.

15. Best Practices Checklist

Before releasing an Android application, review the following:

Performance

  • Avoid long-running operations on the main thread.

  • Optimize images and layouts.

  • Use RecyclerView efficiently.

  • Avoid memory leaks.

  • Measure performance with Android Studio Profiler.

  • Reduce unnecessary background work.

Permissions

  • Request only required permissions.

  • Request permissions in context.

  • Handle denied permissions.

  • Check permission status before protected operations.

  • Prefer privacy-friendly APIs where possible.

Security

  • Use HTTPS.

  • Never store plain-text passwords.

  • Protect API secrets.

  • Validate user input.

  • Use prepared statements on the backend.

  • Protect sensitive local data.

  • Avoid logging private information.

  • Review exported application components.

16. Conclusion

Performance, Permissions, and Security are essential parts of professional Android development.

Performance optimization helps applications run smoothly and use device resources efficiently. Permission management ensures that applications access only the resources they need. Security practices protect users and their personal information.

In this tutorial, we learned about Android Studio Profiler, background processing with ExecutorService, runtime permissions using Activity Result APIs, secure network communication, input validation, and safe data handling.

By following these practices, you can build Android applications that are efficient, privacy-conscious, and more secure.

17. Frequently Asked Questions

Q1. What is Android app performance?

It describes how efficiently an application uses device resources and responds to user interactions.

Q2. What is an ANR error?

ANR stands for Application Not Responding. It occurs when the application fails to respond to user input within the system's expected time.

Q3. What is a runtime permission?

A runtime permission is a permission that an application requests from the user while running when access to a protected resource is needed.

Q4. What is Android Studio Profiler?

It is a development tool used to inspect application performance, including CPU and memory usage.

Q5. Why should we use HTTPS?

HTTPS protects data exchanged between the application and server through encrypted communication.

Q6. Should passwords be stored in SharedPreferences?

No. Do not store plain-text passwords in SharedPreferences. Use a trusted authentication system and appropriate secure credential handling.

Q7. What is a memory leak?

A memory leak occurs when objects that are no longer needed remain reachable and occupy memory.

Q8. Why should we avoid network operations on the main thread?

Network operations can take time and block the user interface, causing freezing or ANR errors.

Q9. What is the Android Keystore?

Android Keystore is a system facility that helps applications securely generate and manage cryptographic keys.

Q10. Can an application work when a user denies a permission?

Yes, when possible. The application should disable or limit only the feature that requires the denied permission and allow unrelated features to continue working.

←
Post 36 of 40
→