[Java][Kotlin][Android] μλλ‘μ΄λ μλ°μ μ½νλ¦° ν¨κ» μ¬μ©νκΈ° - μλλ‘μ΄λ Legacy μ½λ μ μ§λ³΄μ νκΈ° (1)
μλ νμΈμ π
κ±°μ ν λ¬ λ§μ ν¬μ€ν μΌλ‘ μ°Ύμλ΅λ κ² κ°μ΅λλ€.
μ¬λ¬ νλ‘μ νΈλ€μ κ²½ννλ€ λ³΄λ©΄ μλ°λ‘ λμ΄μλ μ½λλ₯Ό μ½νλ¦°μΌλ‘ λ°κΎΈκ±°λ
λ κ±°μ μ½λλ€μ μ μ§ λ³΄μνλ©΄μ μ½νλ¦°μ ν¨κ» μ¬μ©νλ κ²½μ°κ° λλ¬ μμ΅λλ€.
μ€λμ μ΄λ° κ²½μ°μ λν μ¬λ¬κ°μ§ λ΄μ©λ€μ ν¬μ€ν ν΄λ³΄λ € ν©λλ€.

μ΄λ² ν¬μ€ν μ μ΄ 2νΈμΌλ‘ κΈ°νμ΄ λ κ²μΌλ‘ 보μ΄λ©°
1νΈ(λ³Έ ν¬μ€ν )μ μλ°μ μ½νλ¦°μ ν¨κ» μ¬μ©νλ λ°©λ²
2νΈμ μλ° μ½λλ₯Ό μ½νλ¦°μΌλ‘ λ³κ²½νλ λ°©λ²μ λν΄μ ν¬μ€ν ν΄λ³΄λ € ν©λλ€!
κ·ΈλΌ λ°λ‘ μμν΄λ³΄λλ‘ ν κΉμ? π
1. μ€μ
μλ° κΈ°λ° νλ‘μ νΈμμ μ½νλ¦°μ μ¬μ©νκΈ° μν΄ μ μ½λμ κ°μ΄ build.gradleμ μ€μ ν΄μ€λλ€.
// Project gradle
plugins {
... // μλ΅
id 'org.jetbrains.kotlin.android' version '1.8.10' apply false
}
// Module gradle
plugins {
... // μλ΅
id 'org.jetbrains.kotlin.android'
}
android {
... // μλ΅
sourceSets{
main.java.srcDirs+='src/main/kotlin'
}
}
dependencies {
... // μλ΅
// Kotlin
implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.8.10'
}
2. λλ ν 리 μμ±
Android Studioμμ νλ‘μ νΈ λ³΄κΈ° μ€μ μ Android -> Projectλ‘ λ³κ²½ ν mainμ kotlinμ΄λΌλ μ΄λ¦μΌλ‘ λλ ν 리λ₯Ό μμ±ν΄ μ€λλ€.
μ°μ κΈ°λ³Έμ μΈ μ€μ μ μ΄λ κ² λ§μΉλ©΄ λκ² μ΅λλ€. π€©
κ·ΈλΌ μ§κΈλΆν°λ μμ§ μλ°λ₯Ό μ°κ³ μλ νλ‘μ νΈμ μ¬λ¬ κ°μ§ λΌμ΄λΈλ¬λ¦¬ λ° ν¨ν΄ λ±μ μ μ©μν€λ λ°©λ²μ μμλ³΄κ² μ΅λλ€.
· MainActivity
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private ActivityMainBinding mBinding;
private MainViewModel mViewModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this , R.layout.activity_main);
mViewModel = new ViewModelProvider(this).get(MainViewModel.class);
mViewModel.callAllBeachList();
observeData();
}
private void observeData() {
mViewModel.getToastMessage().observe(this, new Observer<String>() { // Toast Message
@Override
public void onChanged(String message) {
Toast.makeText(MainActivity.this, message , Toast.LENGTH_SHORT).show();
}
});
mViewModel.getBeachList().observe(this, new Observer<List<BeachDTO>>() {
@Override
public void onChanged(List<BeachDTO> beachDTOs) {
for(BeachDTO beach : beachDTOs){
Log.d(TAG, "onChanged: " + beach.toString());
}
}
});
}
}
· MainViewModel
@HiltViewModel
public class MainViewModel extends ViewModel {
private BeachRepository mBeachRepository;
private CompositeDisposable mCompositeDisposable;
private MutableLiveData<List<BeachDTO>> mBeachList = new MutableLiveData<>();
public LiveData<List<BeachDTO>> getBeachList() {
return mBeachList;
}
private MutableLiveData<String> mToastMessage = new MutableLiveData<>();
public void setToastMessage(String message) {
mToastMessage.setValue(message);
}
public MutableLiveData<String> getToastMessage() {
return mToastMessage;
}
@Inject
MainViewModel(BeachRepository repository){
mBeachRepository = repository;
}
/**
* RxJavaλ₯Ό ν΅ν΄ ν΄μμμ₯ νΌμ‘λλ₯Ό κ°μ Έμ€λ λ©μλ
* **/
public void callAllBeachList() {
if(mCompositeDisposable == null){
mCompositeDisposable = new CompositeDisposable();
}
mCompositeDisposable.add(
mBeachRepository.getBeachCongestion()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableSingleObserver<BeachListDTO>(){
@Override
public void onSuccess(@NonNull BeachListDTO beachListDTO) {
mBeachList.setValue(beachListDTO.getAllBeachList());
}
@Override
public void onError(@NonNull Throwable e) {
mToastMessage.setValue("ν΅μ μ μ€ν¨νμ΅λλ€!");
}
})
);
}
@Override
protected void onCleared() {
super.onCleared();
if(mCompositeDisposable != null){
mCompositeDisposable.clear(); // ViewModelμ΄ clear λ λ CompositeDisposable μμ
mCompositeDisposable = null;
}
}
}
μ 보μλ λ°μ κ°μ΄ MainActivityλ JavaκΈ°λ°μΌλ‘ RxJavaμ LiveDataλ₯Ό ν΅ν΄ ν΅μ νκ³ μμ΅λλ€.
ν΄λΉ Activityμ ν¨κ» μ¬μ©νλ Repositoryμ Hiltμ module , Modelμμ μ¬μ©ν class λ±μ μ½νλ¦°μΌλ‘
μμ±ν΄ ν¨κ» μ¬μ©νλ λ°©λ²μ λν΄ μμ보λλ‘ νκ² μ΅λλ€.
· RestApi (Retrofit API ν΅μ μ μν Interface)
interface RestApi {
@GET(Utils.GET_BEACH_CONGESTION_URL)
fun getBeachCongestion() : Single<BeachListDTO>
}
· BeachRepository ( Repository Interface RxJavaμ ν¨κ» μ¬μ©νκΈ° μν΄ Single κ°μ²΄λ₯Ό μ λ¬λ°λλ€. )
interface BeachRepository {
/**
* ν΄μμμ₯ νΌμ‘λ κ°μ Έμ€κΈ°
* **/
fun getBeachCongestion() : Single<BeachListDTO>
}
· BeachRepositoryImpl (Repositoryμ ꡬν체 )
class BeachRepositoryImpl @Inject constructor(
private val restApi: RestApi
) : BeachRepository {
/**
* ν΄μμμ₯ νΌμ‘λ κ°μ Έμ€κΈ°
* **/
override fun getBeachCongestion(): Single<BeachListDTO> {
return restApi.getBeachCongestion()
}
}
· Modelμμ μ¬μ©ν DTO classλ€
data class BeachDTO(
val etlDt : String = "",
val seqId : Int = -1,
val poiNm : String = "",
val uniqPop : Int = -1,
var congestion : String = ""
)
class BeachListDTO {
private lateinit var mBeachList : MutableList<BeachDTO>
@SerializedName("Beach0")
val beach0 : BeachDTO? = null
@SerializedName("Beach1")
val beach1 : BeachDTO? = null
@SerializedName("Beach2")
... μλ΅
fun getAllBeachList() : MutableList<BeachDTO> {
if(!::mBeachList.isInitialized){
mBeachList = mutableListOf()
mBeachList.add(beach0 as BeachDTO)
mBeachList.add(beach1 as BeachDTO)
mBeachList.add(beach2 as BeachDTO)
... μλ΅
}
return mBeachList
}
}
· ProvideModule( Providesλ₯Ό ν΄μ€ μμλ€μ λͺ¨μλμ Module )
@Module
@InstallIn(SingletonComponent::class)
object ProvideModule {
@Provides
@Singleton
fun provideRestApi(okHttpClient: OkHttpClient) : RestApi {
return Retrofit.Builder()
.baseUrl(Utils.BEACH_BASE_URL)
.client(okHttpClient)
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(RestApi::class.java)
}
@Provides
@Singleton
fun provideOkHttpClient() : OkHttpClient {
val interceptor = HttpLoggingInterceptor()
interceptor.level= HttpLoggingInterceptor.Level.BODY
return OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(Utils.CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)
.build()
}
}
· BindModule( Bindsλ₯Ό ν΄μ€ μμλ€μ λͺ¨μλμ Module )
@Module
@InstallIn(SingletonComponent::class)
abstract class BindModule {
@Binds
@Singleton
abstract fun bindBeachRepository(beachRepositoryImpl: BeachRepositoryImpl) : BeachRepository
}
μμμ 보μ΄λ―μ΄ Hilt λ° μ¬λ¬ κ°μ§ Repository λ±μ μ½νλ¦°μΌλ‘ μλ‘ μΆκ°νμ¬ μ¬μ©ν μ μμ΅λλ€.
μ μ΄μ μ½νλ¦°μ μ₯μ μ€ νλκ° μλ°μ νΈνμ΄ λλ€λ κ²μ΄κΈ° λλ¬Έμ μ΄λ κ² μ¬μ©νλ κ²μ λΉμ°ν ν λ°μ
μ€λλ νλ‘μ νΈλ€μ μ μ§ λ³΄μ νλ€ λ³΄λ©΄ μλ°λ‘ λ λΆλΆμ μλ°λ‘ μ μ§λ³΄μλ₯Ό μ§ννκ³
μ κ· κΈ°λ₯λΆν°λ μ½νλ¦°μ μ μ©νμ¬ κ°λ°νλ κ²½μ°κ° λ§μλ° μ΄λ»κ² μμμ ν΄μΌ ν μ§ κ°μ΄ μ μ‘νλ κ²½μ°κ° λ§μ΅λλ€.
κ·Έλ° λΆλ€μκ² μ‘°κΈμ΄λλ§ λμμ΄ λμμΌλ©΄ μ’κ² μ΅λλ€. π
λ€μ ν¬μ€ν μΌλ‘λ ν΄λΉ μλ° μ½λλ₯Ό μ΄λ»κ² μ½νλ¦°μΌλ‘ Migration νλμ§μ λν΄ λ€λ€λ³΄κ² μ΅λλ€.
κ·ΈλΌ
μ€λλ μ¦μ½νμΈμ :)