Android之官方MVP例子分析(第三篇statistics包)

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();
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值