startService 메소드를 호출할 때도 인텐트 객체를 파라미터로 전달해야 하며 이 인텐트 객체는 시스템으로 전달된 후 시스템에서 지정한 서비스를 만들고 실행하는 과정을 거치게 됩니다.
서비스로의 명령 전달
서비스가 자동으로 재시작되게 하는 것이 일반적이다 보니 앱이 실행된 후에 startService 메소드를 이용해 서비스를 시작시키기만 하면 더 이상 startService 메소드를 호출할 일이 없지 않을까요?
그렇지 않습니다.
이미 알고 있는 것처럼 인텐트를 이용해 서비스를 시작시키면 인텐트 객체가 서비스로도 전달됩니다.
그리고 그 안에 부가데이터를 넣어 전달할 수 있으므로 서비스로 데이터를 전달하고 싶은 경우에는 startService가 더 자주 호출될 수 있습니다.
그런데 이 때의 startService 메소드는 서비스를 시작시키기 위한 목적이 아니라 명령이나 데이터를 전달하기 위한 용도로 사용됩니다.
이렇게 startService 메소드를 호출하면서 인텐트 안에 넣어 전달한 명령이나 데이터를 잘 처리할 수 있도록 onStartCommand라는 메소드를 사용할 수 있습니다.
새로운 서비스 클래스를 정의할 때는 다음과 같이 onCreate, onStartCommand, onDestroy 메소드를 재정의하는 경우가 많습니다.
public class MyService extends Service {
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate() 호출됨.");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand() 호출됨.");
return super.onStartCommand(intent, flags, startId);
}
}
onStartCommand 메소드가 호출되면 인텐트 객체를 파라미터로 전달받을 수 있습니다.
따라서 인텐트 안에 들어있는 명령이나 데이터를 확인하여 필요한 기능을 수행할 수 있습니다.
서비스에서 액티비티로 데이터 전달
서비스에는 화면이 없다 보니 사용자에게 무언가를 보여주고 싶다면 액티비티로 데이터를 전달한 후 액티비티에서 보여주어야 합니다.
서비스에서 액티비티로 데이터를 전달할 때는 인텐트를 사용하며 인텐트 안에 부가데이터를 넣어 보냅니다.
Intent showIntent = new Intent(getApplicationContext(), MainActivity.class);
showIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
showIntent.putExtra("command", "show");
showIntent.putExtra("name", "mike");
startActivity(showIntent);
화면이 없는 서비스에서 화면이 있는 액티비티를 띄울 때는 태스크(Task)를 새로 만들어서 연결해야 합니다.
이 때문에 FLAG_ACTIVITY_NEW_TASK 플래그를 추가해주게 되는데 일반적인 경우 세 개의 플래그를 같이 사용합니다.
액티비티가 화면에 보인 상태에서 위와 같이 startActivity를 호출하면 액티비티는 새로 만들어지지 않고 기존 액티비티를 그대로 사용하게 됩니다.
그리고 액티비티의 onNewIntent 메소드가 자동으로 호출됩니다.
@Override
protected void onNewIntent(Intent intent) {
processIntent(intent);
super.onNewIntent(intent);
}
생각해보기
- 어떤 경우에 액티비티가 아닌 서비스에서 기능을 실행하도록 해야 하는 걸까요?
- 인터넷을 통해 데이터를 주고받는 기능을 액티비티에 넣어두는 경우 어떤 문제가 발생할 수 있을까요?
참고 자료
comment
질문1.
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
processCommand(intent);
}
에서 onNewIntent() 메소드는 스택에서 MainActivity->Service->MainActivity로 돌아왔을 때 사용하는 것이라는 것을 의미하는건가요? 그렇다면 onCreate() 메소드에서
Intent passedIntent = getIntent();
processCommand(passedIntent);
를 사용할 필요 없는 것 아닌가요? 받는 인텐트가 Service로부터 오는 것인데 Service에서 다시 MainActivity로 올 때는 onNewIntent()를 사용하는 것이니까요.
질문2.
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
processCommand(intent);
}
상황에서 processCommand() 메소드가 인텐트를 getExtra() 메소드로 받는 역할을 하는데 processCommand() 내부 혹은 onNewIntent() 메소드 내부에 Intent passedIntent = getIntent(); 를 선언할 필요는 없는건가요? 혹시 그 이유가 매개변수로 intent를 받고 있기 때문인가요?
토스트메시지 대신 스낵바를 써볼수도 있을까요?
AppBarLayout 다운받아서 써보려고 했는데 바로 쓸 수가 없더라구요.ㅜㅜ
부가 데이터 강의에서 설명할때 분명히 보내는 전달값(Extra data)들은 시스템에 거치지 않고 바로 통과된다고 하셨는데 이번에는
액티비티에서 서비스를 실행하거나 액티비티에서 서비스로 어떤 데이터를 전달하고 싶다하면
시스템을 항상 통과하는데 그 이유 액티비티와 서비스 둘 다 구성요소라서 시스템이 관리하기 때문이라고
말씀하셨습니다. 뭐가 맞는건가요? 일단은 둘 다 시스템의 호출을 받아 동작되는건 알지만
Extra data는 확실히 시스템을 건드리지 않고 전달되는 것은 맞죠?
⭐️생각해보기⭐️
1. 사진이나 파일을 전송하거나 다운로드 받을 때 서비스를 이용해서 화면이 보이지 않아도 기능을 수행할 수 있게 할 수 있을 것 같습니다.
2. OnPause나 OnStop 되었을 때 기능이 중단되는 문제와 UI 스레드에서 이를 처리함으로 인해서 화면이 버벅댈 수도 있을 것 같습니다.
첫번째 영상에서 Android Device Monitor를 실행해서 App process 를 중단시켰다 다시 키는 부분이 있습니다.
그런데 Android Studio 3.2 부터 저 모니터가 사라졌다고 합니다.
대체 가능한 게 뭐가 있을까요?
혹시 로그인이 필요한 앱에서 자동로그인 기능을 서비스를 이용해서 하는 건가요?
이 코드는 무엇을 위해 작성하는건가요?
파라미터 값을 넣는다는것이 무슨뜻인가요?
Log를 한다는게 무슨말인가요?
생각해보기
1. 화면의 데이터를 받아서 데이터베이스에 입력할때도 서비스를 통해 입력할 것 같습니다.
2. 보안상 문제가 생길 것 같습니다.
생각해보기
1. 앱의 화면이 켜지지 않은 경우에도 앱이 활동을 해야하는 경우에 필요할 것 같습니다. 말씀해 주신것처럼 카톡/라인과 같은 채팅어플이 꺼져있을때에도 알람이 울리도록 하려면 서비스를 사용해야 할 것 같습니다.
2. 음... 액티비티만을 사용하여 인터넷에서 글자를 따오는 예제를 수행해 본 적이 있는데 그땐 문제가 일어나지 않아서... 잘 모르겠습니다 ㅠㅜ.. 아마 인터넷에 접속하는 순간 포커스가 인터넷을 여는 어플리케이션으로 가버리게 되는 문제가 생길 것 같습니다.