공감 및 댓글은 포스팅 하는데 아주아주 큰 힘이 됩니다!! 포스팅 내용이 찾아주신 분들께 도움이 되길 바라며 더 깔끔하고 좋은 포스팅을 만들어 나가겠습니다^^
|
이번 포스팅에서는 RxAndroid2를 사용한 간단한 예제를 보려고 합니다.
스마트폰에 설치된 애플리케이션 목록을 보는 예제인데요.
앱 레벨 gradle
android {} 블록에
dataBinding {
enabled true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
를 추가해주시고,
dependencies {} 블록에
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
kapt 'com.android.databinding.compiler:3.2.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.2'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'com.trello.rxlifecycle2:rxlifecycle:2.2.2'
implementation 'com.trello.rxlifecycle2:rxlifecycle-android:2.2.2'
implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.2'
를 추가해주세요.
저는 코틀린도 사용해서 위에 2개를 추가해주었는데,
코틀린을 안쓰시면 아래 5개만 추가하시면 됩니다.
AppInfo.kt 데이터 클래스입니다.
package park.sunggyun.thomas.rxandroidex
import android.graphics.drawable.Drawable
data class AppInfo(val name : String, val icon : Drawable )
recyclerView에 사용될 item_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/imgView"
android:contentDescription="@string/app_name"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_width="48dp"
android:layout_height="48dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/txtView"
/>
<TextView
app:layout_constraintStart_toEndOf="@+id/imgView"
app:layout_constraintEnd_toEndOf="parent"
android:id="@+id/txtView"
android:textColor="@android:color/black"
android:textSize="20sp"
android:layout_width="0dp"
android:layout_height="64dp"
android:gravity="center|start"
tools:text="asd"/>
</android.support.constraint.ConstraintLayout>
</layout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:id="@+id/rxRecyclerView"
android:layout_width="0dp"
android:layout_height="0dp"/>
</android.support.constraint.ConstraintLayout>
</layout>
xml 부분은 그냥 UI를 구성하는 부분이니 그냥 넘어가겠씁니다.
MainAdapter.java
package park.sunggyun.thomas.rxandroidex;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.Vector;
import io.reactivex.Observable;
import io.reactivex.subjects.PublishSubject;
import park.sunggyun.thomas.rxandroidex.databinding.ItemMainBinding;
public class MainAdapter extends RecyclerView.Adapter<MainAdapter.MainViewHolder> {
private Vector<AppInfo> appInfoVector = new Vector<>();
Context context;
MainAdapter(Context context) {
this.context = context;
this.publishSubject = PublishSubject.create();
}
private PublishSubject<AppInfo> publishSubject;
@NonNull
@Override
public MainViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
ItemMainBinding binding = ItemMainBinding.inflate(LayoutInflater.from(context), viewGroup, false);
return new MainViewHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull MainViewHolder mainViewHolder, int position) {
ItemMainBinding binding = mainViewHolder.binding;
AppInfo appInfo = appInfoVector.get(position);
Log.e("getName", appInfo.getName());
binding.imgView.setImageDrawable(appInfo.getIcon());
binding.txtView.setText(appInfo.getName());
mainViewHolder.getClickObserver(appInfo).subscribe(publishSubject);
}
@Override
public int getItemCount() {
return appInfoVector.size();
}
void update(AppInfo appInfo) {
appInfoVector.add(appInfo);
}
PublishSubject<AppInfo> getPublishSubject() {
return this.publishSubject;
}
class MainViewHolder extends RecyclerView.ViewHolder {
ItemMainBinding binding;
View view;
MainViewHolder(ItemMainBinding binding) {
super(binding.getRoot());
view = binding.getRoot();
this.binding = binding;
}
Observable<AppInfo> getClickObserver(AppInfo appInfo) {
return Observable.create(event -> view.setOnClickListener(view -> event.onNext(appInfo)));
}
}
}
PublishISubject 로 구독자가 구독을 했을 때(subscribe()를 호출하면)
데이터를 발행해줍니다.
Adapter 클래스에는 데이터를 받았을 때 어떻게 처리할 것인지만
정의되어있고, update(AppInfo appInfo) 를 통해
설치된 애플리케이션의 정보를 추가하게 됩니다.
MainActivity.java
package park.sunggyun.thomas.rxandroidex;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.databinding.DataBindingUtil;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.util.Log;
import android.widget.Toast;
import com.trello.rxlifecycle2.components.support.RxAppCompatActivity;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import park.sunggyun.thomas.rxandroidex.databinding.ActivityMainBinding;
public class MainActivity extends RxAppCompatActivity {
MainAdapter adapter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.rxRecyclerView.setLayoutManager(new LinearLayoutManager(this));
Log.e("onCreate()", "application started!");
adapter = new MainAdapter(this);
binding.rxRecyclerView.setAdapter(adapter);
adapter.getPublishSubject()
.subscribe(s ->
Toast.makeText(getApplicationContext(), s.getName(), Toast.LENGTH_SHORT).show()
).isDisposed();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onStart() {
super.onStart();
if (adapter == null) {
return;
}
getAppInfo()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(item -> {
Log.e("getAppInfo", item.getName());
adapter.update(item);
adapter.notifyDataSetChanged();
}).isDisposed();
}
private Observable<AppInfo> getAppInfo() {
final PackageManager manager = this.getPackageManager();
Intent i = new Intent(Intent.ACTION_MAIN, null);
i.addCategory(Intent.CATEGORY_LAUNCHER);
return Observable.fromIterable(manager.queryIntentActivities(i, 0))
.sorted(new ResolveInfo.DisplayNameComparator(manager))
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.map(item -> {
Drawable img = item.activityInfo.loadIcon(manager);
String title = item.activityInfo.loadLabel(manager).toString();
return new AppInfo(title, img);
});
}
}
getAppInfo() 메서드에서 Observable<AppInfo> 를 반환합니다.
설치된 애플리케이션들의 이름과 아이콘을 가져와서 AppInfo 클래스에 담고,
Observable<AppInfo> 형태로 반환해주는 것이죠.
받은 정보를 가지고 onStart() 메서드에서 구독을 합니다.
그리고 AppInfo 데이터를 하나씩 구독할 때마다
apdater.update(item);
adapter.notifyDataSetChanged();
'RxJava2, RxAndroid2' 카테고리의 다른 글
[RxAndroid2] Timer, TimerTask, CountDownTimer -> RxAndroid 로 바꿔보기 (0) | 2018.10.10 |
---|---|
[RxAndroid2] RxAndroid로 안드로이드 스레드 대체하기. AndroidSchedulers.mainThread() (2) | 2018.10.10 |
[RxAndroid2] RxAndroid 란? (0) | 2018.10.05 |
[RxJava2] 스케줄러 종류와 사용 법 : newThread(), computation(), io(), trampoline(), single(), from(executor) (0) | 2018.10.04 |
[RxJava2] 스케줄러 Schedulers (0) | 2018.10.02 |