Quản lý tiến trình trong Android bằng ActivityManager

Trong Android, lớp ActivityManager cung cấp khả năng truy xuất thông tin về các tiến trình đang chạy và thực hiện thao tác quản lý như kết thúc tiến trình. Bài viết này minh họa cách lấy danh sách tiến trình hệ thống và cho phép người dùng chọn để chấm dứt một hoặc nhiều tiến trình nền.

Giao diện người dùng

Giao diện gồm một tiêu đề hiển thị các cột: trạng thái chọn, ID tiến trình, tên tiến trình và bộ nhớ sử dụng, kèm theo một ListView để liệt kê các tiến trình và nút "Kết thúc" để xử lý các mục đã chọn.

<?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">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="5"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/col_select"
            style="@style/my_style"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="3" />

        <TextView
            android:id="@+id/col_pid"
            style="@style/my_style"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="3"
            android:gravity="center"
            android:text="PID" />

        <TextView
            android:id="@+id/col_name"
            style="@style/my_style"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2"
            android:gravity="center"
            android:text="Tên tiến trình" />

        <TextView
            android:id="@+id/col_mem"
            style="@style/my_style"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="3"
            android:gravity="center"
            android:text="Bộ nhớ (KB)" />
    </LinearLayout>

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <Button
        android:id="@+id/btn_kill"
        style="@style/my_style"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="5"
        android:text="Kết thúc tiến trình" />
</LinearLayout>

Triển khai logic trong Java

Mã nguồn gồm ba lớp chính:

  • ProcessManagerActivity: lớp Activity chính, chịu trách nhiệm thu thập dữ liệu tiến trình và xử lý sự kiện người dùng.
  • ProcessListAdapter: bộ điều hợp (adapter) cho ListView.
  • ProcessItemView: thành phần giao diện đại diện cho một dòng trong danh sách.
package com.example.processmanager;

import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Debug;
import android.view.View;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;

public class ProcessManagerActivity extends ListActivity {

    private Button killButton;
    private ActivityManager activityManager;
    private ProcessListAdapter adapter;

    private void fetchRunningProcesses() {
        adapter = new ProcessListAdapter(this);
        activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> processes = activityManager.getRunningAppProcesses();

        if (processes != null) {
            for (ActivityManager.RunningAppProcessInfo process : processes) {
                int[] pids = {process.pid};
                Debug.MemoryInfo[] memoryInfo = activityManager.getProcessMemoryInfo(pids);
                String memoryUsage = memoryInfo[0].dalvikPrivateDirty + "KB";
                adapter.addItem(String.valueOf(process.pid), process.processName, memoryUsage, false);
            }
        }

        setListAdapter(adapter);
    }

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

        fetchRunningProcesses();

