시작됨 : startService()를 호출하여 시작되며, 한번 시작되고 나면 백그라운드에서 무기한으로 실행 될 수 있음. 해당 서비스를 시작한 구성 요소가 소멸되었더라도 무관함. 작업을 수행하고 결과를 호출자에게 반환하지 않음
바인드 됨 : bindService()를 호출하여 바인드 되며, 클라이언트-서버 인터페이스를 제공하여 구성 요소가 서비스와 상호작용할 수 있도록 해줌. 바인드된 서비스는 또 다른 애플리케이션 구성 요소가 이를 바인드되어 있는 경우에만 실행됨. 여러 개의 구성 요소가 서비스에 한꺼번에 바인드될 수 있지만, 이 모든 것이 바인딩을 해제하면 서비스가 소멸됨.
서비스는 위 두 가지 방식 모두 취할 수 있음.
서비스는 자신의 호스팅 프로세스의 기본 스레드에서 실행됨.
자신의 스레드를 직접 생성하지 않으며, 별도의 프로세스에서 실행되지도 않음.
기본 스레드 외부에서 작업을 수행해야 하지만, 사용자가 애플리케이션과 상호작용 중인 동안에만 수행하면 되는 경우라면, 서비스가 아니라 그 대신 새 스레드를 생성해야 함.
onStartCommand() : 다른 구성요소가 서비스를 시작하도록 요청한 경우.(바인딩만 제공시 이 메서드는 구현하지 않아도 됨.)
onBind() : 다른 구성요소가 서비스에 바인드되고자 하는 경우. 클라이언트가 서비스와 통신을 주고받기 위해 사용할 인터페이스를 제공해야 함. IBinder를 반환함.
한 구성 요소가 startService()를 호출하여 서비스를 시작하면(onStartCommand() 호출 발생) 해당 서비스는 스스로 stopSelf()나 다른 구성요소가 stopService()를 호출하기 전까지 실행 중인 상태 유지함.
한 구성 요소가 bindService()를 호출하여 서비스를 시작하면(onStartCommand() 호출 안함) 해당 서비스는 해당 구성 요소가 바인딩된 경우에만 실행됨. 모든 클라이언트로 바인딩 해제되면 소멸됨.
서비스는 기본적으로 메인 스레드에서 실행되므로, 성능에 영향일 미치는 작업은 서비스 내에서 새 스레드를 시작해야 함.
IntentService는 Service의 서브클래스로 기본 작업자 스레드를 생성하여 모든 시작 요청을 처리하되 한번에 하나씩 처리함. 여러 개의 요청을 동시에 처리하지 않아도 되는 경우 최선의 옵션. onHandleIntent()를 구현하면 됨. 시작 요청이 모두 처리된 후 서비스를 중단하므로 stopSelf()를 호출할 필요 없음.
onStartCommand() 메서드의 반환 값
START_NOT_STICKY : 서비스 중단되면 재생성 안됨.
START_STICKY : 서비스 중단되면 재생성하고 onStartCommand() 호출됨. null 인텐트로 처리됨.
START_REDELIVER_INTENT : 서비스 중단되면 재생성하고 onStartCommand() 호출됨. 서비스에 마지막에 전달된 인텐트로 처리됨.
바인드된 서비스를 생성하려면 onBind() 콜백 메서드를 구현하여 서비스와 통신을 위한 인터페이스를 정의하는 IBinder를 반환하도록 해야 함.
바인드된 서비스는 onStartCommand()를 통해 시작된 서비스와 달리 중단시키지 않아도 됨.
여러 클라이언트가 서비스에 한꺼번에 바인딩 된 경우 서비스와 상호작용 완료시 unbindService()를 호출하여 바인딩 해제함. 바인딩된 클라이언트가 없을 경우 서비스는 소멸됨.
포그라운드 서비스 실행시 startForeground()를 호출하며 상태 표시줄에 대한 알림인 Notification과 매개변수로 알림을 식별하는 정수를 사용함.(정수는 0이면 안됨.)
언제인지는 정확히 모르겠지만... 기존에 알던 html 양식이 바뀌었습니다...;;;; (아마 2018.12월말부터??)
위 블로그에서는 2가지 방식을 권하고 있지요. jsoup을 사용하는 방식과 HttpURLConnection을 사용하는 법이요.
먼저 jsoup을 사용하는 경우 기존 아래 같은 부분이..
Elements Version = doc.select(".content");
for (Element mElement : Version) {
if (mElement.attr("itemprop").equals("softwareVersion")) {
return mElement.text().trim();
}
}
아래와 같이 바꾸시면 되고요.
Elements Version = doc.select(".htlgb").eq(3);
for (Element mElement : Version) {
return mElement.text().trim();
}
public class BithumbTickerData {
@SerializedName("opening_price")
public String openingPrice;
@SerializedName("closing_price")
public String closingPrice;
@SerializedName("min_price")
public String minPrice;
@SerializedName("max_price")
public String maxPrice;
@SerializedName("average_price")
public String averagePrice;
@SerializedName("units_traded")
public String unitsTraded;
@SerializedName("volume_1day")
public String volume1day;
@SerializedName("volume_7day")
public String volume7day;
@SerializedName("buy_price")
public String buyPrice;
@SerializedName("sell_price")
public String sellPrice;
@SerializedName("date")
public long date;
}
public class BithumbTicker {
@SerializedName("status")
public String status;
@SerializedName("data")
public BithumbTickerData data;
}
4. interface 생성
API Method 방식 및 Path에 대해서 정의하자.
public interface OpenApiService {
@GET("public/ticker/{path}")
Call tickerInfo(@Path("path") String path);
}
5.1. Retrofit 초기화
Retrofit 생성 후 사용할 interface를 통해 서비스를 만들자. (Response를 String 형태로 받고 싶다면 ScalarsConverterFactory 사용)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.bithumb.com/")
.addConverterFactory(GsonConverterFactory.create()) // Gson 처리시
//.addConverterFactory(ScalarsConverterFactory.create()) // String 등 처리시
.build();
OpenApiService openApiService = retrofit.create(OpenApiService.class);
기존과 비교했을 때 OkhttpClient 라는 놈을 Retrofit Builder에 추가하는 모습이 보인다.
개인적으로 디버그 모드일때만 로그를 보기 위해 BuildConfig.DEBUG 로 분기 처리를 하였다.
그리고 로그 수준은 아래와 같다.
public final class HttpLoggingInterceptor implements Interceptor {
...
public enum Level {
/** No logs. */
NONE,
/**
* Logs request and response lines.
*
*
Example:
*
{@code
* --> POST /greeting http/1.1 (3-byte body)
*
* <-- 200 OK (22ms, 6-byte body)
* }
*/
BASIC,
/**
* Logs request and response lines and their respective headers.
*
*
Example:
*
{@code
* --> POST /greeting http/1.1
* Host: example.com
* Content-Type: plain/text
* Content-Length: 3
* --> END POST
*
* <-- 200 OK (22ms)
* Content-Type: plain/text
* Content-Length: 6
* <-- END HTTP
* }
*/
HEADERS,
/**
* Logs request and response lines and their respective headers and bodies (if present).
*
*
Example:
*
{@code
* --> POST /greeting http/1.1
* Host: example.com
* Content-Type: plain/text
* Content-Length: 3
*
* Hi?
* --> END POST
*
* <-- 200 OK (22ms)
* Content-Type: plain/text
* Content-Length: 6
*
* Hello!
* <-- END HTTP
* }
*/
BODY
}
위 소스를 보면 로그 레벨은 NONE, BASIC, HEADERS, BODY 로 이루어져 있다. 필요에 따라 설정하면 된다.
- NONE : No logs.
- BASIC : Logs request and response lines.
- HEADERS : Logs request and response lines and their respective headers.
- BODY : Logs request and response lines and their respective headers and bodies (if present).
앱을 실제 signed release apk 만들시 Progaurd 사용하는데, 이때 Retrofit 사용시 아래와 같이 proguard.pro 파일에 추가해준다.
# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions
Retrofit 로그에서 문제가 될시 아래도 추가해 보자.
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
# A resource is loaded with a relative path so the package of this class must be preserved.
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase