0

I am working on a Bluetooth communication project where I need to transfer data among devices.Upon receiving an InputStream I pass the data to the UI thread from the worker thread using the following code:-

// Read from the InputStream.
numBytes = mmInStream.read(mmBuffer);
// Send the obtained bytes to the UI activity.
Message readMsg = handler.obtainMessage(MessageConstants.MESSAGE_READ,numBytes, -1,mmBuffer);
readMsg.sendToTarget();

Below is my handler class:-

public Handler mHandler = new Handler() {
    public synchronized void handleMessage(Message msg) {
        byte[] readBuf=(byte[])msg.obj;
        String readMsg=new String(readBuf,0,msg.arg1);
        TextView textView=findViewById(R.id.textview);
        textView.setText(readMsg);
    }
}

But This shows the following warning:

This Handler class should be static or leaks might occur(anonymous android.os.Handler).

I tried making the class static but then it gives the following error:-

Non-static method findViewById(int) can't be referenced from a static context.

What should I do to resolve this?

Fury2898
  • 3
  • 4

2 Answers2

0
public MyHandler mHandler;

public static class MyHandler extends Handler {

    WeakReference<TextView> mTextViewReference;

    public MyHandler(TextView textView) {
        mTextViewReference = new WeakReference<TextView>(textView);
    }

    public synchronized void handleMessage(Message msg) {
        byte[] readBuf=(byte[])msg.obj;
        String readMsg = new String(readBuf,0,msg.arg1);
        TextView textView = mTextViewReference.get();
        if(textView != null) {
            textView.setText(readMsg);
        };
    }

    public void clear() {
        mTextViewReference.clear();
        mTextViewReference = null;
    }
}

protected void onCreate(final Bundle savedInstanceState) {
    ....
    mHandler = new MyHandler(findViewById(R.id.textView));
    ....
}

@Override
public void onDestroy() {
    if(mHandler != null) {
        mHandler.clear();
        mHandler = null;
    }
    super.onDestroy();
}

EDIT

Fix above works fine if you just want to update one single TextView. However, very often, you need to take more actions and update more stuff (not only a single TextView). So, I think you can create a Interface that is invoked every time a message is received. Something like:

public class MyActivity extends Activity {

    public MyHandler mHandler;

    protected final void onCreate(final Bundle savedInstanceState) {
        //....
        mHandler = new MyHandler(new MyHandler.OnMessageReceivedListener() {
            @Override
            public void handleMessage(final String message) {
                // Update the views as you with
            }
        });

        //....
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mHandler.clear();
    }

    public static class MyHandler extends Handler {

        WeakReference<OnMessageReceivedListener> mListenerReference;

        public MyHandler(OnMessageReceivedListener listener) {
            mListenerReference = new WeakReference<>(listener);
        }

        public synchronized void handleMessage(Message msg) {
            byte[] readBuf=(byte[])msg.obj;
            String readMsg = new String(readBuf,0,msg.arg1);
            OnMessageReceivedListener listener = mListenerReference.get();
            if(listener != null) {
                listener.handleMessage(readMsg);
            };
        }

        public void clear() {
            mListenerReference.clear();
        }

        public interface OnMessageReceivedListener {
            void handleMessage(String message);
        }
    }
}
guipivoto
  • 18,327
  • 9
  • 60
  • 75
  • Note that my answer is different. I'm not telling you to create a static object (like the other answer) but to create a static class – guipivoto Sep 13 '19 at 15:56
  • Yes,I saw that.But I need to do something after receing the message.For this I need to do method calls.Is there any way to do that?Do I need to put the method inside the handler class? – Fury2898 Sep 13 '19 at 15:58
  • Thnx very much for your help! – Fury2898 Sep 13 '19 at 16:22
  • You are welcome. I added another option on the answer. This way, you can execute more code instead of just updating a text view etc. – guipivoto Sep 13 '19 at 16:31
0

You're not doing very heavy staff in your handleMessage part, so no need to extend Handler keep it simple and ligthweight; just add a callback instead. Create a callback in your Activity/Fragment:

private class MessageCallback implements Handler.Callback {

        @Override
        public boolean handleMessage(@NonNull Message message) {

            // Here you can call any UI component you want

            TextView textView=findViewById(R.id.textview);
            textView.setText(readMsg);
            return true;
        }
    }

Then call it as:

Handler handler = new Handler(getMainLooper(), new MessageCallback());
Message readMsg = handler.obtainMessage(what, arg1, arg2, object);
readMsg.sendToTarget();
Farid
  • 2,317
  • 1
  • 20
  • 34