android mvp demo


一、项目功能说明

APP获取好友列表后将数据展示在一个ListView中,点击Item会打开一个新页面展示好友详细信息。

二、项目结构

android mvp demo_第1张图片

示例将代码分为四层,对应到MVP模式中:

  • Mode:Entities
  • Presenter:Use Cases+Presenters
  • View:UI
为了保证每个层都能方便的进行单元测试并和其它层相对独立,将项目分为三个模块,Presentation、Domain和Data。
android mvp demo_第2张图片

1)Presentation

Presenters和UI被划分到这一层,但Presenters在这里只是负责将Domain逻辑处理后的数据进行组装并调度UI显示,没有业务处理逻辑。这样将数据逻辑处理划分给Domain可以让Presenter更关注于UI显示的调度,从而避免Present逻辑的冗余。这也是我选择这个工程作为示例的原因。

2)Domain

这里对Data中的数据进行逻辑处理,为Present提供业务逻辑和数据支持。

3)Data

数据仓库。例如,当通过id获取用户数据时,首先会检测用户信息是否已经存储在本地,否则的话就会从服务器获取后在本地缓存。根据上篇博客提到的设计原则,外圆代码逻辑无需关心用户数据是从存储介质、内存还是服务器获取,只需拿到Domain处理好的最终数据进行展示和交互即可。


三、代码详解

通过获取用户详细信息这个功能分析各个层级之间的调度及数据传递方向和方式。

data 层

data 模块,把要提供的数据封装好,只向domain层提供UserRepository 接口

/**
 * Copyright (C) 2014 android10.org. All rights reserved.
 * @author Fernando Cejas (the android10 coder)
 */
package com.guo.data;


import java.util.List;


import com.guo.bean.User;


/**
 * Interface that represents a Repository for getting {@link User} related data.
 */
public interface UserRepository {
  /**
   * Callback used to be notified when either a user list has been loaded or an error happened.
   */
  interface UserListCallback {
    void onUserListLoaded(List usersCollection);


    void onError(ErrorBundle errorBundle);
  }


  /**
   * Callback used to be notified when either a user has been loaded or an error happened.
   */
  interface UserDetailsCallback {
    void onUserLoaded(User user);


    void onError(ErrorBundle errorBundle);
  }


  /**
   * Get a collection of {@link User}.
   *
   * @param userListCallback A {@link UserListCallback} used for notifying clients.
   */
  void getUserList(UserListCallback userListCallback);


  /**
   * Get an {@link User} by id.
   *
   * @param userId The user id used to retrieve user data.
   * @param userCallback A {@link UserDetailsCallback} used for notifying clients.
   */
  void getUserById(final int userId, UserDetailsCallback userCallback);
}


domain层

domain层主要负责数据回调和加载数据的业务处理,向上层提供接口,如GetUserDetailUserCase

GetUserDetailUserCase的代码如下:

package com.guo.domain;
import com.guo.bean.User;
import com.guo.data.ErrorBundle;
public interface GetUserDetailUserCase extends Runnable{
	interface Callback{
		void onUserDetailLoad(User user);
		void onError(ErrorBundle error);
	}
	
	void execute(int userId,Callback callback);
}
//GetUserDetailUserCase 的实现GetUserDetailUserCaseImp 如下所示:
package com.guo.domain;
import com.guo.bean.User;
import com.guo.data.ErrorBundle;
import com.guo.data.UserRepository;
import com.guo.data.UserRepository.UserDetailsCallback;
public class GetUserDetailUserCaseImp implements GetUserDetailUserCase {
	private UserRepository userRepository;
	private ThreadExecutor executor;
	private PostExecutionThread postThread;
	private int userId;
	//回调主界面
	private Callback callBack;
	public GetUserDetailUserCaseImp(UserRepository userRepository,
			ThreadExecutor executor, PostExecutionThread postThread) {
		this.executor = executor;
		this.userRepository = userRepository;
		this.postThread = postThread;
	}




	@Override
	public void run() {
		// TODO Auto-generated method stub
		// executor.execute(this);
		userRepository.getUserById(userId, udCallback);
	}


	@Override
	public void execute(int userId, Callback callback) {
		// TODO Auto-generated method stub
		this.userId = userId;
		this.callBack=callback;
		executor.execute(this);


	}
	//拉取数据后,回调返回数据
	private UserRepository.UserDetailsCallback udCallback = new UserDetailsCallback() {


		@Override
		public void onUserLoaded(User user) {
			// TODO Auto-generated method stub
			getDataSuccess(user);
		}


		@Override
		public void onError(ErrorBundle errorBundle) {
			// TODO Auto-generated method stub
			getDataFail(errorBundle);
		}
	};


	public void getDataSuccess(final User user) {
		postThread.post(new Runnable(){


			@Override
			public void run() {
				// TODO Auto-generated method stub
				callBack.onUserDetailLoad(user);
			}
			
		});
		
	}


	public void getDataFail(final ErrorBundle errorBundle) {
		postThread.post(new Runnable(){


			@Override
			public void run() {
				// TODO Auto-generated method stub
				callBack.onError(errorBundle);
			}
			
		});
		
	}
}


