2010-07-14 39 views
11

Mặc dù similar question was asked, tôi có tình huống differnet: Ứng dụng của tôi bao gồm chủ yếu là nền Service. Tôi muốn bắt đầu các hoạt động bên ngoài và nhận lại kết quả.Tương tự của startActivityForResult cho Dịch vụ

tôi thấy một số tùy chọn:

  1. Tạo hình nộm Activity và giữ tham chiếu đến nó cho việc sử dụng startActivityForResult của nó. Điều này tiêu thụ khá nhiều bộ nhớ, như chúng ta biết.

  2. Sử dụng Broadcast Intents thay vì cơ sở hạ tầng kết quả của Android: yêu cầu các hoạt động của khách hàng phát sóng kết quả của họ trước khi đóng. Loại phá vỡ ý tưởng và không hiệu quả như vậy.

  3. Sử dụng trực tiếp Instrumentation - thử sao chép mã từ startActivityForResult vào Dịch vụ của tôi.

  4. Sử dụng giao diện Dịch vụ - tuần tự hóa và thêm AIDL kết nối với Intent để bắt đầu Hoạt động. Trong trường hợp này, Activity nên call Service directly thay vì cung cấp kết quả.

Cách tiếp cận thứ ba cảm thấy gần gũi hơn với Android đối với tôi, nhưng tôi không chắc chắn nếu nó có thể làm - Dịch vụ không có Instrumentation của nó, và thực hiện mặc định dường như luôn luôn trả về null.

Có thể bạn có bất kỳ ý tưởng nào khác không?

+0

Nó có thể đạt được với một hack đơn giản, bằng cách sử dụng SharedPreferences, [SO] (http://stackoverflow.com/a/31461941/4859873) –

Trả lời

3

Tôi nghĩ tùy chọn 2 là cách thành ngữ nhất trên Android. Sử dụng startActivityForResult từ một số Activity là một cuộc gọi đồng bộ/chặn, nghĩa là hoạt động của phụ huynh sẽ chờ và không làm bất cứ điều gì cho đến khi trẻ hoàn thành. Khi làm việc từ một Service và tương tác với các hoạt động của bạn chủ yếu là thực hiện các cuộc gọi không đồng bộ/không chặn, tức là dịch vụ sẽ thực hiện một số công việc và sau đó đợi tín hiệu báo hiệu rằng nó có thể tiếp tục.

Nếu bạn đang sử dụng android local service pattern thì bạn có thể có hoạt động của mình có được tham chiếu đến Service và sau đó gọi một chức năng cụ thể sau khi nó đã thực hiện công việc của mình. Việc thử tùy chọn 3 của bạn sẽ phản đối những gì khung cung cấp cho bạn.

+1

Cảm ơn những suy nghĩ của bạn! Bây giờ tôi đang lựa chọn giữa 2 (dễ thực hiện hơn) và 4 (an toàn hơn/riêng tư và phải nhanh hơn). Tôi không thực sự đồng ý rằng startActivityForResult đang chặn (vì nó sử dụng chức năng gọi lại, không phải giá trị kết quả), và cũng là Thiết bị đo đạc trong API công cộng =) Cảm ơn! –

+1

Tôi có nghĩa là nó không bị chặn theo nghĩa truyền thống (ví dụ: chặn cuộc gọi io). Nó chặn theo cách thức khái niệm mà bạn sử dụng nó. – Qberticus

+0

@Qberticus Liên kết mà bạn cung cấp chỉ liên kết đến trang mẫu chung. –

16

Tôi đã suy nghĩ về điều này gần đây khi triển khai account authenticators với luồng ủy quyền ba bên. Gửi kết quả trở lại dịch vụ để xử lý hoạt động tốt hơn xử lý nó trong hoạt động. Nó cũng cung cấp một sự phân tách mối quan tâm tốt hơn.

