2017-04-17 18 views
0

我需要在我的應用程序中從外部硬件無限期地收聽key-presses,並且要這樣做,我希望創建一個bound service,只要我的應用程序正在運行,就可以完成這項工作。Android:如何在服務中啓動一個新的線程(並將結果發送回我的活動)?

問題是,這項工作需要在單獨的thread上完成,到目前爲止,我只能通過我的服務將預設值傳回給我的activity。在做了一些調查之後,我明白這是因爲服務默認在ui thread上運行。

...但是,如果我在服務中運行我的線程,我不知道如何將處理後的結果發送回我的活動。

當我試圖直接做在活動這個過程中,我只想用 runOnUiThread()方法儘快更新文本視圖作爲按鍵進行處理,但由於我使用的是 service現在我也不

返回有權訪問該方法。

DeviceService類使用一個處理程序和Messenger從客戶端活動接收響應:

class IncomingHandler extends Handler { 

    @Override 
    public void handleMessage(Message msg) { 

     switch (msg.what) { 

      case (MSG_START_REST): 

       // This starts a worker thread. 
       // I DON'T KNOW HOW TO GET THE RESULT BACK TO THE UI THREAD 
       Log.v(TAG, "Starting listening for keypad"); 
       startREST(msg); 

       // THIS IS WHERE I'M HAVING TROUBLE 
       // I want to set this to the result of the above call... 
       String keyPressed = "ice cream"; 

       try { 
        // Response 
        Message keyResponse = Message.obtain(null, KEYPRESS); 
        Bundle bundle = new Bundle(); 
        bundle.putString("keyPressed", keyPressed); 
        keyResponse.setData(bundle); 
        msg.replyTo.send(keyResponse); 
       } catch (RemoteException e) { 
        e.printStackTrace(); 
       } 

       break; 

      // This works. 
      case (TO_UPPERCASE): 
       try { 
        // Incoming data 
        String data = msg.getData().getString("data"); 

        // Response 
        Message resp = Message.obtain(null, TO_UPPERCASE_RESPONSE); 
        Bundle bResp = new Bundle(); 
        bResp.putString("respData", data.toUpperCase()); 
        resp.setData(bResp); 
        msg.replyTo.send(resp); 
       } catch (RemoteException e) { 
        e.printStackTrace(); 
       } 
       break; 

      default: 
       super.handleMessage(msg); 
     } 
} 

// Target we publish for clients to send messages to IncomingHandler. 
final Messenger mMessenger = new Messenger(new IncomingHandler()); 

我不會讓我的所有線程處理的(正常工作),但這裏是它完成和得到它的結果。它傳遞一行json,從中提取鍵碼。

同樣,我的問題是我不知道如何獲得這個鍵碼回到我的活動。

private void sendKeyboardEvent(final String keyboardEvent) { 

    Log.v(TAG, "Keyboard event : " + keyboardEvent); 

    // Parse json to find keycode 
    JSONObject jsonObject = null; 
    try { 
     jsonObject = new JSONObject(keyboardEvent); 

     // THIS IS THE KEYCODE. IT WILL BE SOMETHING LIKE "30" or "31" 
     String keycode = jsonObject.getString("pressedKeycodes"); 
     Log.v(TAG, "Keycode : " + keycode); 

    } catch (JSONException e) { 
     e.printStackTrace(); 
    } 
} 

我的MainActivity也有一個處理程序和信使來解釋服務的響應。

// Handler of incoming messages from clients. 
class ResponseHandler extends Handler { 

    @Override 
    public void handleMessage(Message msg) { 

     switch (msg.what) { 

      case (DeviceService.KEYPRESS): 
       String result4 = msg.getData().getString("keyPressed"); 
       Toast.makeText(getApplicationContext(), "A key was pressed! -"+ result4, Toast.LENGTH_SHORT).show(); 
       break; 

      case (DeviceService.TO_UPPERCASE_RESPONSE): 
       String result = msg.getData().getString("respData"); 
       TextView tvResult = (TextView) findViewById(R.id.textView_result); 
       tvResult.setText(result); 
       break; 

      default: 
       super.handleMessage(msg); 
     } 
    } 
} 

這裏是我撥打服務的地方。這似乎也很好。

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    Button btnResult = (Button) findViewById(R.id.btnResult); 
    btnResult.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      String val = "hello"; 
      Message msg = Message.obtain(null, DeviceService.TO_UPPERCASE); 
      msg.replyTo = new Messenger(new ResponseHandler()); 

      Bundle b = new Bundle(); 
      b.putString("data", val); 
      msg.setData(b); 

      try { 
       mService.send(msg); 
      } catch (RemoteException e) { 
       e.printStackTrace(); 
      } 
     } 
    }); 

    Button btnStart = (Button) findViewById(R.id.btn_start_keypad_listener); 
    btnStart.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      Message msg = Message.obtain(null, DeviceService.MSG_START_REST); 
      msg.replyTo = new Messenger(new ResponseHandler()); 

      try { 
       mService.send(msg); 
      } catch (RemoteException e) { 
       e.printStackTrace(); 
      } 
     } 
    }); 
} 

Tldr,我需要將結果從運行在我的MainActivity外面的線程發回到我的MainActivity和UI線程。

請幫忙?

+0

如果您有需要執行的特定操作,請使用IntentService而不是 – Zoe

+0

https://developer.android.com/reference/android/os/Messenger.html – tynn

+0

@LunarWatcher這看起來像是一個很有前途的解決方案。我可以以同樣的方式使用bindind嗎?該文檔有一個onBind()方法,但因爲我現在正在處理意圖,所以它看起來好像處理方式不同 –

回答

2

如果您需要保持服務和活動解耦,Android允許您使用廣播。您可以檢查:https://developer.android.com/guide/components/broadcasts.html 就您的情況而言,活動將會註冊以等待您的服務發送廣播,以便您的服務完成作業或任何任務時可以發送將監聽您的活動的廣播。 這裏有一個樣本:Using a broadcast intent/broadcast receiver to send messages from a service to an activity 希望它有幫助。

+0

廣播接收器工作!我在sendKeyboardEvent()方法中發送了一個廣播,並在我的活動中進行了監聽。當我的活動得到廣播時,我可以做任何我想用它的東西。謝謝! –

+0

歡迎你! –

相關問題