티스토리 뷰

Android

[Android] 서비스(Service)

감자형 2017. 9. 22. 02:13
  • 서비스
화면이 없는것을 얘기 하는것이다.

화면이 어떻게 보일까? xml
화면 동작기능 ? java source

1
2
3
4
5
6
7
1. 화면이 없더라도 뭔가 기능이 실행될 수 있게 하는것이 서비스 이다.
2. 서비스는 어플리케이션 구성요소이다.
3. 시스템이 관리한다.
4. 서비스는 뒤에서 계속 실행되어야하는 기능이 있어야한다.
5. 서비스가 메모리에 CPU가 작아서 시스템이 자동으로 종료시켰다고 하더라도, 서비스가 계속감시를 하다가 자동으로 재시작해준다.
6. 수명주기 onCreate,onDestory 메소드
7. 서비스는 StartService()로 시작하게 된다.
cs

<구조>


  • 서비스를 만들고 싶을때는?
App-> 오른쪽 마우스 ->new -> service -> Service를 만들수 있다.

버튼 클릭했을때 StartService()로 실행을 하는 구조로 사용될 수 있다.

  • 서비스를 직접 만들어 보자
1
2
3
4
5
6
7
8
1. New Project를 만드는데 이름은 : Example_Service 로 지정하자
 
2. App-> 오른쪽 마우스 ->new -> service -> Service를 만들수 있다.
(서비스는 시스템 구성요소이다. 메니페스트에 등록해야 한다. 시스템이 관리하므로)
 
3.Myservice 라는 Class Name을 생성한다. 그러면 MyService라는 클래스가 생성이 된다.
 
4.   이후에 메니페스트로 가보면 Service라는 태그가 생성 된것을 확인 할 수 있다.
cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.example_service">
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
 
        <service
            android:name=".MyService"
            android:enabled="true"        //설정 정보
            android:exported="true"></service>    // 설정정보
    </application>
 
</manifest>
cs
5. MyService로 가보자.
Service를 상속한것을 알 수 있다.
일반적으로 onBind()를 사용하지 않는다.
Service라는것을 동작을 시키려면 StartService()를 동작시켜야한다.

  • 이제 메인화면에서 버튼 클릭시 서비스가 동작하는지를 알아 보자. 예제)
1
2
3
4
5
6
7
1. 버튼을 하나만들어서 "서비스 시작" 이라는 Text를 지정하자
 
2. 서비스는 시스템이 관리 한다. 직접 시작을 못하고 시스템에 요청을 해야한다 이때는 ,시스템이 알아먹는 포멧을 써야하므로 Intent를 써야한다. 데이터를 넘겨줄려면 ExtraData를 써야한다. 우리는 이제 데이터를 넘겨볼것이다 이 과정을 통해서
 
3. 입력 상자 Plain Text를 추가 한다. 이때 text 를 KGH로 지정하자.
 
4. Main.java로 가서 코드 작성해보자.
cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.example.example_service;
 
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
 
public class MainActivity extends AppCompatActivity {
    EditText editText;
 
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        final EditText editText = (EditText) findViewById(R.id.editText); // 변수로 할당 완료 id값
 
 
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
 
            @Override
            public void onClick(View v) {
                /*
                    여기안에서 서비스를 실행해볼것이다 . 데이터를 부가 데이터로 해서 넘겨볼것이다.
                     */
 
                String name = editText.getText().toString();
                Intent intent = new Intent(getApplicationContext(),MyService.class);
                // 서비스 클래스가 등록된 객체
                intent.putExtra("command","show");      // 부가 데이터 보냄 1
                intent.putExtra("name", name);          // 부가 데이터 보냄 2
                startService(intent);
                // intent로 서비스를 실행시키면, 서비스로 가서 부가데이터가지고 처리하고 싶은경우
 
 
            }
        });
 
        /*
         */
    }
}
cs

