0、第三篇就分析一下statistics包吧,这也是一个页面,让我们看看大牛怎么用MVP写一个页面的
1、老规矩,先看interface
/**
* This specifies the contract between the view and the presenter.
* 在View和presenter之间指定一个contract用来,哈哈,管理他们呗
*/
public interface StatisticsContract {
/**
* 业务逻辑的动作之后(交互、页面初始化),View的变化
*/
interface View extends BaseView<Presenter> {
void setProgressIndicator(boolean active); //设置显示进度条
void showStatistics(int numberOfIncompleteTasks, int numberOfCompletedTasks); //展示Task的统计情况
void showLoadingStatisticsError(); //展示加载统计错误的信息,当发生错误时,View上要有个提示
boolean isActive(); //判断fragment是否已经依附到Activity上
}
/**
* 在Statistics页下的能有哪些动作呢?只是实现BasePresenter,看来这个页面只是做了一个展示的用途
* 在Statistics下,现在没有什么交互的业务逻辑,只有用来展示数据的需求业务逻辑,所以里面的方法都是空的
* 这里把业务逻辑分为两部分:
* 1、展示部分,最基本的需求,Presenter下如果不需要重新刷数据啥的,就不用写动作了
* 2、交互部分,Presenter下都是交互部分的方法
* 大牛为什么这么牛逼
*/
interface Presenter extends BasePresenter {
}
}
2、再看Activity吧
/**
* Show statistics for tasks.
* 展示Tasks的统计页,这么牛逼
* 入口在 TasksActivity下的options item上
* 看来TasksActivity、StatisticsActivity确实是
*/
public class StatisticsActivity extends AppCompatActivity {
private DrawerLayout mDrawerLayout; //View引用
/**
* 生命周期方法
* @param savedInstanceState Bundle
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.statistics_act); //初始化布局
// Set up the toolbar.初始化tool bar
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar ab = getSupportActionBar();
ab.setTitle(R.string.statistics_title); //设置标题
ab.setHomeAsUpIndicator(R.drawable.ic_menu); //设置图标
ab.setDisplayHomeAsUpEnabled(true); //设置显示Home按钮可以返回吗?
// Set up the navigation drawer. 初始化DrawerLayout
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerLayout.setStatusBarBackground(R.color.colorPrimaryDark); //设置状态栏颜色
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); //获取DrawerLayout顶部的那块View
if (navigationView != null) {
setupDrawerContent(navigationView); //初始化DrawerLayout左侧边栏的所有View
}
StatisticsFragment statisticsFragment = (StatisticsFragment) getSupportFragmentManager()
.findFragmentById(R.id.contentFrame); //通过Layout的id,获取fragment
if (statisticsFragment == null) { //如果fragment为null
statisticsFragment = StatisticsFragment.newInstance(); //创建一个fragment对象
ActivityUtils.addFragmentToActivity(getSupportFragmentManager(), //将fragment依附到Activity下指定Layout的id处
statisticsFragment, R.id.contentFrame); //不通xml文件中的View,id可以相同,Android可以识别出来
}
new StatisticsPresenter( //这里创建Presenter
Injection.provideTasksRepository(getApplicationContext()), statisticsFragment); //创建TasksRepository,
}
/**
* 点击Options item,会调用该方法
* @param item
* @return
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home: //home键
// Open the navigation drawer when the home icon is selected from the toolbar.
mDrawerLayout.openDrawer(GravityCompat.START); //当从Tool bar 选择 home图标时,打开左侧抽屉
return true; //返回true
}
return super.onOptionsItemSelected(item); //调用基类的方法,还不知道里面干了啥
}
/**
* 设置左侧边栏的View
* @param navigationView
*/
private void setupDrawerContent(NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.list_navigation_menu_item:
NavUtils.navigateUpFromSameTask(StatisticsActivity.this); //这个方法值得深究一下啊
break; //感觉是返回同一个Task栈中的上一个Activity啊
case R.id.statistics_navigation_menu_item:
// Do nothing, we're already on that screen
break; //点击当前页的item,什么都不做,我们已经在这个屏幕了
default:
break;
}
// Close the navigation drawer when an item is selected.
menuItem.setChecked(true); //当drawerLayout的item被选择的时候,色纸menuItem的checked状态为true
mDrawerLayout.closeDrawers(); //关闭左侧边栏
return true; //返回true,事件被消费了吗
}
});
}
}
3、再看Presenter实现类,欧耶
/**
* Listens to user actions from the UI ({@link StatisticsFragment}), retrieves the data and updates
* the UI as required.
*/
public class StatisticsPresenter implements StatisticsContract.Presenter {
private final TasksRepository mTasksRepository;
private final StatisticsContract.View mStatisticsView;
public StatisticsPresenter(@NonNull TasksRepository tasksRepository,
@NonNull StatisticsContract.View statisticsView) {
mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null");
mStatisticsView = checkNotNull(statisticsView, "StatisticsView cannot be null!");
mStatisticsView.setPresenter(this);
}
/**
* 好吧,最先被调用的方法
*/
@Override
public void start() {
loadStatistics(); //fragment下的onResume(),在首次执行时,就调用了onResume()方法
}
private void loadStatistics() {
mStatisticsView.setProgressIndicator(true); //先显示一个进度条
// The network request might be handled in a different thread so make sure Espresso knows
// that the app is busy until the response is handled.
EspressoIdlingResource.increment(); // App is busy until further notice //自动化测试部分
mTasksRepository.getTasks(new TasksDataSource.LoadTasksCallback() { //去仓库里拿Task
@Override
public void onTasksLoaded(List<Task> tasks) {
int activeTasks = 0; //活动的Tasks,计数
int completedTasks = 0; //完成的Tasks,计数
// This callback may be called twice, once for the cache and once for loading
// the data from the server API, so we check before decrementing, otherwise
// it throws "Counter has been corrupted!" exception.
// 测试用的吧
if (!EspressoIdlingResource.getIdlingResource().isIdleNow()) {
EspressoIdlingResource.decrement(); // Set app as idle.
}
// We calculate number of active and completed tasks
for (Task task : tasks) { //遍历Tasks
if (task.isCompleted()) { //如果task是已经完成的
completedTasks += 1; //completedTasks加1
} else {
activeTasks += 1; //否则activeTasks加1
}
}
// The view may not be able to handle UI updates anymore
if (!mStatisticsView.isActive()) { //如果fragment没有依附到Activity,直接return
return;
}
mStatisticsView.setProgressIndicator(false); //不展示进度条
mStatisticsView.showStatistics(activeTasks, completedTasks); //调用fragment的show方法,把completed、active的数量传过去
}
/**
* 如果没有获得数据
*/
@Override
public void onDataNotAvailable() {
// The view may not be able to handle UI updates anymore
if (!mStatisticsView.isActive()) {
return; //fragment没有依附到Activity上,直接中断方法
}
mStatisticsView.showLoadingStatisticsError(); //在fragment上展示加载错误的view
}
});
}
}
4、再看Fragment
/**
* Main UI for the statistics screen.
* 作者牛逼啊,就一个页面,也一样要用fragment
*/
public class StatisticsFragment extends Fragment implements StatisticsContract.View {
private TextView mStatisticsTV;
private StatisticsContract.Presenter mPresenter;
/**
* 静态方法
* @return 返回一个fragment对象嘛
*/
public static StatisticsFragment newInstance() {
return new StatisticsFragment();
}
/**
* 从StatisticsContract.View上实现的方法
* @param presenter
*/
@Override
public void setPresenter(@NonNull StatisticsContract.Presenter presenter) {
mPresenter = checkNotNull(presenter);
}
/**
* 生命周期方法
* @param inflater
* @param container
* @param savedInstanceState
* @return
*/
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.statistics_frag, container, false); //初始化View
mStatisticsTV = (TextView) root.findViewById(R.id.statistics); //嘿嘿,拿到一个TextView
return root;
}
/**
* 生命周期方法
*/
@Override
public void onResume() {
super.onResume();
mPresenter.start(); //fragment初始化时,直接调用presenter的start()
}
/**
* 设置是否展示进度状态
* @param active
*/
@Override
public void setProgressIndicator(boolean active) {
if (active) { //有活动行为,展示Loading字符串状态
mStatisticsTV.setText(getString(R.string.loading)); //就是在TextView展示一个Loading
} else {
mStatisticsTV.setText(""); //如果active为false
}
}
/**
* 展示计数的方法
* @param numberOfIncompleteTasks
* @param numberOfCompletedTasks
*/
@Override
public void showStatistics(int numberOfIncompleteTasks, int numberOfCompletedTasks) {
if (numberOfCompletedTasks == 0 && numberOfIncompleteTasks == 0) { //如果活动Task和完成Task都是0的话
mStatisticsTV.setText(getResources().getString(R.string.statistics_no_tasks)); //看来是用了一个View啊
} else {
String displayString = getResources().getString(R.string.statistics_active_tasks) + " "
+ numberOfIncompleteTasks + "\n" + getResources().getString(
R.string.statistics_completed_tasks) + " " + numberOfCompletedTasks; //拼接字符串
mStatisticsTV.setText(displayString); //显示内容
}
}
/**
* 加载内容时,设置错误内容
*/
@Override
public void showLoadingStatisticsError() {
mStatisticsTV.setText(getResources().getString(R.string.statistics_error));
}
/**
* 判断fragment是否已经依附到Activity上
* @return 是否依附到activity上的状态
*/
@Override
public boolean isActive() {
return isAdded();
}
}