일단 안드로이드에 대해 기본적인 지식이 있으며, MVP패턴이 어떤 장점들을 가지고 있는지 알고 이 글을 읽는다고 가정하고 어떤 방식으로 프로젝트에서 MVP패턴을 사용하고 있는지 공유하고 피드백 받고싶습니다.
액티비티에서 서버로 부터 요청을 통해 응답받은 것을 화면에 보여주는 시나리오를 통해 예시를 들려고 합니다!
* 기본적으로 모든 데이터는 presenter를 통해 이동하고 있으며 모델과 뷰는 서로를 모르고 있습니다. Input은 view를 통해 들어옵니다.
그럼 바로 시작-
Presenter를 만들기전 필요한 기능이 있는 인터페이스를 만들어줘야 합니다.
저는 간단하게 이정도로 선언해줬습니다. 여기서도 저희가 사용할 메소드는 requestSendImgApi로 imagePath 파라미터를 제외하고는 Nullable 하게 구성하였습니다.
*네이밍은 편하시게 하세요. 대부분은 ResultPresenterImpl 정도로 하더라구요. 저는 익숙하지 않아 그냥 앞아 I를 붙여줍니다.
public interface IResultPresenter {
void requestOcrApi(String imageUrl);
void requestSendImgApi(String brand, String imagePath, String type, String modelType);
}
그럼 이 인터페이스를 implement 할 클래스가 필요하겠죠?
requestOcrApi가 오버라이드 된 메소드는 혼란을 드릴거 같아서 과감히 제거하였습니다.
코드에 대해 간단하게 설명드리자면 ResultPresenter의 생성자는 2개의 파라미터를 받고 있으며, 액티비티의 Context와 IResultView로 구성되어 있습니다.
IResultView는 인터페이스로 requestSendImgApi메소드가 완료되고 어떤 화면에 변화가 있을때 필요한 메소드들의 선언을 담고 있습니다.
아래의 view.startIntro(); 서버와 통신을 하기전 Animation을 보여주는 부분이며, 통신이 성공한 경우, view.setSimilarityImgList()메소드를 실행하여, 받아온 이미지와 메타데이터를 아답터로 보내 갱신시키는 부분입니다. 그후 view.stopIntro()하여 Animation을 종료합니다.
ProductServiceManager는 상품 서비스를 관리해주는 클래스로 통신에 대한 부분들이 들어있는 클래스로 안에 존재하는 메소드는 static으로 작성하고 있습니다.
observeOn은 Rxjava에 존재하는 메소드로 subscribe의 스케쥴로를 변경할수 있게 해주는 메소드로 안드로이드에서는 MainThread에서만 UI의 변경을 할 수 있으므로 AndroidSchedulers.mainThread로 바꿔주고 있습니다.
public class ResultPresenter implements IResultPresenter {
private Context context;
private IResultView view;
private Ocr data;
public ResultPresenter(Context context, IResultView view) {
this.context = context;
this.view = view;
}
@Override
public void requestSendImgApi(String brand, String imagePath, String type, String modelType) {
view.startIntro();
ProductServiceManager
.post(brand, imagePath, type, modelType)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Response<BaseResponse<Result>>>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
Ln.d(e.toString());
view.stopIntro();
}
@Override
public void onNext(Response<BaseResponse<Result>> baseResponseResponse) {
view.setSmilarityImgList(baseResponseResponse.body().mResult.mDataList);
view.stopIntro();
}
});
}
}
ProductServiceManager, ProductService 클래스는 이정도로 구성되어 있습니다.
BaseUrl은 Retrofit 객체를 만들때 빌더패턴으로 넣어줬습니다.
public interface ProductService {
@Multipart
@POST("api/project/search/")
Observable<Response<BaseResponse<Result>>> postPicDescription(@Part MultipartBody.Part image
, @Part("brand") RequestBody brand
, @Part("class_type") RequestBody itemType
, @Part("model_type")RequestBody modelType);
}
public class ProductServiceManager {
private ProductServiceManager() {
}
private static ProductService service = ServiceDefine.retrofit.create(ProductService.class);
public static Observable<Response<BaseResponse<Result>>> post(String brand, String imagePath
, String type, String modelType) {
MultipartBody.Part image = null;
RequestBody itemBrand = null;
RequestBody classType = null;
RequestBody itemModelType = null;
if (imagePath != null) {
image = getMultipartBody(imagePath);
}
if (brand != null) {
itemBrand = RequestBody.create(okhttp3.MultipartBody.FORM, brand);
}
if (type != null) {
classType = RequestBody.create(okhttp3.MultipartBody.FORM, type);
}
if (modelType != null) {
itemModelType = RequestBody.create(MultipartBody.FORM, modelType);
}
return service.postPicDescription(image, itemBrand, classType, itemModelType)
.subscribeOn(ServiceHelper.getPriorityScheduler(Priority.MEDIUM))
.lift(new ServiceErrorChecker<>(new BaseServiceErrorChecker<Result>()));
}
private static MultipartBody.Part getMultipartBody(String imagePath) {
if (imagePath == null) {
return null;
}
File file = new File(imagePath);
RequestBody requestFile = RequestBody.create(MediaType.parse("mImage/*"), file);
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestFile);
return body;
}
}
그럼 이제 사용하는 것만 남은 것 같습니다?
액티비티 클래스에서 선언 해주고
private ResultPresenter presenter;
onCreate()문에서 초기화 해줍니다.
위의 Presenter 생성자에서 볼수 있었지만 Context와 IResultView를 받고있습니다.
presenter = new ResultPresenter(this, this);
ResultActivity클래스는 이런식으로 구성되어 있어있습니다. 그래서 this키워드를 사용하여 초기화하고있습니다.
public class ResultAcitivity extends DepthActivity implements IResultView, RecyclerViewItemClickListener {
이제 Presenter를 통해 서버로 요청을 해봅니다. 마찬가지로 onCreate문 안에서 작성되었습니다.
presenter.requestSendImgApi("K쇼핑", mFilePath, "K-SHOPPING", mModelType); 이부분이 요청하는 부분입니다!
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
ButterKnife.bind(this);
presenter = new ResultPresenter(this, this);
Intent intent = getIntent();
Bundle args = intent.getExtras();
if(intent != null && args != null ) {
//load to album mode
decodePicData(args);
} else {
//take pic mode
loadToPicData();
}
mFilePath = saveBitmapTemp(this, mServerBitmap, makeUniqueFileName());
//requestOcrApi
presenter.requestOcrApi(mOcrFilePath);
//requestSendApi [mock data]
presenter.requestSendImgApi("K쇼핑", mFilePath, "K-SHOPPING", mModelType);
initRecyclerView();
}
통신이 잘 되었다면 ResultPresneter의 requestSendImgApi메소드의 onNext부분으로 서버에서 오는 값들이 있겠지요!
@Override
public void onNext(Response<BaseResponse<Result>> baseResponseResponse) {
view.setSmilarityImgList(baseResponseResponse.body().mResult.mDataList);
view.stopIntro();
}
그럼 setSmilarityImgList() 메소드를 실행할 차례입니다. 그전에 IResultView를 보면 저런 메소드 들을 담고 있습니다. 화면을 제어하는 함수들입니다.
public interface IResultView {
void setOcrText(Ocr text);
void setSmilarityImgList(List<Product> item); 사용할 메소드!
void sendToServer();
void showLoadingBar();
void hideLoadingBar();
void startIntro();
void stopIntro();
}
setSmilarityImgList()메소드는 액티비티코드에서 이런식으로 구현되어 있습니다.
@Override
public void setSmilarityImgList(List<Product> item) {
if (item != null) {
cameraAdapter.clear(); 기존의 데이터를 삭제하고
cameraAdapter.addAll(item); 서버에서 보내준 데이터를 넣어준뒤
cameraAdapter.notifyDataSetChanged(); 새로고침!
}
}
그럼 끝
'Android > 미분류' 카테고리의 다른 글
fire tracking sequence diagram (0) | 2018.01.09 |
---|---|
Fire detection for mobile (5) | 2017.11.17 |
안드로이드 객체 추출 최종결과 (2) | 2017.09.21 |
안드로이드 객체 추출 사주일차 (7) | 2017.08.14 |
안드로이드 객체 추출 삼주일차 (0) | 2017.08.14 |