마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

서비스에서 실시간으로 데이터를 보내고 액티비티에서 받을 수 있는 방법이 있을까요?

0 추천

안녕하세요. 블루투스 관련 앱을 만들고 있습니다.

지금까지 액티비티 A,B,C가 있으면 A액티비티에서 블루투스 통신을하고

블루투스 통신을 하는동안 받은 값을 핸들러로 받아서 텍스트뷰를 실시간으로 바꾸는 코드를 짰습니다.

그리고 액티비티 B,C에 intent로 데이터를 전달하여 블루투스로 받아온 값을 처리하였습니다.

구현하려는 액티비티를 A가 아닌 B,C에서도 실시간으로 데이터를 받게 코드를 짜고 싶어.

A에 있던 블루투스 통신 코드를 Service로 옮겨 데이터를 백그라운드에서 실시간으로 받는것까지 성공하였습니다.

하지만 Service에서 읽은 readMessage 값을 어떻게 액티비티 A,B,C로 실시간으로 넘겨줘야 하는지 잘 모르겠습니다.

public void run() {          // 액티비티 A에 있던 코드
    byte[] buffer = new byte[1024];
    int bytes;

    while (true) {
        try {
            bytes = mmInStream.available();  //InputStream mmInStream;
            if (bytes != 0) {
                SystemClock.sleep(100);
                bytes = mmInStream.available();  
                bytes = mmInStream.read(buffer, 0, bytes);
                mBluetoothHandler.obtainMessage(BT_MESSAGE_READ, bytes, -1, buffer).sendToTarget();
            }
        } catch (IOException e) {
            break;
        }
    }
}

 

mBluetoothHandler = new Handler(){          // A 액티비티 핸들러
    @SuppressLint("HandlerLeak")
    public void handleMessage(android.os.Message msg){
        if(msg.what == BT_MESSAGE_READ){
            String readMessage = null;
            try {
                readMessage = new String((byte[]) msg.obj, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            Log.e("측정값", "" + readMessage);
            textView.setText(""+readMessage);

        }
    }
};
@Override
public void run() {               //액티비티A 에서 Service로 옮긴 코드
    buffer = new byte[1024];
    int bytes;

    Log.d("service","connected thread run method");

    while(true) {
        try {
            SystemClock.sleep(200);
            bytes= inS.read(buffer);
            String readMessage = null;
            readMessage = new String((byte[]) buffer, "UTF-8");
            Log.e("service", "" + readMessage);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
우혼 (260 포인트) 님이 2021년 10월 27일 질문

1개의 답변

0 추천
 
채택된 답변

서비스에 리스너를 등록해서 이벤트가 발생할 때  리스너를 호출하도록 해보세요.

public class MyService extends Service. {
    interface Listenter {
        void onReceivedMessage(String message);
    }

    private final Set<Listener> mListeners = new HashSet<>();

    public void addListener(Listener listener) {
          mListeners.add(listener);
    }

    public void removeLisetner(Lisetner listener) {
          mListeners.remove(listener);
    }


@Override
public void run() {               //액티비티A 에서 Service로 옮긴 코드
     //생략

    while(true) {
        try {
            //생략
            readMessage = new String((byte[]) buffer, "UTF-8");
            Log.e("service", "" + readMessage);
            notifyMessage(readMessage);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

}

 private void notifyMessage(message String) {
         for (Listener listener : mListeners) {
                 listener.onReceivedMessage(message);
         }
    }

 

참고로 Set이 Thread에 안전하지 않기 때문에 addListener, removeListener를 호출할 때 ConcurrentModificationException이  일어날 수 있습니다. Thread에 안전한 데이터 타입을 사용하거나 addListener, removeListene할 때 synchronise 등을 이용해  Thread에 안전하게 처리해 주세요. 이 부분은 아래 블로그를 참조해 주세요.

https://www.techyourchance.com/thread-safe-observer-design-pattern-in-java/

 액티비티에서 addListener와 removeListener를 호출하는 시점은 onStart-onStop을 이용하면 제일 좋고, 그렇지 않다면 상황에 맞게 처리하시기 바랍니다.

spark (226,720 포인트) 님이 2021년 10월 27일 답변
우혼님이 2021년 11월 2일 채택됨
...