23

Trong ứng dụng Android của tôi, tôi có chế độ xem danh sách đơn giản với bộ điều hợp. Có một truy vấn nặng để lấp đầy chế độ xem danh sách với dữ liệu. Vì vậy, tôi đặt nó vào một IntentService chạy trong một chủ đề khác.Bắt đầu IntentService từ Hoạt động và làm mới Hoạt động khi IntentService được hoàn thành

IntentService thường chạy riêng rẽ, chỉ để truy vấn một số dữ liệu và chèn nó vào cơ sở dữ liệu SQLite.

Nhưng bây giờ tôi muốn có khả năng sau đây:

  1. Các hoạt động khởi động IntentService với startService().
  2. IntentService thực hiện công việc nặng nhọc của nó.
  3. Khi IntentService kết thúc, nó sẽ thông báo cho hoạt động về kết quả để hoạt động có thể được làm mới để hiển thị dữ liệu mới.

Điều này có khả thi không? Tôi đọc rất nhiều câu hỏi ở đây về Stack Overflow về chủ đề này. Nhưng trong mọi câu hỏi, có một giải pháp khác. Vì vậy, tôi muốn hỏi tất cả các bạn: Giải pháp nào là tốt nhất cho mục đích của tôi?

  • Ràng buộc IntentService vào hoạt động dường như không phải là giải pháp tốt nhất vì có thể có xung đột với thay đổi cấu hình hoạt động, v.v.
  • This blog post đề xuất sử dụng AIDL với các kiện hàng - nghe có vẻ rất phức tạp đối với tôi. Có một cách dễ dàng hơn, phải không?
  • Người ta có thể thiết lập bộ thu phát sóng trong hoạt động và kích hoạt phát sóng này trong IntentService khi nó kết thúc.
  • Một số người nói rằng bạn nên use createPendingResult() to pass a PendingIntent cho IntentService. Nếu IntentService tìm thấy PendingIntent trong phần bổ sung của nó, nó sử dụng nó để kích hoạt onActivityResult() trong Activity. Đây có phải là cách để lựa chọn không?

Trả lời

21

Ví dụ: tôi sử dụng ResultReceiver để gọi notifyDataSetChanged() trên bộ điều hợp của Activity của tôi (mở rộng ListActivity). Nó có thể được điều chỉnh để làm bất cứ điều gì bạn cần.

đang ResultReceiver:

public class MyResultReceiver extends ResultReceiver { 

    private Context context = null; 

    protected void setParentContext (Context context) { 
     this.context = context; 
    } 

    public MyResultReceiver(Handler handler) { 
     super(handler); 
    } 

    @Override 
    protected void onReceiveResult (int resultCode, Bundle resultData) { 

     // Code to process resultData here 

     ((BaseAdapter) ((ListActivity)context).getListAdapter()).notifyDataSetChanged(); 
    } 
} 

đang MyActivity:

public class MyActivity extends ListActivity { 

    private MyResultReceiver theReceiver = null; 

    ... 

    private void callService() { 
     theReceiver = new MyResultReceiver(new Handler()); 
     theReceiver.setParentContext(this); 
     Intent i = new Intent("com.mycompany.ACTION_DO_SOMETHING"); 

     // Code to define and initialize myData here 

     i.putExtra("someData", myData); 
     i.putExtra("resReceiver", theReceiver); 
     startService(i); 

    } 
} 

đang IntentService:

Bundle resultBundle = new Bundle(); 
ResultReceiver resRec = intent.getParcelableExtra("resReceiver"); 

// Do some work then put some stuff in resultBundle here 

resRec.send(12345, resultBundle); 
+0

Cảm ơn bạn rất nhiều vì giải pháp này và mô tả chi tiết! Tôi có phải đăng ký ResultReceiver hoặc Mục đích tùy chỉnh trong tệp kê khai Android không? Và tôi có thể đặt những thứ như một ArrayList hoặc một con trỏ vào gói kết quả? Tôi có cần bưu kiện ở đó không? – caw

+0

Trình kết quả không cần phải được đăng ký trong tệp kê khai nhưng tôi có mục đích tùy chỉnh đã đăng ký cho mục đích của mình. Bạn có thể gọi IntentService theo bất kỳ cách nào bạn muốn miễn là có một Intent để truyền ResultReceiver. Đối với resultBundle bạn có thể đặt bất cứ thứ gì trong đó một Bundle có thể xử lý. – Squonk

+0

Điều thú vị là hai chủ đề tương tự đều có giải pháp được chấp nhận bằng cách sử dụng ResultReceiver, nhưng cách chính thức có vẻ là LocalBroadcastManager. Tôi nghĩ rằng lý do mà LocalBroadcastManager là thích hợp hơn vì ResultReceiver có thể bị phá hủy nếu hoạt động bị phá hủy và sau đó khởi động lại? –

3

Tôi khuyên bạn nên sử dụng Bộ thu phát sóng trong Hoạt động chờ kết quả. Dịch vụ của bạn sẽ chỉ sử dụng sendBroadcast với tùy chỉnh Intent.

+0

Cảm ơn bạn! Nhưng không phải điều này cũng hơi quá mức vì chương trình phát sóng có sẵn trên toàn hệ thống (đối với tất cả các ứng dụng) không? – caw

+0

Tôi nghĩ rằng có nhiều cách không phát sóng cho toàn bộ hệ thống. Và nếu bạn muốn chạy dịch vụ trong một quy trình khác, nó sẽ là một cách giao tiếp đơn giản. –

+2

[LocalBroadcastManager] (http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html) là đối tượng mà bạn cần tạo một chương trình phát sóng bên trong ứng dụng của bạn. – AlexSanchez

10

Khi IntentService hoàn tất, nó sẽ sử dụng LocalBroadcastManager để gửi một ý định bất kỳ đăng ký Hoạt động.

Các IntentService sẽ chứa mã như thế này:

private void sendBroadcast() { 
    Intent intent = new Intent("myBroadcastIntent"); 
    intent.putExtra("someName", someValue); 
    LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 
} 

Các hoạt động nhận được thông báo sẽ chứa mã như thế này:

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    // ... 
    BroadcastReceiver receiver = new BroadcastReceiver() { 
     @Override 
     public void onReceive(Context context, Intent intent) { 
      String someValue = intent.getStringExtra("someName"); 
      // ... do something ... 
     } 
    }; 
    LocalBroadcastManager.getInstance(this) 
     .registerReceiver(receiver, new IntentFilter("myBroadcastIntent")); 
} 

Đối với chiều sâu hơn, hãy xem các bài viết trên blog Using LocalBroadcastManager In Service To Activity Communications.

11

Không có câu trả lời khác tham chiếu tài liệu android chính thức

https://developer.android.com/training/run-background-service/report-status.html

đó nêu rõ rằng đối với truyền thông Hoạt động-IntentService "Cách khuyến khích để gửi và nhận tình trạng là sử dụng một LocalBroadcastManager, làm hạn chế phát các đối tượng Intent đến các thành phần trong ứng dụng của riêng bạn "!

+0

cảm ơn vì đã trỏ đến tài liệu chính thức –

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