도전과제 11,12 : 서비스에서 수신자로 메시지 보내기 (Do it 안드로이드 앱 프로그래밍) [JAVA]
반응형

 

도전과제 11,12

서비스에서 보낸 메시지를 액티비티 안에서 등록한 브로드캐스트 수신자를 이용해 받도록 만들어 보세요

  1. 화면에 버튼 하나와 입력상자 그리고 텍스트뷰를 배치합니다.
  2. 버튼을 누르면 입력상자의 글자를 가져와 서비스를 실행하면서 보내줍니다.
  3. 서비스에는 다시 브로드캐스팅을 이용해 글자를 보내줍니다.
  4. MainActivity 화면에서는 브로드캐스트 수신자를 통해 글자를 전달받습니다.
  5. 수신자를 통해 전달받은 글자를 화면에 있는 텍스트뷰에 표시합니다.

참고할점
액티비티 안에서 브로드캐스트 수신자를 등록할 수 있습니다.
액티비티 안의 수신자에서 메시지를 수신하면 그 메시지를 액티비티 안의 텍스트뷰에 표시할 수 있습니다.

 

풀이

레이아웃은 단순하게 EditText로 메세지를 보내면, 밑에 TextView에 각각의 서비스와 수신자를 거치는게 기록되면서 표시되게 구성하였다.

메인 액티비티에서 버튼을 누르면 인텐트에 메세지를 담아 서비스를 시작한다. 그럼 인텐트는 MyService.class를 실행하며 전달된다.

button.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
            String text = editText.getText().toString();
            Intent intent = new Intent(getApplicationContext(), MyService.class);
            intent.putExtra("text", text);
            intent.putExtra("name", "메인 출발\n");
            startService(intent);
      }
});

실행된 서비스인 MyService.class에서는 onStartCommand()로 시작할 때의 동작을 정의한다. 이때 인텐트 객체가 null이 아니면 processCommand를 실행하는데, 이 processCommand에서는 액션을 정의한 후 브로드캐스트로 뿌린다.

public class MyService extends Service {
    private static final String TAG = "MyService";
    public MyService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate Called");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStratCommand Called");
        if(intent == null){
            return Service.START_STICKY;
        }else{
            processCommand(intent);//인텐트 객체가 null이 아니면 실행
        }
        return super.onStartCommand(intent, flags, startId);
    }

    private void processCommand(Intent intent){
        String text = intent.getStringExtra("text");
        String name = intent.getStringExtra("name");    //인텐트 안에서 데이터 따와서
        //com.example.doitmission12.myAction의 액션으로 정의 후
        Intent sendIntent = new Intent("com.example.doitmission12.myAction");
        sendIntent.putExtra("text", text);
        sendIntent.putExtra("name", name + "서비스 거침\n");
        sendBroadcast(sendIntent); //브로드캐스트로 뿌림
        Log.d(TAG, "서비스에서 받은 문자 : " + text);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy Called");
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

다시 메인 액티비티로 돌아와서, BoradcastReceiver를 상속받는 MyReceiver를 정의하는데, onReceive 함수로 원하는 액션을 받았을때 할 행동을 정의한다. 여기선 textView를 갱신하게 하였다. 이제 이 myRecevier 객체를 선언한 후, registerReceiver()메소드로 이 액티비티에 등록시킨다.

MyReceiver 자체를 메인 액티비티 내부에서 선언하여 바로 textView를 갱신하거나 받은 인텐트 값을 사용할 수 있지만, 다른 액티비티로 인텐트를 넘겨 사용해야 할 경우가 있다. 위 문제에서는 브로드캐스트 수신자에서 인텐트 값을 다시 넣은 뒤, 다시 메인 액티비티를 호출하는 방법 sendToActivity를 통해 사용하였다. 

 public class MyReceiver extends BroadcastReceiver {
        public static final String TAG = "MyReceiver";
        public Intent BroadcastIntent;
        @Override
        public void onReceive(Context context, Intent intent) {
            String text = intent.getStringExtra("text");
            String name = intent.getStringExtra("name") + "브로드캐스트 거침\n";
            Log.d(TAG, "BroadCast에서 받은 문자  : " + text);
            //textView.setText("내용 : " + text+ "\n" + "경로 : " + name + "다시 메인으로");
            sendToActivity(context, text, name);
        }

        //아래 메소드를 사용하면 새 액티비티 창켜서 인텐트내용 전송 가능.
        public void sendToActivity(Context context, String text, String name){
            BroadcastIntent = new Intent(context.getApplicationContext(), MainActivity.class);
            BroadcastIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP);
            BroadcastIntent.putExtra("text" , text);
            BroadcastIntent.putExtra("name", name);
            context.getApplicationContext().startActivity(BroadcastIntent);
        }
}

그렇게 되면 onCreate함수의 getIntent()가 발동하면서 NewActivity 메소드가 실행되고, 새 메인 액티비티 창이 켜지면서 텍스트뷰에 지금까지의 경로가 표시된다.

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        editText = findViewById(R.id.editText);
        textView = findViewById(R.id.textView);
        button = findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() {
            //중략..
        });

        myReceiver = new MyReceiver();
        IntentFilter filter = new IntentFilter("com.example.doitmission12.myAction");
        this.registerReceiver(myReceiver, filter);

        NewActivity(getIntent());
    }

        public void NewActivity(Intent intent){
            String text = intent.getStringExtra("text");
            String name = intent.getStringExtra("name");
            if(text != null){
                textView.setText("내용 : " + text+ "\n" + "경로 : " + name + "다시 메인으로");
            }
    }

 

결과

전체 소스코드 : https://github.com/howtolivelikehuman/DoitAndroid/tree/master/DoitMission_12

 

반응형