12

Trên Android, tôi có một Activity được gọi là FirstActivity bắt đầu một Service có tên MyService để thực hiện các công việc mạng trong nền. Các ActivityService liên lạc với nhau mọi lúc bằng cách gọi các phương thức.Hoạt động với dịch vụ lâu dài trong nền sẽ không bị giết

Bây giờ khi người dùng điều hướng FirstActivity-SecondActivity, dịch vụ nền nên không bị giết hoặc tái tạo, nhưng vẫn giữ còn sống và truyền cho SecondActivity mà bây giờ sẽ là người nối với dịch vụ.

Nói cách khác, các Service được chạy miễn là một trong hai Activity s đang chạy, và nó không nên dừng lại khi người dùng điều hướng giữa hai Activity s.

Một trong số Activity s sẽ luôn ở mặt trước và trong thời gian này, dịch vụ nên (tối ưu) không bao giờ bị giết. Tôi nghĩ rằng đây không phải là một vấn đề bởi vì một trong hai Activity s luôn hoạt động và do đó Android biết dịch vụ là quan trọng và không phải cái gì đó phải bị giết.

(Nếu không có cách nào để ngăn chặn Android từ giết chết và tái tạo các dịch vụ bất cứ lúc nào, tôi sẽ cần một cách để khôi phục lại toàn bộ trạng thái của dịch vụ một cách duyên dáng.)

Tổng hợp , Service phải có cùng tuổi thọ như hai "Activity" được kết hợp ". Nó nên bắt đầu với cái đầu tiên và dừng lại trước khi cả hai đã bị phá hủy.

Vì vậy, mã sau là đúng cho thiết lập và mục tiêu đó?

Đây có phải là cách tốt nhất để đảm bảo dịch vụ lâu dài trong nền của Activity mà không bị giết hoặc tái tạo không?

Còn khoảng Context.BIND_AUTO_CREATE thì sao? Có đúng là đặt cờ này ở đây không? Còn về Context.BIND_ADJUST_WITH_ACTIVITYContext.BIND_WAIVE_PRIORITY - tôi có cần những thứ này không?

+0

Bạn đã thử mã đó hay bạn đang hỏi trước khi thử? Nếu bạn đã thử, bạn có gặp bất kỳ lỗi nào không? Nó không hoạt động như bạn mong đợi? Chúng tôi sẽ có một cuộc thảo luận hiệu quả hơn và một câu trả lời hữu ích hơn cho cộng đồng và bản thân bạn nếu bạn thực sự thử nó và sau đó yêu cầu chúng tôi giải quyết một vấn đề cụ thể mà bạn có – DallaRosa

+0

@DallaRosa Có, tất nhiên, tôi đã thử điều này.Đây là một câu hỏi chung về cách thiết kế một lớp dịch vụ và các lớp 'Activity' tương ứng để dịch vụ kéo dài càng lâu càng tốt và không bị giết. Người dùng đã báo cáo rằng các tính năng được cung cấp bởi dịch vụ này ngừng hoạt động trong một trong các lớp 'Hoạt động' theo thời gian. Và tôi (a) thấy khó để gỡ lỗi khi syste có thể giết dịch vụ này và (b) muốn biết về một số thực hành hay cải tiến tốt nhất nên được áp dụng cho dịch vụ này cho các mục tiêu và yêu cầu được xác định rõ. – caw

+0

Tôi có thể thấy nhiều vấn đề trong việc quản lý 'Dịch vụ' của bạn. Bạn chỉ cần dừng nó khi 'Activity' đầu tiên bị phá hủy, hoặc phụ thuộc vào sự ràng buộc và quản lý nó đúng cách. Có một số hướng dẫn chung về điều này trong các sách Bắt đầu từ Android: https://books.google.com.pk/books?id=mRGrCQbqHkoC&pg=PA399 – corsair992

Trả lời

7

(Rất cám ơn đến @ corsair992 cho con trỏ hữu ích của mình!)


