2017-05-17 4 views
4

this articleを使用して非同期UDPソケットを作成しようとしています。このメッセージはまだ使用中のためリサイクルできません

だから私はこのコードをしました:

import android.os.Handler; 
import android.os.HandlerThread; 
import android.os.Message; 

import java.net.DatagramSocket; 
import java.net.SocketException; 

public class UdpThread 
    extends HandlerThread { 

    private static final String TAG = "UDP"; 
    private final Handler uiHandler, workerHandler; 
    private final DatagramSocket socket = new DatagramSocket(); 

    public UdpThread(final Handler uiHandler, final String hostname, final int port) throws SocketException { 
     super(TAG); 
     this.uiHandler = uiHandler; 
     start(); 
     workerHandler = new Handler(getLooper(), new Handler.Callback() { 
      @Override 
      public boolean handleMessage(final Message msg) { 
       /* 
       if (msg.what == port && msg.obj == hostname) { 
        final InetSocketAddress address = new InetSocketAddress(hostname, port); 
        Log.d(TAG, "Connecting to " + address); 
        try { 
         socket.connect(address); 
        } catch (SocketException se) { 
         throw new RuntimeException(se); 
        } 
       } 
       */ 
       msg.recycle(); //java.lang.IllegalStateException: This message cannot be recycled because it is still in use. 
       return true; 
      } 
     }); 
     workerHandler.obtainMessage(port, hostname).sendToTarget(); 
    } 
} 

をしかし、私は、コードを実行するときにメッセージをリサイクルしようとしたとき、私が述べたjava.lang.IllegalStateException: This message cannot be recycled because it is still in use.を取得します。なぜそれを解決してメモリリークを防ぐのか?

+1

msg.recycle(); 

を置き換える私は考えていませんあなたはリサイクル –

+0

を使用する必要がありますこれは正しいようです。私がメッセージのスパムを開始しても、メモリ消費は平らに見えます。 – Pitel

答えて

3

すべてのまあ最初はMessagerecycle()方法がどのように動作するかを確認することができます。それが使用されている場合

public void recycle() { 
    if (isInUse()) { 
     if (gCheckRecycle) { 
      throw new IllegalStateException("This message cannot be recycled because it " 
        + "is still in use."); 
     } 
     return; 
    } 
    recycleUnchecked(); 
} 

だからあなたが IllegalStateExceptionを取得している

isInUse()だけフラグをチェックし、次のようになります。

boolean isInUse() { 
     return ((flags & FLAG_IN_USE) == FLAG_IN_USE); 
    } 

そして、我々はそのフラグについて読んしようとすると、私たちは説明を参照してください。

設定されたメッセージが使用中の場合。

このフラグは、メッセージがエンキューされたときに設定され、 が配信されてからリサイクルされたときに設定されたままになります。アプリケーションが メッセージの内容を変更することが許可されるのは、 なので、新しいメッセージが作成または取得されたときにフラグが唯一 にクリアされます。

すでに使用中のメッセージ をエンキューまたはリサイクルしようとするとエラーが発生します。

それでは、私たちは

  1. 持っているあなたは、その "使用中" までカントリサイクルメッセージ
  2. 新しいメッセージが得られたり

を作成するまでは、 "使用中" であります問題の解決方法

メッセージオブジェクトをリサイクルするには、メッセージクラス内にメソッドrecycleUnchecked()があります。使用している場合でもが必要です。それの説明:

リサイクルa使用中の可能性があるメッセージ。

キューに入れられたメッセージを廃棄するときに、MessageQueueとLooperによって内部的に使用されます。

パッケージアクセスが内部で使用する最悪のもの。あなたが呼ぶとき、それは内部的に使用していることを良いこと:

handler.removeMessages(int what) 

だから私は最終的な解決策を推測です:

try { 
    msg.recycle(); //it can work in some situations 
} catch (IllegalStateException e) { 
    workerHandler.removeMessages(msg.what); //if recycle doesnt work we do it manually 
} 
0

を使用して、ハンドラスレッドが処理を続行するときにメッセージを削除してください。

//[..] 
     //synchronized with the handler thread 
     @Override 
     public boolean handleMessage(final Message msg) { 
      new MessageDestructor().execute(msg); 
      return true; 
     } 
//[..] 
private class MessageDestructor extends AsyncTask<Message, Void, Void> { 
    Message msg; 
    @Override 
    protected String doInBackground(Message... params) { 
     msg = (Message) params[0]; 
     return null; 
    } 

    @Override 
    protected void onPostExecute(Void result) { 
     msg.recycle(); //synchronized with the main thread 
    } 

    @Override 
    protected void onPreExecute() { 
    } 

    @Override 
    protected void onProgressUpdate(Void... values) { 
    } 
} 
関連する問題