2017-03-07 2 views
1

私は既存のアプリケーションで、MVPアーキテクチャに移行しています。 RecyclerView.Adapterのうちの1つでは、ヘッダViewがどのように見えるかに関して、かなりの論理があります。 MVPアーキテクチャによれば、そのようなロジックはPresenterに移動され、発表者はのものをと表示するにはViewを使用する必要があります。また、プレゼンターにAndroidのクラスがあるとどういうことがあるのか​​、それは基本的には何かが間違っていることを示しています。Android MVP - Androidクラスに依存してロジックを操作する方法は?

だから私の考えでは、これまでViewHolderMVP観点からもView)が作成されたときViewHolderためPresenterを作成し、そこに私のロジックを移動させるためのものです。しかし、私が抱えている問題は、ロジックがPaintRectSpannableなどのAndroidクラスに基づいているということです。

どうすればこの問題をできるだけクリーンな方法で解決できますか?すべてのロジックをViewに移動しますか?または、ロジックを私のPresenterに保持する必要がありますが、特定のAndroidオブジェクトに関連する計算だけをViewに移動しますか?プレゼンターに

:それのようになります。一例として

ビューで
double textLines = mView.getTextLines(text, 0 , text.length()); 

Paint paint = mTextView.getPaint(); 
Rect bounds = new Rect(); 
paint.getTextBounds(text, start, end, bounds); 
double parentWidth = parentView.getWidth() - parentView.getPaddingLeft() - parentView 
      .getPaddingRight(); 
return Math.ceil((double) bounds.width()/parentWidth); 

それとも別の良い方法はありますか?

答えて

3

Androidのクラスに依存するすべてのコードは、ビューの実装(Activiy、Fragment、ViewHolderなど)に保持する必要があります。ビューは可能な限りダムでなければなりません。 ViewHolderにはプレゼンターが必要ないと思います。なぜなら、通常はロジックを持つべきではないからです。

単体テストがあれば、それをテストすることができるため、別の場所にAndroid依存クラスを移動する必要があるため、プロセスを把握しやすくなります。

たとえば、RecyclerViewの実際のシナリオは、アクティビティのビューインターフェイス、ViewHolderのビューインターフェイス、アダプタのプレゼンター、アクティビティのプレゼンターです。以下は、デモのための部分的でコンパイル不可能な例です。ここでは、レイヤー間の懸念の分離を見ることができます。

実際のアンドロイドビューではAndroid APIの実際のクラスとメソッドを使用して取得するため、ビューインタフェースには「どこからでも」という文字列を返すメソッドがあります要求されたデータ

私の例は以下の通りです。

// Definitions for the event adapter stuff 
public interface EventAdapterContract { 
    interface View { 
     void onFetchEventsFailed(String reason); 
     void notifyDataSetChanged(); 
    } 

    interface Presenter { 
     void getItemViewType(int position); 
     void getItemCount(); 
     void bindEventRow(int position, ViewHolder holder, int backgroundColor); 
    } 

    interface ViewHolder { 
     void setTitle(String value); 
     void setHour(String value); 
     void setBackgroundColor(int color); 
    } 
} 

// Adapter presenter implementation. Again, partial code for simplicity 
public class EventAdapterPresenter implements EventAdapterContract.Presenter { 
    private final EventAdapterContract.View view; 
    private final List<Event> events; 

    static int VIEW_FINISHED = 0; 
    static int VIEW_pending = 0; 

    public EventAdapterPresenter(EventAdapterContract.View view, EventAPI api) { 
     this.view = view; 
     this.events = new ArrayList<>(); 

     // EventAPI is an interface (Retrofit in this case), which can 
     // also be tested with plain junit 
    } 

    @Override 
    public int getItemCount() { 
     return events.size(); 
    } 

    @Override 
    public int getItemViewType(int position) { 
     Event item = events.get(position); 
     return item.isFinished() ? VIEW_FINISHED : VIEW_PENDING; 
    } 

    @Override 
    public void bindEventRow(int position, EventAdapterContract.ViewHolder holder, int backgroundColor) { 
     Event event = events.get(position); 
     holder.setTitle(event.getTitle()); 
     holder.setHour(String.format("Event time: %s", event.getStartTime())); 
     holder.setBackgroundColor(backgroundColor); 
    } 
} 



// The adapter itself. Please mind that this is a partial 
// piece of code just for the sake of demonstration, 
// I ommited several parts to keep it simple 
public class EventAdapter 
    extends RecyclerView.Adapter<RecyclerView.ViewHolder> 
    implements EventAdapterContract.View { 

    private EventAdapterContract.Presenter presenter; 

    public class EventAdapter(Contex context) { 
     // Regular adapter contructor 
     // ... 
     presenter = new EventAdapterPresenter(this, someImplOfEventApi); 
    } 

    @Override 
    public void onFetchEventsFailed(String reason) { 
     // Show an AlertDialog 
    } 

    @Override 
    public int getItemViewType(int position) { 
     return presenter.getItemViewType(position); 
    } 

    @Override 
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 
     int backgroundColor = ContextCompat.getColor(context, R.color.colorEventPending); 
     presenter.bindEventRow(position, holder, backgroundColor); 
    } 
} 

public class EventRowViewHolder 
    extends RecyclerView.ViewHolder 
    implements View.OnClickListener, EventAdapterContract.ViewHolder.Row { 

    private TextView title; 
    private TextView hour; 

    public EventRowViewHolder(View view) { 
     super(view); 
     // init widgets etc... 
     view.setOnClickListener(this); 
    } 

    @Override 
    public void setTitle(String value) { 
     title.setText(value); 
    } 

    @Override 
    public void setHour(String value) { 
     hour.setText(value); 
    } 

    @Override 
    public void setBackgroundColor(int color) { 
     this.itemView.setBackgroundColor(color); 
    } 

    @Override 
    public void onClick(View view) { 
     EventBus.getDefault().post(new OpenEventDetailsMessage(orderId)); 
    } 
} 
+1

確認していただきありがとうございます。うん、 'ViewHolder'自体にロジック/プレゼンターは必要ないと私は同意します。論理は結合のためのものであり、すなわち「アダプタ」のためのものである。もう一度ありがとう、非常に役立つ – vkislicins

関連する問題