        killButton = findViewById(R.id.btn_kill);
        killButton.setOnClickListener(v -> {
            boolean hasSelection = false;
            for (int i = 0; i < adapter.getItemCount(); i++) {
                ProcessItem item = adapter.getItemAt(i);
                if (item.isSelected()) {
                    hasSelection = true;
                    String packageName = item.getProcessName();
                    new AlertDialog.Builder(ProcessManagerActivity.this)
                        .setTitle("Xác nhận kết thúc")
                        .setMessage("Bạn có chắc muốn kết thúc tiến trình: " + packageName + "?")
                        .setPositiveButton("Đồng ý", (dialog, which) -> {
                            activityManager.killBackgroundProcesses(packageName);
                            Toast.makeText(ProcessManagerActivity.this,
                                "Đã kết thúc: " + packageName, Toast.LENGTH_SHORT).show();
                            fetchRunningProcesses();
                        })
                        .setNegativeButton("Hủy", null)
                        .show();
                    break;
                }
            }
            if (!hasSelection) {
                Toast.makeText(this, "Vui lòng chọn ít nhất một tiến trình", Toast.LENGTH_SHORT).show();
            }
        });
    }

    static class ProcessListAdapter extends BaseAdapter {
        private final Context context;
        private final List<ProcessItem> items;

        ProcessListAdapter(Context ctx) {
            this.context = ctx;
            this.items = new ArrayList<>();
        }

        void addItem(String pid, String name, String mem, boolean selected) {
            items.add(new ProcessItem(pid, name, mem, selected));
        }

        int getItemCount() {
            return items.size();
        }

        ProcessItem getItemAt(int index) {
            return items.get(index);
        }

        @Override
        public int getCount() {
            return items.size();
        }

        @Override
        public Object getItem(int position) {
            return items.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ProcessItemView view;
            if (convertView == null) {
                ProcessItem item = items.get(position);
                view = new ProcessItemView(context, item);
            } else {
                view = (ProcessItemView) convertView;
                view.bind(items.get(position));
            }
            return view;
        }
    }

    static class ProcessItem {
        private final String pid;
        private final String processName;
        private final String memory;
        private boolean selected;

        ProcessItem(String pid, String name, String mem, boolean sel) {
            this.pid = pid;
            this.processName = name;
            this.memory = mem;
            this.selected = sel;
        }

        String getPid() { return pid; }
        String getProcessName() { return processName; }
        String getMemory() { return memory; }
        boolean isSelected() { return selected; }
        void setSelected(boolean sel) { selected = sel; }
    }

    static class ProcessItemView extends LinearLayout {
        private final CheckBox checkBox;
        private final TextView pidText;
        private final TextView nameText;
        private final TextView memText;

        ProcessItemView(Context context, ProcessItem item) {
            super(context);
            setOrientation(HORIZONTAL);

            int height = dipToPx(context, 60);

            checkBox = new CheckBox(context);
            addView(checkBox, new LayoutParams(0, height, 2f));

            pidText = new TextView(context);
            pidText.setText(item.getPid());
            addView(pidText, new LayoutParams(0, height, 3f));

            nameText = new TextView(context);
            nameText.setText(item.getProcessName());
            addView(nameText, new LayoutParams(0, height, 4f));

            memText = new TextView(context);
            memText.setText(item.getMemory());
            addView(memText, new LayoutParams(0, height, 3f));

            checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
                // Cập nhật trạng thái chọn trong item
                // Trong ví dụ đơn giản này, không lưu tham chiếu ngược
            });
        }

        void bind(ProcessItem item) {
            pidText.setText(item.getPid());
            nameText.setText(item.getProcessName());
            memText.setText(item.getMemory());
            checkBox.setChecked(item.isSelected());
        }

        private static int dipToPx(Context context, float dp) {
            return (int) (dp * context.getResources().getDisplayMetrics().density);
        }
    }
}

Phương thức getRunningAppProcesses() trả về danh sách các tiến trình đang chạy dưới dạng RunningAppProcessInfo. Mỗi mục chứa pid (ID tiến trình) và processName (thường là tên gói ứng dụng). Bộ nhớ được truy vấn qua getProcessMemoryInfo(), với giá trị dalvikPrivateDirty phản ánh lượng RAM riêng mà tiến trình đang sử dụng.

Để kết thúc tiến trình nền, ứng dụng gọi killBackgroundProcesses(packageName). Lưu ý rằng phương thức này chỉ có hiệu lực với các tiến trình nền của ứng dụng khác — không thể chấm dứt tiến trình hệ thống hoặc tiến trình đang ở foreground. Ngoài ra, cần khai báo quyền sau trong AndroidManifest.xml:

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

Cần nhấn mạnh rằng việc kết thúc tiến trình không phải lúc nào cũng giải phóng tài nguyên ngay lập tức, và hệ thống Android có cơ chế quản lý vòng đời ứng dụng riêng. Do đó, tính năng này chủ yếu mang tính minh họa hoặc hỗ trợ gỡ lỗi, không nên lạm dụng trong ứng dụng thực tế.

Thẻ: Android ActivityManager Process Management RunningAppProcessInfo killBackgroundProcesses

Đăng vào ngày 24 tháng 5 lúc 00:06