Làm thế nào để xử lý mã khi ứng dụng bị chết bằng cách vuốt trong Android?


104

Nếu ứng dụng của tôi đang chạy và tôi nhấn nút trang chủ, ứng dụng sẽ ở chế độ nền. Bây giờ nếu một dài bấm nút home và tắt ứng dụng bằng cách vuốt từ danh sách ứng dụng gần đây, không ai trong số những sự kiện như thế onPause(), onStop()hay onDestroy()được gọi chứ không phải quá trình được chấm dứt. Vì vậy, nếu tôi muốn các dịch vụ của mình dừng, hủy thông báo và hủy đăng ký người nghe, tôi có thể làm như thế nào? Tôi đã đọc khá nhiều bài báo và blog nhưng không nhận được bất kỳ thông tin hữu ích nào và tôi không tìm thấy bất kỳ tài liệu nào về nó. Bất kỳ trợ giúp sẽ được đánh giá cao. Cảm ơn trước.


Tôi giải quyết vấn đề của tôi. Kiểm tra
MysticMagicϡ

@MysticMagic Hoạt động cho một Dịch vụ, còn việc hủy Thông báo và hủy đăng ký người nghe thì sao?
CodeWarrior

Bạn có thể hủy đăng ký người nghe trong onTaskRemoved. Bạn không thể? Và tương tự đối với việc hủy thông báo
MysticMagic

@ MysticMagicϡ Nếu tôi muốn làm những điều tương tự khi cập nhật ứng dụng thì sao?
reji

Câu trả lời:


150

Tôi vừa giải quyết một loại vấn đề tương tự.

Đây là những gì bạn có thể làm nếu nó chỉ dừng dịch vụ khi ứng dụng bị tắt bằng cách vuốt từ danh sách ứng dụng Gần đây.

Bên trong tệp kê khai của bạn, giữ cờ stopWithTasknhư truecho Dịch vụ. Giống:

<service
    android:name="com.myapp.MyService"
    android:stopWithTask="true" />

Nhưng khi bạn nói rằng bạn muốn hủy đăng ký người nghe và dừng thông báo, v.v., tôi sẽ đề xuất phương pháp này:

  1. Bên trong tệp kê khai của bạn, giữ cờ stopWithTasknhư falsecho Dịch vụ. Giống:

    <service
        android:name="com.myapp.MyService"
        android:stopWithTask="false" />
    
  2. Bây giờ trong MyServicedịch vụ của bạn , ghi đè phương thức onTaskRemoved. (Điều này sẽ chỉ được kích hoạt nếu stopWithTaskđược đặt thành false).

    public void onTaskRemoved(Intent rootIntent) {
    
        //unregister listeners
        //do any other cleanup if required
    
        //stop service
        stopSelf();  
    }
    

Tham khảo câu hỏi của tôi để biết thêm chi tiết, cũng có phần khác của mã.

Hi vọng điêu nay co ich.


Cảm ơn. Suy nghĩ xem phương pháp này có thể được sử dụng để xác định số lần giết bằng cách vuốt. Dịch vụ trống đơn giản?
Kiran

Có @Kiran bạn có thể thử. :)
MysticMagicϡ

1
@ MysticMagicϡ xin chào, một câu hỏi, tôi đã thử sử dụng giải pháp của bạn, nhưng có vẻ như các hoạt động dài như gửi dữ liệu đến máy chủ, phân tích lên google, v.v. đôi khi không thành công. Nó có thể là quá trình bị giết trước khi phương pháp này có cơ hội để hoàn thành chính nó? Ngoài ra, bạn đã thử phương pháp này trên thiết bị Huawei chưa? Có vẻ như onTaskRemoved không bao giờ được gọi trên các thiết bị đó. Bất kỳ ý tưởng tại sao?
Alon Minski

2
@ MysticMagicϡ public void onTaskRemoved (..) Phương thức không gọi trong Android O. Hoạt động tốt trong hệ điều hành khác nhưng gặp sự cố trong Android O.
Jay Patel

2
Mã này không hoạt động cho Android O do giới hạn Dịch vụ nền. Có cách nào để xử lý điều này trong tất cả các thiết bị Android không?
Aanal Mehta

33

Tìm thấy một cách để làm điều này

thực hiện một dịch vụ như thế này

public class OnClearFromRecentService extends Service {

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

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d("ClearFromRecentService", "Service Started");
    return START_NOT_STICKY;
}

@Override
public void onDestroy() {
    super.onDestroy();
    Log.d("ClearFromRecentService", "Service Destroyed");
}

