2017-11-05 5 views
1

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の知識の末尾にあり、誰かがこれを私に理解してもらえると願っています。

答えて

1

グローバルプールから新しいMessageインスタンスを返すMessage.obtain();を使用します。

新しいスレッドを作成すると、メソッドhandleMessage(Message msg)が実行を終了し、依然としてグローバルプールに属するオブジェクトMessageがリサイクルされています。

@Override 
public void handleMessage(Message msg) { 
    final Message message = new Message(); 
    message.copyFrom(msg); 
    //your code 
} 

それとも、独自のカスタムオブジェクトにMessageオブジェクトをマッピングすることができますので、新しいスレッドでこのオブジェクトは、あなたがこれを行うことができ、あなたのサービスでは、既に空

です。 Messageオブジェクトは、データ転送にのみ使用してください。Handler

+0

ありがとうございました!正確に記述された方法であるように見えます。メッセージオブジェクトは、handleMessage(Message msg)が終了した後にリサイクルされます。メソッドの終了を遅らせると、データは保持されます。この手順は明らかに文書には記載されていないのは残念です。 – JCoder

関連する問題