1
2
3
4
5
6
7
8
5. intent를 StartService로 서비스를 실행시키면 서비스로 가서 부가데이터를 처리하고 싶은경우가 생길텐데 이때, Myservice 클래스로 가서 처리 할 수 있다. ( 소스)
 
6. 이때 MyService로 가서 오른쪽 마우스 클릭 ->generate -> override Method 클릭
-> onCreate(), onDestory() , onStartCommand() 세개를 선택 해서  OK 버튼을 누른다.
 
7. 혹시 에러메시지가 나오는 파라미터가 있으면 삭제를 해도 무방하다.
 
8. MyService 코드를 작성해 보자.
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package com.example.example_service;
 
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
 
public class MyService extends Service {
 
    private static final String TAG = "MyService";
    // 상수를 하나 정의한다. 이정보를 계속사용하게되면 String 을 계속 생성할 필요가 없다.
 
    public MyService() {
    }
 
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG,"onCrete 호출 된다.");//태그를 한번 찍어보자, 태그를 잘못 정의하면 태그가 잘못 들어간다.
    }
 
    @Override
    public void onDestroy() {
        Log.d(TAG,"onDestroy 호출 된다.");//태그를 한번 찍어보자, 태그를 잘못 정의하면 태그가 잘못 들어간다.
        super.onDestroy();
    }
 
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG,"onStartCommand 호출 된다.");//태그를 한번 찍어보자, 태그를 잘못 정의하면 태그가 잘못 들어간다.
 
 
        // 여기서 처리 한다. 시스템 특성상 아래 특징 확인
        if(intent == null){
            return Service.START_STICKY;
            // 끈적끈적하게 계쏙 서비스가 종료되더라도 자동으로 실행되도록한다.
        }else{          // Null이 아닐경우
            processCommand(intent); // 메소드를 분리하는게 보기가 좋다. 여기서 처리한다.
        }
 
        return super.onStartCommand(intent, flags, startId);
 
    }
    private void processCommand(Intent intent){
        // 전달 받은 데이터 찍기 위함.
        String command = intent.getStringExtra("command"); // command 는 구분 하기 위한것
        String name = intent.getStringExtra("name");
 
        Log.d(TAG, "전달 받은 데이터 : " + command + ", "+ name);      // 로그를 찍어보자.
    }
 
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
 
    /*
    서비스는 한번 시작되면 계속 시작되어야한다. 말은 StartService이나, 아무리 StartService를 실행한다고하더라도
    새로 만들어 지지않는다.
    문제는 인텐트 안에 넣어서 전달하는게 onCreate에서 확인할 수 가없다. 따라서, onStartCommand에서 실행하게 된다.
    서비스의 특성상 인텐트는 onStartCommand에서 처리한다.! 꼭 알고 있어야함.!
     */
}
cs
<실행 화면>



<부가 설명>
1
2
3
1. SERVICE START를 한번 클릭 하였을 경우 onCreate 호출 되고 , onStartCommand가 호출 되고, 전달 받은 데이터는 show, KGH 이다.
 
2. SERVICE START를 한번더 클릭 하면, onCreate 함수는 호출 되지 않고 onStartCommand와 전달받은 데이터만 호출 된다.

 (onCrate함수는 호출 X 서비스가 실행되어져 있기때문에 
-> 이것을 확인해 보려면 상단에 Tools 
-> Android 
-> Android Device Manager 를 누르고 세션 끄겠다는 것을 Yes를 누르고 
-> 하나의 창이 뜨게 되는데 어떠한 프로세스가 동작되어있는지 알수 있다.
 예를 들어 ) org.techtown.service 이게 실행한 앱의 프로세스가 된다. 이것을 스탑을 시키게 되면 강제로 프로세스가 종료된것인데, 자동으로 또 실행되는것을 볼 수 있다.
 시스템이 자동으로 시스템을 시작시키는것을 알 수 있다. 
cs


2탄
  • 여기까지 서비스를 만들어 보았다. 그특징은 ?