@Override
public void onTaskRemoved(Intent rootIntent) {
    Log.e("ClearFromRecentService", "END");
    //Code here
    stopSelf();
}

}

2) đăng ký dịch vụ này trong tệp kê khai.xml

<service android:name="com.example.OnClearFromRecentService" android:stopWithTask="false" />

3) Sau đó bắt đầu dịch vụ này trên hoạt động giật gân của bạn

startService(new Intent(getBaseContext(), OnClearFromRecentService.class));

Và bây giờ bất cứ khi nào bạn xóa ứng dụng của mình khỏi android gần đây thì phương thức này onTaskRemoved () sẽ thực thi.


1
Một với một sao chép và dán từ câu trả lời này: stackoverflow.com/questions/21040339
Flot2011

17

Tôi đã giải quyết vấn đề tương tự. Nếu bạn muốn sau khi vuốt từ tác vụ gần đây và vào lần khởi chạy tiếp theo, nó hoạt động bình thường thì hãy làm theo các bước sau: -

1) Lưu ID quy trình trong tùy chọn chia sẻ:

SharedPreferencesUtils.getInstance().putInt(SharedPreferencesUtils.APP_PROCESS_ID, android.os.Process.myPid());

2) Khi ứng dụng được khởi chạy từ trình khởi chạy sau khi xóa khỏi tác vụ gần đây, hãy thực hiện:

int previousProcessID = mSharedPreferencesUtils.getInt(SharedPreferencesUtils.APP_PROCESS_ID);

int currentProcessID = android.os.Process.myPid();

if ((previousProcessID == currentProcessID)) {
    // This ensures application not killed yet either by clearing recent or anyway
} else {
    // This ensures application killed either by clearing recent or by anyother means
}

Đã xác nhận - sử dụng trên Android 8 mà không cần dịch vụ.onTaskRemoved () - hoàn thành tốt
Gal Rom

4
Giải pháp này chỉ phát hiện khi ứng dụng được khởi động lại, nhưng bạn không thể phát hiện thời điểm chính xác khi ứng dụng đã bị giết chết
Vadim Kotov

6

Khi bạn nhấn nút home - onPauseonStopActivity của bạn đang được gọi, vì vậy tại thời điểm này, bạn phải thực hiện tất cả tiết kiệm và dọn dẹp, vì nền tảng Android không đảm bảo thêm rằng onDestroyhoặc bất kỳ phương thức vòng đời nào khác sẽ được gọi, vì vậy quá trình có thể bị hủy mà không có bất kỳ thông báo nào.


12
Cảm ơn bạn đã đề xuất, nhưng tôi không muốn giết thông báo, dịch vụ và trình nghe của mình onPause()onstop()chúng chỉ cần bị giết khi người dùng thoát khỏi ứng dụng tức là đăng xuất.
CodeWarrior

1

Bạn cần lưu dữ liệu của mình khi onPause()được gọi. Nhìn vào sơ đồ vòng đời này: Nhà phát triển Android

Bạn có thể thấy rằng một ứng dụng có thể bị giết sau onPause()hoặc onStop().

Xử lý dữ liệu của bạn ở đó và khôi phục nó trong onRestart()\ onCreate().

chúc may mắn!


1

Bạn không thể xử lý thao tác vuốt vì hệ thống chỉ xóa quy trình của bạn khỏi bộ nhớ mà không gọi bất kỳ cuộc gọi lại nào.

Tôi đã kiểm tra rằng trước khi người dùng gọi màn hình "ứng dụng gần đây", onPause () sẽ luôn được gọi. Vì vậy, bạn cần lưu tất cả dữ liệu trong phương thức onPause mà không đánh dấu isFinishing ().

Để kiểm tra nút quay lại, hãy sử dụng phương pháp onBackPressed.


1
Tôi tin rằng đây là phương pháp an toàn duy nhất cho tất cả các phiên bản Android.
Sergio

@Sergio vâng, đó là phương pháp an toàn nhất và tôi đã thử nghiệm nó trên Ứng dụng quy mô lớn hơn.
Ahmad

1

ViewModel.onCleared () có thể hữu ích, nếu mục đích là giải phóng một số tài nguyên (có thể là một hệ thống đang chạy ở một nơi khác trên mạng) khi người dùng thực hiện một lần thoát bất ngờ bằng cách vuốt, thay vì nhấn "dừng" hoặc nút. [Đây là cách ban đầu tôi đặt ra câu hỏi này].

