2010-07-14 86 views
11

儘管similar question was asked,我有不同的情況: 我的應用程序主要由背景Service組成。我想開始外部活動並取回結果。模擬startActivityForResult服務

我看到幾個選項:

  1. 創建虛擬Activity,並保持對它的引用使用其startActivityForResult。正如我們所知,這消耗了相當多的內存。

  2. 使用Broadcast Intents,而不是Android的成果基礎設施:要求客戶活動,在關閉之前播出他們的結果。這種打破想法並不如此高效。

  3. 使用Instrumentation直接 - 嘗試從startActivityForResult複製代碼到我的服務。

  4. 使用服務接口 - 序列化和增加AIDL連接到意向啓動的活動。在這種情況下,活動應該call Service directly而不是提供結果。

第三種方法更接近的感覺到Android我,但我不知道是否有可能做的事情 - 服務不具有其儀器儀表,以及默認的實現似乎總是返回null。

也許您有任何其他想法?

+0

它可以用一個簡單的黑客來實現,通過使用SharedPreferences的,[SO]( http://stackoverflow.com/a/31461941/4859873) – 2015-07-16 18:46:48

回答

3

我認爲選項2是Android上最習慣的方式。使用來自ActivitystartActivityForResult是同步/阻塞調用,即,父活動等待並且在孩子完成之前不做任何事情。從Service開始工作並與主要進行異步/非阻塞調用的活動進行交互時,即服務要求完成一些工作,然後等待信號告訴它可以繼續。

如果您使用的是android local service pattern,那麼您可以讓您的活動獲得Service的引用,然後在其執行完工作後調用特定的函數。嘗試您的選項3將與該框架爲您提供的內容相抵觸。

+1

感謝您的想法!現在我選擇2(更容易實施)和4(更安全/私密,應該更快)。 我不完全同意startActivityForResult是阻塞的(因爲它使用回調函數,而不是結果值),而且Instrumentation是在公共API =) 謝謝! – 2010-07-14 21:16:33

+1

我的意思是它不是傳統意義上的阻塞(例如阻塞io呼叫)。它阻礙了你使用它的概念性方式。 – Qberticus 2010-07-14 21:53:13

+0

@Qberticus您提供的鏈接只是指向通用示例頁面的鏈接。 – 2014-08-29 14:58:14

16

實施account authenticators有三條腿的授權流程,當我最近一直在思考這個問題。將結果發送回服務進行處理比在活動中處理結果要好。它還提供了更好的問題分離。

它不是那麼明確記載,但Android提供了一個簡單的方法來與ResultReceiver任何地方發送和接收結果(包括服務)。

我發現它比傳遞活動要乾淨得多,因爲這總會帶來泄漏這些活動的風險。另外,調用具體的方法不夠靈活。

要在服務中使用ResultReceiver,你需要繼承它,並提供一種方法來處理接收到的結果,通常是在一個內部類:

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. 
     } 

    } 

} 

當你在服務啓動的活動,創建一個結果接收機,它包入意圖演員:

/** 
* 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); 
} 

最後,在活動中,解包接收器,並使用ResultReceiver#send(int, Bundle)一個結果送回去。

您可以隨時發送結果,但在這裏我選擇了做整理之前:

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

感謝您的解決方案!一件事:RESULT_OK應該是** - 1 **根據Activity.java – Philipp 2016-03-31 21:30:22

+0

好點。我認爲在這種情況下可以使用任何值,但最好與平臺提供的任何值保持一致。我已經更新了答案。你也可以直接使用Activity.RESULT_OK。 – 2016-04-02 21:10:42

+0

您需要在類MessageReceiver前添加@SuppressLint(「ParcelCreator」),否則它會要求您將CREATOR設置爲[ResultReceiver](https://developer.android.com/reference/android/os/) ResultReceiver.html)實現Parcelable。感謝你的回答。 – ArJ 2016-07-27 08:24:42