我需要在我的應用程序中從外部硬件無限期地收聽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線程。
請幫忙?
如果您有需要執行的特定操作,請使用IntentService而不是 – Zoe
https://developer.android.com/reference/android/os/Messenger.html – tynn
@LunarWatcher這看起來像是一個很有前途的解決方案。我可以以同樣的方式使用bindind嗎?該文檔有一個onBind()方法,但因爲我現在正在處理意圖,所以它看起來好像處理方式不同 –