Diycode开源项目 MyTopicActivity分析

1.总体浏览效果及布局分析

1.1.看一下我的帖子预览效果

  

 

1.2.然后看一下我的收藏预览效果

  

 

1.3.归纳一下

  所以我的帖子和我的收藏可以共用同一个类。

  布局效果几乎一样,只是用户的选择不同。

  所以今天我研究的就是共用的同一个类MyTopicActivity。

 

1.4.中间这个活动就是MyTopicActivity。布局为:activity_fragment.

  1.4.1.看一下布局的源代码。  

<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright 2017 GcsSloop
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~    http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  ~
  ~ Last modified 2017-04-09 19:39:57
  ~
  ~ GitHub:  https://github.com/GcsSloop
  ~ Website: http://www.gcssloop.com
  ~ Weibo:   http://weibo.com/GcsSloop
  -->

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_topic"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.gcssloop.diycode.activity.TopicActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <FrameLayout
        android:id="@+id/fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>
View Code

 

  1.4.2.布局对应实体关系。

      

 

  1.4.3.分析整体布局

      外层是一个LinearLayout线性布局。

      然后是Toolbar标题栏。

     然后是FrameLayout布局。

     深入理解FrameLayout布局点击我!


2.分析MyTopicActivity中的成员变量及部分函数

2.1.预览一下所有的变量。

  

  这里使用了一个DataCache类,在通用类中的数据缓存工具,之前分析过。

  然后使用了一个枚举类型,enum InfoType{MY_TOPIC,MY_COLLECT}

  代表我的话题,我的收藏。

  建立一个枚举类型的变量,初始化为我的话题。

 

2.2.建立一个新的实例。

  

  在外部可以直接用MyTopicActivity.newInstance来建立一个实例,来打开这个话题列表。

 

2.3.获取布局资源id。

  

 

2.4.初始化数据。

  

  在BaseActivity中执行顺序为:

    getLayoutId()==>initActionBar()==>initDatas()==>initViews()

  首先获取SDK中API的单例,然后建立一个缓存类。

  然后获取intent中的枚举类型,如果为空就默认“我的话题”。 


3.MyTopActivity关键函数initViews分析