액티비티에서 서비스를 실행하거나 또는 액티비티에서 서비스를 어떠한 데이터를 전달하고 싶은경우에는 시스템을 항상 통과한다. 서비스의 애플리케이션의 구성요소이므로 중요.

  • 반대의 경우는?
서비스 카카오톡,라인 (채팅앱)의 경우에는 화면이 없더라도 메시지를 주고받는 상황이 생길수 있다. 서비스 측에서 데이터를 받을 경우 화면에 메시지를 띄울 것이다. 어차피 서비스는 화면에 없는것이므로, 서비스-> 액티비티로 보낼경우가 있는데 우리가 지금 이것을 실습해볼것이다.

  • 아까 만들던 예제로 또 이어서 작성하겠습니다.
<소스 코드> 주석과 함께있습니다.

(MyService.java)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package com.example.example_service;
 
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
 
public class MyService extends Service {
 
    private static final String TAG = "MyService";
    // 상수를 하나 정의한다. 이정보를 계속사용하게되면 String 을 계속 생성할 필요가 없다.
 
    public MyService() {
    }
 
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG,"onCrete 호출 된다.");//태그를 한번 찍어보자, 태그를 잘못 정의하면 태그가 잘못 들어간다.
    }
 
    @Override
    public void onDestroy() {
        Log.d(TAG,"onDestroy 호출 된다.");//태그를 한번 찍어보자, 태그를 잘못 정의하면 태그가 잘못 들어간다.
        super.onDestroy();
    }
 
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG,"onStartCommand 호출 된다.");//태그를 한번 찍어보자, 태그를 잘못 정의하면 태그가 잘못 들어간다.
 
 
        // 여기서 처리 한다. 시스템 특성상 아래 특징 확인
        if(intent == null){
            return Service.START_STICKY;
            // 끈적끈적하게 계쏙 서비스가 종료되더라도 자동으로 실행되도록한다.
        }else{          // Null이 아닐경우
            processCommand(intent); // 메소드를 분리하는게 보기가 좋다. 여기서 처리한다.
        }
 
        return super.onStartCommand(intent, flags, startId);
 
    }
    private void processCommand(Intent intent){
        // 전달 받은 데이터 찍기 위함.
        String command = intent.getStringExtra("command"); // command 는 구분 하기 위한것
        String name = intent.getStringExtra("name");
 
        Log.d(TAG, "전달 받은 데이터 : " + command + ", "+ name);      // 로그를 찍어보자.
 
        try{
            Thread.sleep(5000);     //여기에서 5초동안 쉬겠다.
 
        }catch(Exception e){
 
        }
 
        /*
        이제 액티비티로 전달해보자. 시스템으로 전달하므로 인텐트 필요
         */
 
        Intent showIntent = new Intent(getApplicationContext(),MainActivity.class);
        // MainActivity로 보내겠다.
 
        showIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|
                            Intent.FLAG_ACTIVITY_SINGLE_TOP|
                            Intent.FLAG_ACTIVITY_CLEAR_TOP); // intent 객체 안에다가  데이터를 보내고 싶을 경우
        showIntent.putExtra("command","show");
        showIntent.putExtra("name",name + "from Service");
        startActivity(showIntent);
        // 이렇게 보내면 문제가 생기는데 why? 서비스라는것은 화면이 없으므로 화면->화면 을 띄우면 문제가 생긴다.
        // 화면은 Task로 바뀌어져있는데, 내가만든것, 다른사람이 만든것 화면끼리 띄워줄수있도록 하는데
        // Task 라는것이 없어서 화면이 없는것에서 화면을 띄워줄려고 하면 Task 에서 문제가 발생하는데 ,
        // 이때 옵션을 주어야 한다.
        /*일반적으로 이 옵션세개가 자주 쓰인다. 이제 이렇게 하면 MainActivity에서 받을 수 있다.
        showIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|
                            Intent.FLAG_ACTIVITY_SINGLE_TOP|
                            Intent.FLAG_ACTIVITY_CLEAR_TOP);
         */
 
 
 
    }
    // 만약 처음 만들어 지는 시기에서는 onCrete에서 확인하게되고, 아닌경우에서는 새로운
    //onNewIntent 메소드가 호출 되게 된다. -> mainActivity로 넘어 갈것.
 
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
 
    /*
    서비스는 한번 시작되면 계속 시작되어야한다. 말은 StartService이나, 아무리 StartService를 실행한다고하더라도
    새로 만들어 지지않는다.
    문제는 인텐트 안에 넣어서 전달하는게 onCreate에서 확인할 수 가없다. 따라서, onStartCommand에서 실행하게 된다.
    서비스의 특성상 인텐트는 onStartCommand에서 처리한다.! 꼭 알고 있어야함.!
     */
}
cs