Nó không phải là tài liệu rõ ràng, nhưng Android cung cấp một cách dễ dàng để gửi và nhận kết quả ở bất cứ nơi nào (bao gồm cả dịch vụ) với ResultReceiver.

Tôi thấy nó sạch hơn nhiều so với các hoạt động xung quanh, vì điều đó luôn đi kèm với nguy cơ rò rỉ các hoạt động đó. Ngoài ra, gọi các phương thức cụ thể ít linh hoạt hơn.

Để sử dụng ResultReceiver trong một dịch vụ, bạn sẽ cần phải phân lớp nó và cung cấp một cách để xử lý các kết quả nhận được, thường trong một lớp bên trong:

public class SomeService extends Service { 

    /** 
    * Code for a successful result, mirrors {@link Activity.RESULT_OK}. 
    */ 
    public static final int RESULT_OK = -1; 

    /** 
    * Key used in the intent extras for the result receiver. 
    */ 
    public static final String KEY_RECEIVER = "KEY_RECEIVER"; 

    /** 
    * Key used in the result bundle for the message. 
    */ 
    public static final String KEY_MESSAGE = "KEY_MESSAGE"; 

    // ... 

    /** 
    * Used by an activity to send a result back to our service. 
    */ 
    class MessageReceiver extends ResultReceiver { 

     public MessageReceiver() { 
      // Pass in a handler or null if you don't care about the thread 
      // on which your code is executed. 
      super(null); 
     } 

     /** 
     * Called when there's a result available. 
     */ 
     @Override 
     protected void onReceiveResult(int resultCode, Bundle resultData) { 
      // Define and handle your own result codes 
      if (resultCode != RESULT_OK) { 
       return; 
      } 

      // Let's assume that a successful result includes a message. 
      String message = resultData.getString(KEY_MESSAGE); 

      // Now you can do something with it. 
     } 

    } 

} 

Khi bạn bắt đầu một hoạt động trong dịch vụ, tạo một máy thu kết quả và đóng gói nó vào extras ý:

/** 
* Starts an activity for retrieving a message. 
*/ 
private void startMessageActivity() { 
    Intent intent = new Intent(this, MessageActivity.class); 

    // Pack the parcelable receiver into the intent extras so the 
    // activity can access it. 
    intent.putExtra(KEY_RECEIVER, new MessageReceiver()); 

    startActivity(intent); 
} 

và cuối cùng, trong hoạt động, giải nén các máy thu và sử dụng ResultReceiver#send(int, Bundle) để gửi kết quả trở lại.

Bạn có thể gửi kết quả là bất cứ lúc nào, nhưng ở đây tôi đã chọn để làm điều đó trước khi kết thúc:

public class MessageActivity extends Activity { 

    // ... 

    @Override 
    public void finish() { 
     // Unpack the receiver. 
     ResultReceiver receiver = 
       getIntent().getParcelableExtra(SomeService.KEY_RECEIVER); 

     Bundle resultData = new Bundle(); 

     resultData.putString(SomeService.KEY_MESSAGE, "Hello world!"); 

     receiver.send(SomeService.RESULT_OK, resultData); 

     super.finish(); 
    } 

} 
+0

cảm ơn vì giải pháp! một điều: RESULT_OK phải là ** - 1 ** theo Activity.java – Philipp

+0

Điểm tốt. Tôi nghĩ trong trường hợp này, bạn có thể sử dụng bất kỳ giá trị nào, nhưng tốt hơn là nên nhất quán với bất kỳ nền tảng nào cung cấp. Tôi đã cập nhật câu trả lời. Bạn cũng có thể sử dụng Activity.RESULT_OK trực tiếp. –

+0

bạn cần phải thêm '@SuppressLint (" ParcelCreator ")' trước lớp 'MessageReceiver' nếu không nó sẽ yêu cầu bạn tạo một CREATOR như [ResultReceiver] (https://developer.android.com/reference/android/os/ ResultReceiver.html) triển khai Parcelable. Cảm ơn câu trả lời. – ArJ

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