Ứng dụng không nhận được thông báo và Activity.onDestroy () được gọi cho các thay đổi cấu hình chẳng hạn như thay đổi về hướng, vì vậy câu trả lời không có ở đó. Nhưng ViewModel.onCleared được gọi khi Ứng dụng được vuốt đi (cũng như khi người dùng quay lại hoạt động). Nếu tài nguyên bạn muốn sử dụng được liên kết với nhiều hoạt động trong ngăn xếp, bạn có thể thêm số lượng tham chiếu hoặc một số cơ chế khác để quyết định xem ViewModel.onClear có nên giải phóng tài nguyên hay không.

Đây là một trong nhiều lý do chính đáng để sử dụng ViewModel.

- Bob


1

Tôi thực sự không biết tại sao các cách tiếp cận trên không hoạt động với trường hợp của tôi ngay cả khi tôi đã đặt android:stopWithTask="false"onTaskRemoved()không được gọi.

Một cách tiếp cận tốt khác sẽ được sử dụng AndroidViewModel. Điều này thậm chí còn hoạt động trong trường hợp khi người dùng thoát ứng dụng khi nhấn nút quay lại.

Chỉ cần liên kết ViewModellớp với bạn MainActivityrồi thực hiện việc onCleared()gọi lại tác vụ của bạn .

Thí dụ:

public class MainViewModel extends AndroidViewModel {
    public MainViewModel(@NonNull Application application) {
        super(application);
    }

    @Override
    protected void onCleared() {
        // Do your task here
        Log.e("MainViewModel", "OnCleared mainViewModel");
        super.onCleared();
    }
}

sau đó liên kết nó với MainActivity của bạn:

MainViewModel viewModel = new ViewModelProvider(this).get(MainViewModel.class);

~ Thì đấy!


nó có thể không hoạt động với cách tiếp cận dịch vụ do Android O trở lên như những người bình luận khác đã đề cập. Đây có vẻ là một giải pháp thú vị để sử dụng các mô hình chế độ xem cho việc này. Điều này có tiếp tục được kích hoạt nếu ứng dụng bị buộc tắt (vuốt trên màn hình trình chuyển đổi ứng dụng) không? chỉnh sửa: Câu trả lời của Bob cho thấy nó hoạt động trong những trường hợp này
William Reed

vâng, nó hoạt động, đó là trường hợp mà tôi gặp phải
droidhs

0

Điều này làm việc cho tôi trên android 6,7,8,9.

Tạo một dịch vụ như thế này:

 public class OnClearFromRecentService extends Service {

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

 @Override public int onStartCommand(Intent intent, int flags, int
 startId) {
     Log.d("ClearFromRecentService", "Service Started");
     return START_NOT_STICKY; }

 @Override public void onDestroy() {
     super.onDestroy();
     Log.d("ClearFromRecentService", "Service Destroyed"); }

 @Override public void onTaskRemoved(Intent rootIntent) {
     Log.e("ClearFromRecentService", "END");
     //Code here
     stopSelf(); } }

2) Đăng ký dịch vụ này tại manifest.xml:

<service android:name="com.example.OnClearFromRecentService"
 android:stopWithTask="false" />

3) Sau đó bắt đầu dịch vụ này trên hoạt động giật gân của bạn

 startService(new Intent(getBaseContext(),
 OnClearFromRecentService.class));

1
Và tại sao dịch vụ của bạn sẽ tiếp tục chạy trên Android 8 trở lên? Bạn nhận ra rằng có những hạn chế đối với Dịch vụ bắt đầu đăng Android 8, phải không?
rahil008

0

Như Bob Cram đã đề cập trong câu trả lời của mình, phương thức onCleared () của View Model là câu trả lời. Nó hoạt động trong cả hai trường hợp:

  1. Khi người dùng xóa ứng dụng bằng cách vuốt ứng dụng khỏi nền.
  2. Khi người dùng xóa tất cả ứng dụng bằng nút danh sách xóa.

OnTaskRemoved () của dịch vụ sẽ hoạt động khi người dùng vuốt ứng dụng khỏi nền, nhưng sẽ không hoạt động khi các ứng dụng bị xóa bằng nút hủy tất cả.

Nhưng phương thức onCleared () của viewModel hoạt động trong cả hai trường hợp. Bạn có thể sử dụng if để dừng mọi quá trình đang diễn ra hoặc xóa bất kỳ tác vụ nào trong máy chủ từ xa.

 override fun onCleared() {
        super.onCleared()
        Log.d(TAG , "App Killed")
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.