PostExecutionThread 是将回调得到的数据进行处理的线程,一般为主线程(本例中为UIThread,主线程)

ThreadExecutor 是进行数据请求的线程的线程池

例如,从网络中拉取数据,ThreadExecutor 启动一个线程去拉取数据,PostExecutionThread将拉取到的数据更新到主界面


Presentation层

Presenters在这里只是负责将Domain逻辑处理后的数据进行组装并调度UI显示,如GetUserDetailPresent

public class GetUserDetailPresent {
	private GetUserDetailUserCase userDetailCase;
	private int userId;
	private final UserDetailsView viewDetailsView;


	public GetUserDetailPresent(UserDetailsView viewDetailsView,
			GetUserDetailUserCase userDetailCase) {
		this.userDetailCase = userDetailCase;
		this.viewDetailsView = viewDetailsView;
	} 


	private void getUserDetails() {
		this.userDetailCase.execute(this.userId, this.userDetailsCallback);
	}


	private GetUserDetailUserCase.Callback userDetailsCallback = new Callback() {


		@Override
		public void onUserDetailLoad(User user) {
			// TODO Auto-generated method stub
			GetUserDetailPresent.this.showUser(user);
			GetUserDetailPresent.this.hideViewLoading();
		}


		@Override
		public void onError(ErrorBundle error) {
			// TODO Auto-generated method stub
			GetUserDetailPresent.this.hideViewLoading();
			GetUserDetailPresent.this.showError(error);
			GetUserDetailPresent.this.showViewRetry();


		}
	};


	public void showUser(User user) {
		viewDetailsView.renderUser(user);
	}


	public void showError(ErrorBundle error) {
		viewDetailsView.showError(error.getError());
	}


	private void loadUserDetails() {
		this.hideViewRetry();
		this.showViewLoading();
		this.getUserDetails();
	}


	private void showViewLoading() {
		this.viewDetailsView.showLoading();
	}


	private void hideViewLoading() {
		this.viewDetailsView.hideLoading();
	}


	private void showViewRetry() {
		this.viewDetailsView.showRetry();
	}


	private void hideViewRetry() {
		this.viewDetailsView.hideRetry();
	}


	public void initialize(int userId) {
		this.userId = userId;
		this.loadUserDetails();
	}
}


view层

view层则就是界面的组装,如UserDetailActivity

package com.example.mvpmodeltest;


import com.guo.bean.User;
import com.guo.data.GetData;
import com.guo.data.JobExecutor;
import com.guo.data.UserRepository;
import com.guo.domain.GetUserDetailUserCase;
import com.guo.domain.GetUserDetailUserCaseImp;
import com.guo.domain.PostExecutionThread;
import com.guo.domain.ThreadExecutor;
import com.guo.presentation.GetUserDetailPresent;
import com.guo.presentation.UIThread;
import com.guo.presentation.UserDetailsView;


import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;


public class UserDetailActivity extends Activity implements UserDetailsView {
	private TextView tv_email;
	private TextView tv_followers;
	private TextView tv_description;
	private GetUserDetailPresent detailPresent;


	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.view_user_details);
		this.tv_email = (TextView) findViewById(R.id.tv_email);
		this.tv_followers = (TextView) findViewById(R.id.tv_followers);
		this.tv_description = (TextView) findViewById(R.id.tv_description);
		initializePresenter();
		Intent intent=this.getIntent();
		int userId=intent.getIntExtra("userId",-1);
		detailPresent.initialize(userId);
	}


	public void initializePresenter() {
		ThreadExecutor threadExecutor = JobExecutor.getInstance();
		PostExecutionThread postExecutionThread = UIThread.getInstance();
		UserRepository userRepository = new GetData();
		GetUserDetailUserCase detailUserCase = new GetUserDetailUserCaseImp(
				userRepository, threadExecutor, postExecutionThread);
		detailPresent = new GetUserDetailPresent(this, detailUserCase);
	}


	@Override
	public void showLoading() {
		// TODO Auto-generated method stub


	}


	@Override
	public void hideLoading() {
		// TODO Auto-generated method stub


	}


	@Override
	public void showRetry() {
		// TODO Auto-generated method stub


	}


	@Override
	public void hideRetry() {
		// TODO Auto-generated method stub


	}


	@Override
	public void showError(String message) {
		// TODO Auto-generated method stub


	}


	@Override
	public Context getContext() {
		// TODO Auto-generated method stub
		return null;
	}


	@Override
	public void renderUser(User user) {
		// TODO Auto-generated method stub
		System.out.println(user);
		tv_email.setText(user.getEmail());
		tv_followers.setText(user.getFollowers()+"");
		tv_description.setText(user.getDescription());
	}
}

这个demo没有把data层写完善,只是自己做了几个虚假的数据,也没有做缓存, 更详细的内容请看 http://blog.csdn.net/guxiao1201/article/details/40151457 。 原博客将整体分为三个项目来写的,看着有点麻烦,于是我就将这三个项目集成在一起,做了这个demo。 原博客: http://blog.csdn.net/guxiao1201/article/details/40151457



你可能感兴趣的:(android mvp demo)