3.1.首先看一下源代码。 

 @Override
    protected void initViews(ViewHolder holder, View root) {
        if (!mDiycode.isLogin()) {
            toastShort("用户未登录");
            return;
        }

        // 获取用户名
        if (mDataCache.getMe() == null) {
            try {
                UserDetail me = mDiycode.getMeNow();
                mDataCache.saveMe(me);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        String username = mDataCache.getMe().getLogin();

        // 初始化 Fragment
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();

        if (current_type == InfoType.MY_COLLECT){
            setTitle("我的收藏");
            UserCollectionTopicFragment fragment1 = UserCollectionTopicFragment.newInstance(username);
            transaction.add(R.id.fragment, fragment1);
        } else if (current_type == InfoType.MY_TOPIC){
            setTitle("我的话题");
            UserCreateTopicFragment fragment2 = UserCreateTopicFragment.newInstance(username);
            transaction.add(R.id.fragment, fragment2);
        }
        transaction.commit();
    }
View Code

 

3.2.预览一下这个函数。

  

 

3.3.第一个if

  判断是否登录==>如果没有,就不存在我的话题和我的收藏了。

 

3.4.第二个if

  判断缓存中有没有我的信息,如果没有,调用API获得并存进缓存,如果有,那继续。

  

3.5.然后初始化碎片。

  采用方式:开启事务模式。

  

  先从活动中得到FragmentManager,然后开启事务,动态加载碎片。

  然后判断枚举类型

  

  最后提交事务  

  transaction.commit()。


4.分析两个碎片

4.1.我的话题==>UserCreateTopicFragment源代码

/*
 * Copyright 2017 GcsSloop
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Last modified 2017-04-09 20:34:58
 *
 * GitHub:  https://github.com/GcsSloop
 * Website: http://www.gcssloop.com
 * Weibo:   http://weibo.com/GcsSloop
 */

package com.gcssloop.diycode.fragment;

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;

import com.gcssloop.diycode.fragment.base.SimpleRefreshRecyclerFragment;
import com.gcssloop.diycode.fragment.provider.TopicProvider;
import com.gcssloop.diycode_sdk.api.topic.bean.Topic;
import com.gcssloop.diycode_sdk.api.user.event.GetUserCreateTopicListEvent;
import com.gcssloop.recyclerview.adapter.multitype.HeaderFooterAdapter;

/**
 * 用户创建的 topic 列表
 */
public class UserCreateTopicFragment extends SimpleRefreshRecyclerFragment<Topic,
        GetUserCreateTopicListEvent> {
    private static String Key_User_Login_Name = "Key_User_Login_Name";
    private String loginName;

    public static UserCreateTopicFragment newInstance(String user_login_name) {
        Bundle args = new Bundle();
        args.putString(Key_User_Login_Name, user_login_name);
        UserCreateTopicFragment fragment = new UserCreateTopicFragment();
        fragment.setArguments(args);
        return fragment;
    }

    @Override public void initData(HeaderFooterAdapter adapter) {
        Bundle args = getArguments();
        loginName = args.getString(Key_User_Login_Name);
        loadMore();
    }

    @Override
    protected void setAdapterRegister(Context context, RecyclerView recyclerView,
                                      HeaderFooterAdapter adapter) {
        adapter.register(Topic.class, new TopicProvider(context));
    }

    @NonNull @Override protected String request(int offset, int limit) {
        return mDiycode.getUserCreateTopicList(loginName, null, offset, limit);
    }
}
View Code

 

4.2.分析我的话题 Fragment源代码

  继承了可以刷新,加载的一个片段==>SimpleRefreshRecyclerFragment<Topic,GetUserCreateTopicListEvent>

  后者GetUserCreateTopicListEvent不用管,是API中定义的一个事件。

  

  4.2.1.分析成员变量。

      

      主要有一个用户的登录名,用来请求服务器。

     还有一个静态的字段,临时存储作用。

 

  4.2.2.开启新的实例。

      

      以用户名为参数,返回一个碎片。

     直接新建一个类,传递了用户名的信息放入Bundle。

 

  4.2.3.初始化数据。

      

      采用了借刀杀人的战术,将Bundle中的数据存入本类。然后利用本类的另一个函数去请求API。

      然后默认加载更多。

     loadMore()定义在RefreshRecyclerFragment中,这里面去request数据。

 

  4.2.4.设置适配器。

      

      因为我的话题和我的收藏有可能没有,所以也包含了一个头部和尾部的适配器HeaderFooterAdapter。

      采用的基类为Topic,采用的提供者为TopicProvider(context)

 

  4.2.5.请求数据。

      这个方法定义在RefreshRecyclerFragment中。

     

     作用:实质上请求API,采用了分页效果,所以有offset和limit。

 

4.3.我的收藏==>UserCollectionTopicFragment源代码

/*
 * Copyright 2017 GcsSloop
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Last modified 2017-04-09 20:45:09
 *
 * GitHub:  https://github.com/GcsSloop
 * Website: http://www.gcssloop.com
 * Weibo:   http://weibo.com/GcsSloop
 */

package com.gcssloop.diycode.fragment;

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;

import com.gcssloop.diycode.fragment.base.SimpleRefreshRecyclerFragment;
import com.gcssloop.diycode.fragment.provider.TopicProvider;
import com.gcssloop.diycode_sdk.api.topic.bean.Topic;
import com.gcssloop.diycode_sdk.api.user.event.GetUserCollectionTopicListEvent;
import com.gcssloop.recyclerview.adapter.multitype.HeaderFooterAdapter;

/**
 * 用户收藏的 topic 列表
 */
public class UserCollectionTopicFragment extends SimpleRefreshRecyclerFragment<Topic,
        GetUserCollectionTopicListEvent> {
    private static String Key_User_Login_Name = "Key_User_Login_Name";
    private String loginName;

    public static UserCollectionTopicFragment newInstance(String user_login_name) {
        Bundle args = new Bundle();
        args.putString(Key_User_Login_Name, user_login_name);
        UserCollectionTopicFragment fragment = new UserCollectionTopicFragment();
        fragment.setArguments(args);
        return fragment;
    }

    @Override public void initData(HeaderFooterAdapter adapter) {
        Bundle args = getArguments();
        loginName = args.getString(Key_User_Login_Name);
        loadMore();
    }

    @Override
    protected void setAdapterRegister(Context context, RecyclerView recyclerView,
                                      HeaderFooterAdapter adapter) {
        adapter.register(Topic.class, new TopicProvider(context));
    }

    @NonNull @Override protected String request(int offset, int limit) {
        return mDiycode.getUserCollectionTopicList(loginName, offset, limit);
    }
}
View Code

 

4.4.分析我的收藏 Fragment源代码。

  继承了可以刷新,加载的一个片段==>SimpleRefreshRecyclerFragment<Topic,GetUserCollectionTopicListEvent>

  后者GetUserCollectionTopicListEvent不用管,是API中定义的一个事件。

  

  4.4.1.分析成员变量。

      

      主要有一个用户的登录名,用来请求服务器。

     还有一个静态的字段,临时存储作用。

 

  4.4.2.开启新的实例。

      

      以用户名为参数,返回一个碎片。

     直接新建一个类,传递了用户名的信息放入Bundle。

 

  4.4.3.初始化数据。

      

      采用了借刀杀人的战术,将Bundle中的数据存入本类。然后利用本类的另一个函数去请求API。

      然后默认加载更多。

     loadMore()定义在RefreshRecyclerFragment中,这里面去request数据。

 

  4.4.4.设置适配器。

      

      因为我的话题和我的收藏有可能没有,所以也包含了一个头部和尾部的适配器HeaderFooterAdapter。

      采用的基类为Topic,采用的提供者为TopicProvider(context)

 

  4.4.5.请求数据。

      这个方法定义在RefreshRecyclerFragment中。

     

     作用:实质上请求API,采用了分页效果,所以有offset和limit。


5.总结一下

5.1.理解了把我的话题和我的收藏放在一起,因为收藏的只能是话题,所以我的话题和我的收藏都是同一个活动。

  如何区分的?由碎片+枚举来完成。枚举是为了区分intent中获得type是话题还是收藏,然后选择不同的碎片。

 

5.2.理解了为什么很多活动都有一个newInstance的静态函数,用了打开本身。比如一个其他活动的按钮,点击后,

  直接跳转到这个活动,直接调用这个活动的newInstance函数岂不是很方便,耦合性也低,nice啊。

 

5.3.理解了为什么要把initDatas函数放在initViews之前执行,因为要获取缓存数据,以及如何请求的问题,数据

  互相之间是有关联的,从一个数据到另一个数据,必然存在一个纽带,首先要从initDatas找到这个纽带,然后

  去API中请求数据,得到数据之后,将数据完美显示在视图中又是另外一个过程。

 

5.4.理解了碎片的加载过程,首先要从活动中getSupportFragmentManager(),然后开启一个事务,然后transaction

  来动态添加这个碎片类到一个布局中,这个布局应该是主活动的一个FrameLayout视图,这里的意义就是当前

  共用活动中的FrameLayout布局的id,最后transaction.commit()一下就好了。

 

5.5.一个注意点,缓存问题,首先一定要从我的缓存类中获取一下,如果获取不到,再去请求API,这样才能显示缓

  存的意义。同时,如果之前没有缓存,那么API请求到数据后,一定要加入缓存。

 

posted @ 2017-11-20 14:11  Jason_Jan  阅读(299)  评论(0编辑  收藏  举报