Nếu các hoạt động luôn luôn được gọi theo thứ tự (ví dụ FirstActivity bắt đầu SecondActivity, và không bao giờ phải là cách khác xung quanh, sau đó bạn nên, về cơ bản, cố gắng "buộc" vòng đời của Dịch vụ vào vòng đời của FirstActivity

Nói chung (xem sau), điều này có nghĩa là:

  • Gọi startService() trong FirstActivity.onCreate().
  • Gọi stopService() trong FirstActivity.onDestroy().
  • Gọi bindService()/unbindService() trong các phương pháp onStart()/onStop() của cả hai hoạt động (để có được quyền truy cập vào các đối tượng Binder, và có thể gọi các phương thức trên nó).

Một dịch vụ bắt đầu theo cách này sẽ còn sống cho đến khi stopService() được gọi mỗi khách hàng unbinds, xem Managing the Lifecycle of a Service:

Hai con đường không hoàn toàn riêng biệt. Tức là, bạn có thể liên kết với dịch vụ đã được bắt đầu với startService(). (...) Trong trường hợp như vậy, stopService() hoặc stopSelf() không thực sự ngừng dịch vụ cho đến khi tất cả khách hàng unbind.

và:

Khi người khách cuối cùng unbinds từ dịch vụ, hệ thống phá hủy các dịch vụ (trừ dịch vụ cũng đã được bắt đầu bởi startService()).

Với chiến lược cơ bản này, Dịch vụ sẽ hoạt động miễn là FirstActivity là khoảng (tức là nó không bị hủy). Tuy nhiên, vẫn còn một điểm quan trọng: trong trường hợp thay đổi cấu hình (ví dụ xoay màn hình) không được xử lý rõ ràng sẽ khiến hoạt động khởi động lại và dịch vụ sẽ bị hủy (vì chúng tôi đang gọi stopService() trong onDestroy()) .

Để tránh điều này, bạn có thể kiểm tra isChangingConfigurations() trước khi thực sự dừng dịch vụ (kể từ khi một onDestroy() gọi lại xảy ra vì lý do này có nghĩa là mặc dù dụ cụ thể của hoạt động đang được phá hủy, nó sẽ được tái tạo sau đó.

Do đó, giải pháp đầy đủ sẽ là một cái gì đó như:

public class FirstActivity extends Activity 
{ 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     startService(new Intent(this, MyService.class)); 
    } 

    private ServiceConnection mServiceConnection = new ServiceConnection() { ... } 

    @Override 
    protected void onStart() { 
     super.onStart(); 
     bindService(new Intent(this, MyService.class), mServiceConnection, Context.BIND_AUTO_CREATE); 
    } 

    @Override 
    protected void onStop() { 
     unbindService(mServiceConnection); 
     super.onStop(); 
    } 

    @Override 
    protected void onDestroy() { 
     if (!isChangingConfigurations()) 
      stopService(new Intent(this, MyService.class)); 

     super.onDestroy(); 
    } 

trong khi SecondActivity sẽ chỉ thực hiện onStart()/onStop() phương pháp (trong cùng đường).


Một vài ghi chú về việc thực hiện cụ thể của bạn:

  • Đó không phải là cần thiết để ghi đè onBackPressed(), vì nếu hoạt động này bị phá hủy các phương pháp vòng đời cần thiết sẽ được gọi là (cộng, nó có thể được hoàn thành mà không cần nhấn nút quay lại, ví dụ: nếu gọi finish() trên đó).
  • Dừng dịch vụ ở onDestroy() thay vì onPause() giúp bạn không phải kiểm tra isUserMovingToSecondActivity.
+0

Xin cảm ơn! (1) Với mục đích của chúng tôi, bạn có thể sử dụng 'onStart()'/'onStop()' và 'onResume()'/'onPause()' thay thế cho nhau, đúng không? Nếu không, cặp phương pháp thứ hai có vẻ ưu việt hơn vì nó được bảo đảm * được gọi, trái ngược với cặp đầu tiên, phải không? (2) Kiểm tra 'isChangingConfigurations()' có thực sự tạo sự khác biệt không? Nếu 'FirstActivity' bị hủy, chúng ta sẽ mất biến thành viên' mMyService', và 'onCreate (...)' và 'onStart()' được gọi lại (cũng có nghĩa là bạn có thể kết buộc hai lần). Và trong 'SecondActivity', chúng tôi mất kết nối trong mọi trường hợp. – caw

+1

@MarcoW. (1) 'onStop()' có thể không đến, nhưng AFAIK chỉ áp dụng nếu ứng dụng bị giết, trong trường hợp đó dịch vụ cũng vậy. (2) Bạn sẽ mất liên kết cục bộ, nhưng dịch vụ không thực sự bị phá hủy và sau đó được tạo lại khi bạn liên kết lại (vì vậy, nếu bạn có một số tiến trình liên tục, nó sẽ vẫn "ở đó"). Tuy nhiên, nó sẽ là nếu bạn gọi 'stopService()'. Tôi cho rằng bạn muốn giữ trạng thái dịch vụ khi xoay vòng. – matiash

+0

Về (2), khi 'onStop()' được gọi trong 'SecondActivity',' Service' có thể bị giết (vì không có 'Activity' nào liên kết với nó nữa và tất cả' Activity 'người gọi' startService (...) 'đã gọi' stopService (...) ') trước khi bạn có thể liên kết lại trong' onStart() 'sau khi thay đổi cấu hình. Liệu tôi có sai? – caw

Các vấn đề liên quan