Dùng hai tiến trình bảo vệ app Android

Việc duy trì hoạt động nền cho ứng dụng Android là vấn đề quan trọng. Nhiều app cần chạy ngầm liên tục để định vị, nhắn tin tức thời hay phát nhạc. Tuy nhiên hệ thống Android thường diệt tiến trình nền để tiết kiệm pin, gây ảnh hưởng đến chức năng và trải nghiệm người dùng.

Có nhiều cách giữ app sống như đưa vào danh sách trắng (không hiệu quả lắm vì tiến trình vẫn bị diệt), hoặc dùng alarm (gây rối lịch báo thức và người dùng dễ phát hiện). Phương pháp dùng hai tiến trình bảo vệ lẫn nhau là cách tối ưu hơn, khó bị diệt và không ảnh hưởng đến người dùng.

Ý tưởng chính: tạo hai Service chạy trên hai tiến trình riêng biệt. Một Service chạy trong tiến trình chính (LocalService), Service kia chạy trên tiến trình phụ (RemoteService). Hai Service này liên kết với nhau, nếu tiến trình nào bị diệt thì service còn lại sẽ khởi động lại ngay.

LocalService.java

public class LocalService extends Service {
    private Handler handler;
    private Runnable periodicTask;

    @Override
    public void onCreate() {
        super.onCreate();
        handler = new Handler();
        periodicTask = new Runnable() {
            @Override
            public void run() {
                try {
                    // Thực hiện tác vụ định kỳ
                } catch (Exception e) {
                    e.printStackTrace();
                }
                handler.postDelayed(this, 3000);
            }
        };
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new LocalBinder();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        handler.post(periodicTask);
        // Liên kết với RemoteService
        bindService(new Intent(this, RemoteService.class),
                connection, Context.BIND_AUTO_CREATE);
        return START_STICKY;
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // Kết nối thành công, không cần xử lý gì thêm
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // RemoteService bị diệt → khởi động lại
            startService(new Intent(LocalService.this, RemoteService.class));
            bindService(new Intent(LocalService.this, RemoteService.class),
                    connection, Context.BIND_IMPORTANT);
        }
    };

    private class LocalBinder extends Binder {
        // Có thể thêm phương thức tương tác nếu cần
    }
}

RemoteService.java

public class RemoteService extends Service {
    private Handler handler;
    private Runnable periodicTask;

    @Override
    public void onCreate() {
        super.onCreate();
        handler = new Handler();
        periodicTask = new Runnable() {
            @Override
            public void run() {
                try {
                    // Thực hiện tác vụ định kỳ
                } catch (Exception e) {
                    e.printStackTrace();
                }
                handler.postDelayed(this, 3000);
            }
        };
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new RemoteBinder();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        handler.post(periodicTask);
        // Liên kết ngược với LocalService
        bindService(new Intent(this, LocalService.class),
                connection, Context.BIND_AUTO_CREATE);
        return START_STICKY;
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // Kết nối thành công
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // LocalService bị diệt → khởi động lại
            startService(new Intent(RemoteService.this, LocalService.class));
            bindService(new Intent(RemoteService.this, LocalService.class),
                    connection, Context.BIND_IMPORTANT);
        }
    };

    private class RemoteBinder extends Binder {
        // Có thể thêm phương thức tương tác nếu cần
    }
}

Cơ chế hoạt động: Hai Service liên kết chéo với nhau. Khi tiến trình của Service A bị hệ thống diệt, Service B sẽ nhận được callback onServiceDisconnected() và ngay lập tức gọi startService() cùng bindService() với cờ BIND_IMPORTANT để khôi phục Service A. Nhờ đó cả hai Service luôn tồn tại.

Khai báo trong AndroidManifest.xml

<service android:name=".service.LocalService" />

<service
    android:name=".service.RemoteService"
    android:enabled="true"
    android:exported="true"
    android:process=":remote" />

Lưu ý: android:process=":remote" bắt buộc RemoteService chạy trên tiến trình riêng, tách biệt với tiến trình chính. LocalService mặc định chạy trong tiến trình chính của ứng dụng.

Thẻ: Android Service android:process ServiceConnection BIND_IMPORTANT

Đăng vào ngày 20 tháng 5 lúc 04:13