(Main.java)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package com.example.example_service;
 
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
 
public class MainActivity extends AppCompatActivity {
    EditText editText;
 
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        final EditText editText = (EditText) findViewById(R.id.editText); // 변수로 할당 완료 id값
 
 
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
 
            @Override
            public void onClick(View v) {
                /*
                    여기안에서 서비스를 실행해볼것이다 . 데이터를 부가 데이터로 해서 넘겨볼것이다.
                     */
 
                String name = editText.getText().toString();
                Intent intent = new Intent(getApplicationContext(),MyService.class);
                // 서비스 클래스가 등록된 객체
                intent.putExtra("command","show");      // 부가 데이터 보냄 1
                intent.putExtra("name", name);          // 부가 데이터 보냄 2
                startService(intent);
                // intent로 서비스를 실행시키면, 서비스로 가서 부가데이터가지고 처리하고 싶은경우
 
 
 
 
            }
        });
 
        // 여기서 확인하는 경우가 생긴다 값이 넘어 오는지
 
 
        // 서비스쪽에서 던져준 데이터를 받기위한 메서드이다. processCommand는 출력하기위한 메소드
        // 처음이면 oncreate에서 확인 하고 그렇지 않으면(처음이 아니라면) oncreate에서 호출되지 않고
        // onNewIntent() 를 호출 하게 된다. 서비스 -> 액티비티에서 확인하는경우.
        Intent passedIntent = getIntent();          // on
        processCommand(passedIntent);
        /*
         */
    }
    //onNewIntent 메소드가 호출 되게 된다. -> mainActivity로 넘어 갈것.
    @Override
    // 서비스쪽에서 던져준 데이터를 받기위한 메서드이다. processCommand는 출력하기위한 메소드
    // 처음이면 oncreate에서 확인 하고 그렇지 않으면(처음이 아니라면) oncreate에서 호출되지 않고
    // onNewIntent() 를 호출 하게 된다. 서비스 -> 액티비티에서 확인하는경우.
    protected void onNewIntent(Intent intent) {
        processCommand(intent);
        super.onNewIntent(intent);
    }
    private void processCommand(Intent intent) {
 
        if(intent != null){
            String command = intent.getStringExtra("command");
            String name = intent.getStringExtra("name");
            Toast.makeText(this"서비스로 부터 전달받은 데이터 :" + command +"," +name, Toast.LENGTH_SHORT).show();
        }
 
    }
 
 
    // 만약 처음 만들어 지는 시기에서는 onCrete에서 확인하게되고, 아닌경우에서는 새로운
 
}
cs
<설명>

1
2
3
1. processCommand 에서 가상으로 보낼것이다.
2. 만약처음 만들어 지는 시기에서는 onCrete에서 확인하게 되고 아닌 경우에서는 새로운 함수를 정의 해주어야 하는데
 이때, 새로운 override를 해준다.
main.java 에서 오른쪽 마우스 
-> generate 
-> override Method 
-> onNewIntent() 를 추가 해준다. 
이때, onNewIntent 를 오버라이드 한곳에서 새로운 processCommand 메소드를 만들어서 서비스에서
 -> 액티비티로 던져준 값을 출력시키는 형태이다.
cs


  • 출력 결과
5초 뒤에 서비스 데이터를 전달 받았다.





공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함