Androidアプリケーションの開発中、私は(私の意見では)非常に奇妙な動作を見つけました。 メッセージオブジェクト(android.os.Message)を別のスレッドに渡すと、その内容はすべて失われます。誰かがおそらくなぜこれが起こっているのかを私に説明することができますか?私はこの問題を説明するためにサンプルアプリケーションを書いた:メッセージが別のスレッドに渡されたときに内容が失われるのはなぜですか?
MainActivity:
package com.test.bundletest;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
private Messenger mOutMsger;
private final ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mOutMsger = new Messenger(service);
System.out.println("Connected");
sendMultipleMessages(10);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startService(new Intent(this, MyService.class));
bindService(new Intent(this, MyService.class), mConnection, BIND_AUTO_CREATE);
}
private void sendMultipleMessages(int messageCount){
if (mOutMsger!=null){
for (int i = 0; i<messageCount; i++){
Message msg = Message.obtain();
Bundle b = new Bundle();
b.putString("test", "Just a test");
msg.setData(b);
msg.what = i;
try {
mOutMsger.send(msg);
System.out.println("Message sent");
} catch (RemoteException e) {
e.printStackTrace();
}
}
}else {
System.out.println("Messenger was null");
}
}
}
サービス:
package com.test.bundletest;
import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyService extends Service {
private ExecutorService mExe = Executors.newSingleThreadExecutor();
@SuppressLint("HandlerLeak")
private final Handler mInHandler = new Handler(){
@Override
public void handleMessage(final Message msg) {
System.out.println(
new StringBuilder(" UI Thread - What? - ")
.append(msg.what)
.append("Data? - ")
.append(msg.peekData() == null)
.append(" KeySet size? - ")
.append(msg.getData().keySet().size()));
mExe.submit(new Runnable() {
@Override
public void run() {
System.out.println(
new StringBuilder(" NonUI Thread - What? - ")
.append(msg.what)
.append("Data? - ")
.append(msg.peekData() == null)
.append(" KeySet size? - ")
.append(msg.getData().keySet().size()));
}
});
}
};
private final Messenger mInMessenger = new Messenger(mInHandler);
@Override
public IBinder onBind(Intent intent) {
return mInMessenger.getBinder();
}
}
出力:
8751-8751/com.test.bundletest I/System.out: Connected
8751-8751/com.test.bundletest I/System.out: Message sent
8751-8751/com.test.bundletest I/System.out: Message sent
8751-8751/com.test.bundletest I/System.out: Message sent
8751-8751/com.test.bundletest I/System.out: Message sent
8751-8751/com.test.bundletest I/System.out: Message sent
8751-8751/com.test.bundletest I/System.out: Message sent
8751-8751/com.test.bundletest I/System.out: Message sent
8751-8751/com.test.bundletest I/System.out: Message sent
8751-8751/com.test.bundletest I/System.out: Message sent
8751-8751/com.test.bundletest I/System.out: Message sent
8751-8751/com.test.bundletest I/System.out: UI Thread - What? - 0Data? - false KeySet size? - 1
8751-8751/com.test.bundletest I/System.out: UI Thread - What? - 1Data? - false KeySet size? - 1
8751-8751/com.test.bundletest I/System.out: UI Thread - What? - 2Data? - false KeySet size? - 1
8751-8751/com.test.bundletest I/System.out: UI Thread - What? - 3Data? - false KeySet size? - 1
8751-8751/com.test.bundletest I/System.out: UI Thread - What? - 4Data? - false KeySet size? - 1
8751-8751/com.test.bundletest I/System.out: UI Thread - What? - 5Data? - false KeySet size? - 1
8751-8751/com.test.bundletest I/System.out: UI Thread - What? - 6Data? - false KeySet size? - 1
8751-8751/com.test.bundletest I/System.out: UI Thread - What? - 7Data? - false KeySet size? - 1
8751-8751/com.test.bundletest I/System.out: UI Thread - What? - 8Data? - false KeySet size? - 1
8751-8751/com.test.bundletest I/System.out: UI Thread - What? - 9Data? - false KeySet size? - 1
8751-8809/com.test.bundletest I/System.out: NonUI Thread - What? - 0Data? - true KeySet size? - 0
8751-8809/com.test.bundletest I/System.out: NonUI Thread - What? - 0Data? - true KeySet size? - 0
8751-8809/com.test.bundletest I/System.out: NonUI Thread - What? - 0Data? - true KeySet size? - 0
8751-8809/com.test.bundletest I/System.out: NonUI Thread - What? - 0Data? - true KeySet size? - 0
8751-8809/com.test.bundletest I/System.out: NonUI Thread - What? - 0Data? - true KeySet size? - 0
8751-8809/com.test.bundletest I/System.out: NonUI Thread - What? - 0Data? - true KeySet size? - 0
8751-8809/com.test.bundletest I/System.out: NonUI Thread - What? - 0Data? - true KeySet size? - 0
8751-8809/com.test.bundletest I/System.out: NonUI Thread - What? - 0Data? - true KeySet size? - 0
8751-8809/com.test.bundletest I/System.out: NonUI Thread - What? - 0Data? - true KeySet size? - 0
8751-8809/com.test.bundletest I/System.out: NonUI Thread - What? - 0Data? - true KeySet size? - 0
それも見知らぬ人だと私はメッセージをコピーする場合それを処理する直前に、これは起こらない:
package com.test.bundletest;
import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyService extends Service {
private ExecutorService mExe = Executors.newSingleThreadExecutor();
@SuppressLint("HandlerLeak")
private final Handler mInHandler = new Handler(){
@Override
public void handleMessage(final Message msg) {
System.out.println(
new StringBuilder(" UI Thread - What? - ")
.append(msg.what)
.append("Data? - ")
.append(msg.peekData() == null)
.append(" KeySet size? - ")
.append(msg.getData().keySet().size()));
final Message msg2 = Message.obtain(msg);
mExe.submit(new Runnable() {
@Override
public void run() {
System.out.println(
new StringBuilder(" NonUI Thread - What? - ")
.append(msg2.what)
.append("Data? - ")
.append(msg2.peekData() == null)
.append(" KeySet size? - ")
.append(msg2.getData().keySet().size()));
}
});
}
};
private final Messenger mInMessenger = new Messenger(mInHandler);
@Override
public IBinder onBind(Intent intent) {
return mInMessenger.getBinder();
}
}
このように実行すると、UIとNON UIスレッドの出力は同じになります。
私はJavaの知識の末尾にあり、誰かがこれを私に理解してもらえると願っています。
ありがとうございました!正確に記述された方法であるように見えます。メッセージオブジェクトは、handleMessage(Message msg)が終了した後にリサイクルされます。メソッドの終了を遅らせると、データは保持されます。この手順は明らかに文書には記載されていないのは残念です。 – JCoder