Android_Month

public class DetailActivity extends AppCompatActivity {

    @BindView(R.id.title_iv)
    ImageView mTitleIv;
    @BindView(R.id.toolbar)
    Toolbar mToolbar;
    @BindView(R.id.collapsing_toolbar_layout)
    CollapsingToolbarLayout mCollapsingToolbarLayout;
    @BindView(R.id.web_view)
    WebView mWebView;
    @BindView(R.id.comments_tv)
    TextView mCommentsTv;
    @BindView(R.id.like_tv)
    TextView mLikeTv;
    private DetailBean mDetailBean;
    private ActionBar mActionBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);

        ButterKnife.bind(this);

        initView();

        initData();
        showData();
    }

    private void initView() {
        // toolbar虽然长得比actionbar好看,但功能还是延用了actionbar
        // 把toolbar当做actionbar使用,就可以使用里面的逻辑了
        setSupportActionBar(mToolbar);
        // 获取toolbar对应的actionbar,操作逻辑
        mActionBar = getSupportActionBar();

        // 设置标题栏左边是否展示返回箭头
        mActionBar.setDisplayHomeAsUpEnabled(true);
    }

    private void showData() {
        // 给折叠toolbar布局设置标题
        mCollapsingToolbarLayout.setTitle(mDetailBean.getTitle());
        mToolbar.setTitle(mDetailBean.getTitle());
        // 标题展开背景
        Glide.with(this)
                .load(mDetailBean.getTitle_bg_url())
                .into(mTitleIv);

        mCommentsTv.setText("评论:" + mDetailBean.getComments());
        mLikeTv.setText("点赞:" + mDetailBean.getLike());

        // 加载html代码
        mWebView.loadDataWithBaseURL(null,
                mDetailBean.getHtmlCode(),
                "text/html",
                "utf-8",
                null);
    }

    private void initData() {
        mDetailBean = new DetailBean();
        mDetailBean.setTitle("美国男同学加我好友");
        mDetailBean.setTitle_bg_url("http://file31.mafengwo.net/M00/21/3C/wKgBs1bz8dmAJqSwAArv_7pK7cI03.groupinfo.w680.jpeg");
        mDetailBean.setComments(128);
        mDetailBean.setLike(256);
        String htmlCode = "";
        for (int i = 0; i < 100; i++) {
            htmlCode += "<div>adasdasdasdsdasdasdsfsddfsdfsdfsdfsdfsdfsdfsd</div><br/>";
        }
        mDetailBean.setHtmlCode(htmlCode);
    }

    // 实现菜单的点击监听,其中可实现toolbar返回按钮的点击监听
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home://
                finish();
                break;
        }
        return super.onOptionsItemSelected(item);
    }
}
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    protected Button mLatestBtn;
    protected Button mBeforeBtn;
    protected LinearLayout mTopContainer;
    protected FrameLayout mFragmentContainer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.setContentView(R.layout.activity_main);

        // 获取最新APK版本信息
        getAPKVersionInfo();
        initView();
    }

    private void initView() {
        mLatestBtn = (Button) findViewById(R.id.latest_btn);
        mLatestBtn.setOnClickListener(MainActivity.this);
        mBeforeBtn = (Button) findViewById(R.id.before_btn);
        mBeforeBtn.setOnClickListener(MainActivity.this);
        mTopContainer = (LinearLayout) findViewById(R.id.top_container);
        mFragmentContainer = (FrameLayout) findViewById(R.id.fragment_container);

        // 展示碎片
        showFragment(NewsFragment.TYPE_LATEST);// 默认展示最新消息碎片
    }

    // 获取最新APK版本信息
    private void getAPKVersionInfo() {
        String newVersionUrl = "https://news-at.zhihu.com/api/4/version/android/2.3.0";

        // 创建OkHttp网络请求客户端
        OkHttpClient client = new OkHttpClient();
        // 创建网络请求对象并设置请求地址、请求方式等操作
        Request request = new Request.Builder()
                .url(newVersionUrl)
                .get()// 不写也行,默认就是get请求方式
                .build();
        // 根据请求对象新建请求任务,执行请求
        Call call = client.newCall(request);
        call.enqueue(new Callback() {

            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                Log.d("1510", "成功获取数据,线程:" + Thread.currentThread().getName());
                // 坑!OkHttp同样具有Call的请求操作,但数据是在子线程中获取到
                // Retrofit框架封装了OkHttp并进行了线程跳转处理,所以Retrofit获取网络数据在主线程

                // 从响应体中获取json字符串
                ResponseBody body = response.body();
                String json = body.string();

                final VersionBean version = new Gson().fromJson(json, VersionBean.class);

                // 手动跳转到主线程,即可更新UI
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Log.d("1510", "成功获取数据,线程:" + Thread.currentThread().getName());
                        Toast.makeText(MainActivity.this, version.getLatest() + ", " + version.getMsg(), Toast.LENGTH_LONG)
                                .show();

                        Log.d("1510", version.getLatest());
                    }
                });
            }

            @Override
            public void onFailure(Call call, IOException e) {
            }
        });
    }

    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.latest_btn) {
            showFragment(NewsFragment.TYPE_LATEST);
        } else if (view.getId() == R.id.before_btn) {
            showFragment(NewsFragment.TYPE_BEFORE);
        }
    }

    // 切换最新消息碎片
    private void showFragment(int type) {
        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.fragment_container, NewsFragment.newInstance(type))
                .commit();
    }

}
public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {

    private Context mContext;
    private List<StoriesBean> mDatas;

    public NewsAdapter(Context context) {
        mContext = context;
        mDatas = new ArrayList<>();
    }

    // 添加数据的操作
    public void addDatas(List<StoriesBean> stories) {
        mDatas.addAll(stories);
        // 一定要刷新界面
        notifyDataSetChanged();
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(mContext)
                .inflate(R.layout.item_news, parent, false);
        // 初始化itemView的点击事件
        initItemListener(itemView, parent);
        return new ViewHolder(itemView);
    }

    // 初始化itemView的点击事件
    // 点击item,咱得能知道被点击item的位置,和item对应的数据
    private void initItemListener(View itemView, ViewGroup parent) {
        // 获取item的父容器RecyclerView,用于监测被点击item的位置
        final RecyclerView parentRecyclerView = (RecyclerView) parent;
        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 父容器获取子控件在布局中的【位置】
                int position = parentRecyclerView.getChildLayoutPosition(v);
                StoriesBean story = mDatas.get(position);

//                // 跳转第二页,咱不这么干
//                Intent intent = new Intent(mContext, DetailActivity.class);
//                mContext.startActivity(intent);

                // 使用EventBus将数据发送到Fragment中
                EventBus.getDefault().post(new SendPositionAndDataEvent(position, story));
            }
        });
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        StoriesBean story = mDatas.get(position);

        holder.mTitleTextView.setText(story.getTitle());

        // 创建Glide配置对象,设置圆图
        RequestOptions options = new RequestOptions()
                .circleCrop();

        Glide.with(mContext)
                .load(story.getImge())
                .apply(options)
                .into(holder.mPicImageView);
    }

    @Override
    public int getItemCount() {
        return mDatas == null ? 0 : mDatas.size();
    }

    static class ViewHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.title_tv)
        TextView mTitleTextView;
        @BindView(R.id.pic_iv)
        ImageView mPicImageView;

        public ViewHolder(View itemView) {
            super(itemView);

            ButterKnife.bind(this, itemView);
        }
    }
}
public class MyApplication extends Application {

    private static Retrofit sRetrofit;

    private static DaoSession sDaoSession;

    @Override
    public void onCreate() {
        super.onCreate();

        initRetrofit();

        initGreenDAO();
    }

    // 参考安卓系统原生的数据库操作方式
    // 1、准备数据库助手SQLiteOpenHelper
    // 1/1、在助手中指定了:数据库文件名,数据库版本号
    // 1/2、初始化数据库时要建表,于是就准备了表名
    // 2、使用助手帮我们创建数据库对象db
    // 3、用db去操作数据库:增删改查

    // 对比greenDAO
    // 0、不再使用数据库助手创建表,根据面向对象思想,把表 -> 类,把列名 -> 类中的属性
    // 应该先去封装数据模型类,添加必要的注解例如表,主键等,make以下工程自动生成必要代码
    // 1、也要创建数据库助手DevOpenHelper
    // 1/1、指定了数据库文件名。默认版本号为1
    // 2、用助手帮我们创建数据库对象,注意:要使用greenDAO框架封装好的数据库对象
    // 3、对比原生操作额外的一项:每次操作数据库其实就是一次和数据库交互的行为,也就是和数据库的一次会话Session
    // 4、在会话中执行具体的操作行为:增删改查(面向对象思想的操作)
    private void initGreenDAO() {
        DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "zhihu.db");
        Database db = helper.getWritableDb();
        sDaoSession = new DaoMaster(db).newSession();// greenDAO框架主干类根据db对象创建的回话
    }

    // 初始化网络请求框架Retrofit
    private void initRetrofit() {
        sRetrofit = new Retrofit.Builder()
                .baseUrl("https://news-at.zhihu.com/")
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
//                .addConverterFactory(GsonConverterFactory.create())// 自动解析
                .addConverterFactory(new MyJSONFactory())// 我们自己定义解析工厂去解析响应中的JSON数据
                .build();
    }

    public static Retrofit getRetrofit() {
        return sRetrofit;
    }

    public static DaoSession getDaoSession() {
        return sDaoSession;
    }
}
public class DetailBean {

    private String title;
    private String title_bg_url;
    private String htmlCode;

    private int comments;// 评论数

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getTitle_bg_url() {
        return title_bg_url;
    }

    public void setTitle_bg_url(String title_bg_url) {
        this.title_bg_url = title_bg_url;
    }

    public String getHtmlCode() {
        return htmlCode;
    }

    public void setHtmlCode(String htmlCode) {
        this.htmlCode = htmlCode;
    }

    public int getComments() {
        return comments;
    }

    public void setComments(int comments) {
        this.comments = comments;
    }

    public int getLike() {
        return like;
    }

    public void setLike(int like) {
        this.like = like;
    }

    private int like;// 点赞数

}
public class NewsBean {
    /**
     * date : 20131118
     * stories : [{"images":["http://p4.zhimg.com/7b/c8/7bc8ef5947b069513c51e4b9521b5c82.jpg"],"type":0,"id":1747159,"ga_prefix":"111822","title":"深夜食堂 · 我的张曼妮"},{"images":["http://p3.zhimg.com/21/0c/210c7b63b931932fa7a1e62bf0113e7b.jpg"],"type":0,"id":1858551,"ga_prefix":"111822","title":"清朝皇帝上朝的时候说的是满语还是汉语?"},{"images":["http://p4.zhimg.com/7c/d1/7cd1496541c7964b2cf8614b9fa664b0.jpg"],"type":0,"id":1848791,"ga_prefix":"111821","title":"淘宝上那些适合送爸妈的东西"},{"images":["http://p2.zhimg.com/11/05/1105cfa3d12f3539ef35fa603614ed92.jpg"],"type":0,"id":1849914,"ga_prefix":"111820","title":"恋爱里的男子汉,迎头专心刷榜才是正经事"},{"images":["http://p4.zhimg.com/cf/1f/cf1fd58f22d3c5fd2fd2a5543d70f81d.jpg"],"type":0,"id":1854693,"ga_prefix":"111819","title":"鸡蛋黄和蛋清长成了的话分别是鸡的什么部位?"},{"images":["http://p2.zhimg.com/e3/d1/e3d15e98b3db498d53d9ed1b85d2fab5.jpg"],"type":0,"id":1861205,"ga_prefix":"111818","title":"鲜柚游戏周报\r\n回顾一周 iOS 精品游戏"},{"title":"吃很重要 · 第一口就开始 high 了(多图)","ga_prefix":"111818","images":["http://p2.zhimg.com/14/3b/143bd74ec7a0299b76d17e6b095799aa.jpg"],"multipic":true,"type":0,"id":1858917},{"images":["http://p2.zhimg.com/51/32/51324fa89e1aba7a337e20e98c9664f1.jpg"],"type":0,"id":1856401,"ga_prefix":"111818","title":"追女孩教练传授:妹子玩手机的话,你就也玩手机,挺好的"},{"images":["http://p3.zhimg.com/f0/97/f0973d30830eed315d46b531f38719cf.jpg"],"type":0,"id":1854400,"ga_prefix":"111817","title":"最美应用 · 给你一种新邮箱Molto"},{"images":["http://p1.zhimg.com/d6/11/d611dd7d57d144621779ec36c8df42fb.jpg"],"type":0,"id":1848590,"ga_prefix":"111817","title":"谁在维护比特币的核心算法?"},{"images":["http://p3.zhimg.com/f8/70/f870fac8fea14e56d2cddf926a4800f2.jpg"],"type":0,"id":1847175,"ga_prefix":"111816","title":"离岸金融:一种光明正大的钻空子行为"},{"images":["http://p1.zhimg.com/d4/30/d430ba0d8d9e51482b6a0bd8ff5ef6ee.jpg"],"type":0,"id":1846706,"ga_prefix":"111815","title":"银泰全面支持支付宝钱包付款,两个初学者的第一次"},{"images":["http://p1.zhimg.com/4b/8c/4b8c8f9c40f08fa9a1a830095131c67c.jpg"],"type":0,"id":1846781,"ga_prefix":"111814","title":"仅售 179 美元,Moto G 为什么定价这么低"},{"images":["http://p3.zhimg.com/2c/ce/2cce90676f6841e01ab683384f4daaf0.jpg"],"type":0,"id":1844934,"ga_prefix":"111813","title":"导演张一白:青春小说到青春电影,中间有层面纱"},{"images":["http://p4.zhimg.com/39/ff/39ff45effc9f6083bb8da5a6f768eaa2.jpg"],"type":0,"id":1838196,"ga_prefix":"111812","title":"知天下 · 圆顶事实上是宗教建筑中常用的一种造型"},{"images":["http://p1.zhimg.com/80/26/802617acf921694c7a2e732008e6c2cf.jpg"],"type":0,"id":1844302,"ga_prefix":"111811","title":"PrimeSense:苹果正在试图收购这个革命性体感控制设备"},{"images":["http://p2.zhimg.com/a6/42/a6423122d959de347cc8a8c61d150c21.jpg"],"type":0,"id":1844263,"ga_prefix":"111810","title":"家庭用 100M 光纤使用什么无线路由器才能发挥最大网速?"},{"images":["http://p2.zhimg.com/52/94/52941a00e16bffffe480e19c387d07d9.jpg"],"type":0,"id":1843578,"ga_prefix":"111809","title":"金融产品也有物流,并且好处多多"},{"images":["http://p1.zhimg.com/86/79/86799f8608bf39171b78456675a9f4f0.jpg"],"type":0,"id":1839454,"ga_prefix":"111807","title":"召回六十多万辆车,大众继续焦头烂额处理变速箱问题"},{"images":["http://p4.zhimg.com/3a/dd/3adda8a964695f3d0c84944fbb676cda.jpg"],"type":0,"id":1843290,"ga_prefix":"111807","title":"全方位冬日晨跑注意事项已供上,假设你已起床"},{"images":["http://p2.zhimg.com/a8/a6/a8a677d04d27a96cdb457e6c1a430d68.jpg"],"type":0,"id":1838920,"ga_prefix":"111807","title":"独处时才是了解自己的最好机会,你上完厕所会冲吗?"},{"images":["http://p4.zhimg.com/c5/7d/c57d1d0ee1ba83df700982a4f8e5ac26.jpg"],"type":0,"id":1843557,"ga_prefix":"111807","title":"李宗盛:既然青春留不住,不如听大叔讲故事"},{"images":["http://p3.zhimg.com/b7/b2/b7b223eaa3a6daaf680f266973803c75.jpg"],"type":0,"id":1839693,"ga_prefix":"111807","title":"创业公司财务怎么做,绝大多数创业初期年轻人不知道这个"},{"images":["http://p3.zhimg.com/21/32/21328ba459bee7961dc71de398002638.jpg"],"type":0,"id":1841395,"ga_prefix":"111806","title":"瞎扯 · 如何正确地吐槽"}]
     */

    private String date;
    private List<StoriesBean> stories;

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public List<StoriesBean> getStories() {
        return stories;
    }

    public void setStories(List<StoriesBean> stories) {
        this.stories = stories;
    }

}
@Entity
public class StoriesBean {

    // 下面的id表达的含义是内容,也就是文章id,还需要创建真正意义的主键_id
    @Id(autoincrement = true)
    private long _id;

    private int id;// 文章id
    private String title;
//    private List<String> images;// 原始数据格式,使用List集合会产生2张表的管理操作,有点难

    private String imge;// 即将使用手动JSON解析方式,可以产生我们要求的数据格式:只有1个url地址就够了

    @Generated(hash = 1675582365)
    public StoriesBean(long _id, int id, String title, String imge) {
        this._id = _id;
        this.id = id;
        this.title = title;
        this.imge = imge;
    }

    @Generated(hash = 929118848)
    public StoriesBean() {
    }

    public long get_id() {
        return this._id;
    }

    public void set_id(long _id) {
        this._id = _id;
    }

    public int getId() {
        return this.id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return this.title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getImge() {
        return this.imge;
    }

    public void setImge(String imge) {
        this.imge = imge;
    }

}
public class VersionBean {
    /**
     * status : 1
     * msg : 【更新】

     - 极大提升性能及稳定性
     - 部分用户无法使用新浪微博登录
     - 部分用户无图模式无法分享至微信及朋友圈
     * url : http://zhstatic.zhihu.com/pkg/store/daily/zhihu-daily-zhihu-2.6.0(744)-release.apk
     * latest : 2.6.0
     */

    private int status;
    private String msg;
    private String url;
    private String latest;

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getLatest() {
        return latest;
    }

    public void setLatest(String latest) {
        this.latest = latest;
    }
}
public class SendPositionAndDataEvent {

    private int mPosition;
    private StoriesBean mData;

    public SendPositionAndDataEvent(int position, StoriesBean data) {
        mPosition = position;
        mData = data;
    }

    public int getPosition() {
        return mPosition;
    }

    public void setPosition(int position) {
        mPosition = position;
    }

    public StoriesBean getData() {
        return mData;
    }

    public void setData(StoriesBean data) {
        mData = data;
    }
}
/**
 * 最新消息和过往消息的数据结构相同,
 * 可以使用同一种类型的Fragment
 * <p>
 * 适配器最佳使用方式是伴随RecyclerView一起初始化,在网络数据产生后才去添加数据
 * 这么写能够保证适配器数据稳定性和扩展灵活性
 */
public class NewsFragment extends Fragment {

    // 定义两个标记代表不同的数据内容
    // 人为规定1代表最新消息,2代表过往消息
    public static final int TYPE_LATEST = 1;
    public static final int TYPE_BEFORE = 2;

    // 碎片类型
    private int mType;

    @BindView(R.id.recycler_view)
    RecyclerView mRecyclerView;
    private NewsAdapter mAdapter;
    private DaoSession mDaoSession;
    private StoriesBeanDao mDao;

    // 传参数创建Fragment的方式
    public static NewsFragment newInstance(int type) {
        Bundle args = new Bundle();
        args.putInt("type", type);// 从外部传递加载数据类型
        NewsFragment fragment = new NewsFragment();
        fragment.setArguments(args);
        return fragment;
    }

    // 在创建碎片是接收碎片类型,根据碎片类型判断加载最新还是过往
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Bundle args = getArguments();
        if (args != null) {
            mType = args.getInt("type");
        }

        mDaoSession = MyApplication.getDaoSession();
        mDao = mDaoSession.getStoriesBeanDao();
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_news, container, false);
        ButterKnife.bind(this, rootView);

        // 在数据产生之前就初始化适配器,防止后面空指针异常
        mAdapter = new NewsAdapter(getContext());
        // 绑定适配器
        mRecyclerView.setAdapter(mAdapter);

        // 加载网络数据
        loadData();
        return rootView;
    }

    // 根据接收到的数据类型加载对应的数据
    private void loadData() {
        NewsHttpService httpService = MyApplication.getRetrofit()
                .create(NewsHttpService.class);

        // RxJava的观察者
        Observable<NewsBean> observable = null;
        switch (mType) {
            case TYPE_LATEST:
                observable = httpService.getLatestObservable();
                break;
            case TYPE_BEFORE:
                observable = httpService.getBeforeObservable();
                break;
        }

        // Retrofit自动获取数据,自动将数据源设置给观察者
        // 我们只需要管理线程调度和数据变换
        // 下载数据和数据变换跳转至子线程
        observable.subscribeOn(Schedulers.io())
                // 链式调用的书写风格,map对数据进行变换
                .map(new Function<NewsBean, List<StoriesBean>>() {
                    // 将原始数据变换为我们想要的数据
                    @Override
                    public List<StoriesBean> apply(NewsBean newsBean) throws Exception {
                        return newsBean.getStories();
                    }
                })
                // 数据跳转至主线程
                .observeOn(AndroidSchedulers.mainThread())
                // 怎么用:【存储】到数据库中
                /**
                 * 我们要向数据库插入数据了,要执行insert方法
                 * 谁来执行insert呢?dao对象来执行
                 * dao从哪来?从DaoSesscion会话中得到
                 * DaoSession从哪来?从数据库对象db中得到
                 * db从哪来?从数据库助手中得到
                 * 数据库助手从哪来?在MyApplication中创建
                 */
                .subscribe(new Consumer<List<StoriesBean>>() {
                               @Override
                               public void accept(List<StoriesBean> storiesBeans) throws Exception {
                                   insertDatasInDB(storiesBeans);
                                   showDataByDB();
                               }
                           },
                        // 第二个消费者叫onError,包括断网情况也会走该操作
                        new Consumer<Throwable>() {
                            @Override
                            public void accept(Throwable throwable) throws Exception {
                                showDataByDB();
                            }
                        });
    }

    // 向数据库插入数据
    private void insertDatasInDB(List<StoriesBean> storiesBeans) {
        for (StoriesBean story : storiesBeans) {
            // 设置主键_id为时间戳
            story.set_id(System.currentTimeMillis());
            // 使用dao插入数据
            mDao.insert(story);
        }
    }

    // 从数据库加载数据并展示
    // 配合query查询类实现查询操作
    // 获取查询对象,如果需要,设置查询条件
    // 使用查询对象查询数据
    // 添加到适配器中展示
    private void showDataByDB() {
        QueryBuilder<StoriesBean> builder = mDao.queryBuilder();
        Query<StoriesBean> query = builder.build();
        // 查询全部数据
        List<StoriesBean> list = query.list();
        if (list != null && !list.isEmpty()) {
            mAdapter.addDatas(list);
        }
    }

    // 在Fragment可见时注册EventBus,这样就能接收到数据了
    // 在Fragment不可见时,解除注册,优化性能
    @Override
    public void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }

    @Override
    public void onStop() {
        super.onStop();
        EventBus.getDefault().unregister(this);
    }

    // 定义一个方法,接收事件
    // 方法参数要求设置为接收的事件
    @Subscribe// EventBus订阅了该方法,即可将数据发送到该方法中
    public void onReceivePositionAndData(SendPositionAndDataEvent event) {
        int position = event.getPosition();
        StoriesBean story = event.getData();

        Toast.makeText(getContext(), "位置:" + position, Toast.LENGTH_SHORT).show();

        // 接收到item点击事件这个事,我们跳转界面
        Intent intent = new Intent(getContext(), DetailActivity.class);
        startActivity(intent);
    }

}
/**
 * 该接口定义了Retrofit请求网络的方法
 * 配合RxjAVA时,定义的方法返回值类型要求为RxJava的观察者Observable
 * 泛型就是JSON解析后的数据模型类
 */
public interface NewsHttpService {

    // 最新消息的方法
    @GET("api/4/news/latest")
    Observable<NewsBean> getLatestObservable();

    // 过往消息的方法
    @GET("api/4/news/before/20131119")
    Observable<NewsBean> getBeforeObservable();

}
/**
 * 自定义JSON解析工厂
 * JSON数据来自网络的响应,所以我们需要重写响应体装换器,将JSON字符串人为进行解析操作并返回
 */
public class MyJSONFactory extends Converter.Factory {

    @Nullable// 选择安卓包的注解
    // 泛型一:原始的响应体,包含JSON字符串
    // 泛型二:指定我们解析后的数据类型
    @Override
    public Converter<ResponseBody, NewsBean> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        return new Converter<ResponseBody, NewsBean>() {
            @Override
            public NewsBean convert(ResponseBody body) throws IOException {
                // 使用JSONObject、JSONArray解析数据并手动封装
                String json = body.string();

                try {
                    JSONObject jsonObject = new JSONObject(json);
                    NewsBean news = new NewsBean();// 根数据模型类

                    // 获取JSON对象中的JSON数组
                    JSONArray storiesArray = jsonObject.getJSONArray("stories");
                    List<StoriesBean> storiesList = new ArrayList<>();

                    // 使用for循环封装JSON数组中的全部数据
                    for (int i = 0; i < storiesArray.length(); i++) {
                        // 获取JSON数组中的大括号对象,就是storiesbean
                        JSONObject storiesObject = storiesArray.getJSONObject(i);
                        StoriesBean story = new StoriesBean();

                        // stories对象中有一个JSON数组叫images,我们要提取出这个数组中唯一的字符串
                        JSONArray imagesArray = storiesObject.getJSONArray("images");
                        String imagesString = imagesArray.getString(0);
                        // 封装至我们的storiesbean中
                        story.setImge(imagesString);

                        // title可以直接通过story对象提取出来并封装
                        String title = storiesObject.getString("title");
                        story.setTitle(title);

                        int storyId = storiesObject.getInt("id");
                        story.setId(storyId);

                        // 将每一个story封装到集合中
                        storiesList.add(story);
                    }
                    // 循环后,将sotries集合封装到根数据模型类中
                    news.setStories(storiesList);
                    return news;
                } catch (Exception e) {
                    e.printStackTrace();
                }


                return null;
            }

        };
    }
}

activity_detail:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/coordinator_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="net.bwie.month12exam.activity.DetailActivity">

    <!--标题部分,实现折叠标题栏-->
    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <!--为了实现标题栏和主体内容的联动效果,要给AppBarLayout里的子控件设置滑动标记scrollFlags-->
        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:contentScrim="@color/colorAccent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <!--折叠布局中摆放两个UI控件-->
            <!--第一个控件在标题展开时显示-->
            <!--第二个控件Toolbar在标题收起时显示-->

            <ImageView
                android:id="@+id/title_iv"
                android:layout_width="match_parent"
                android:layout_height="200dp" />

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="56dp"
                app:layout_collapseMode="pin"
                app:title="@string/app_name">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="56dp"
                    android:gravity="center_vertical"
                    android:orientation="horizontal">

                    <TextView
                        android:id="@+id/share_tv"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:text="分享" />

                    <TextView
                        android:id="@+id/collect_tv"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:text="收藏" />

                    <TextView
                        android:id="@+id/comments_tv"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:text="评论" />

                    <TextView
                        android:id="@+id/like_tv"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:text="点赞" />

                </LinearLayout>

            </android.support.v7.widget.Toolbar>

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <!--测试webview是否兼容标题滑动操作?-->
    <!--主体内容记得添加behavior行为属性,实现和上面标题栏的联动-->
    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <WebView
            android:id="@+id/web_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </android.support.v4.widget.NestedScrollView>

</android.support.design.widget.CoordinatorLayout>
activity_main:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="net.bwie.month12exam.activity.MainActivity">

    <LinearLayout
        android:id="@+id/top_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/latest_btn"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="最新消息" />

        <Button
            android:id="@+id/before_btn"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="过往消息" />

    </LinearLayout>

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/top_container" />

</RelativeLayout>
fragment_news:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutManager="android.support.v7.widget.LinearLayoutManager" />

</RelativeLayout>
item_news:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <!--高度一定要改成wrap_content-->

    <TextView
        android:id="@+id/title_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <ImageView
        android:id="@+id/pic_iv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_toRightOf="@id/title_tv" />

</RelativeLayout>

导包:

apply plugin: 'org.greenrobot.greendao'

//    Glide
    compile 'com.github.bumptech.glide:glide:4.2.0'
    //    Retrofit
    compile 'com.squareup.retrofit2:converter-gson:2.3.0'
    compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
    //    RxJava+Retrofit
    compile 'io.reactivex.rxjava2:rxjava:2.1.5'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    //    app模块下的build.gradle中添加:
    compile 'org.greenrobot:greendao:3.2.2'
    //    ButterKnife
    //    在app文件夹的build.gradle中一起导入:
    compile 'com.jakewharton:butterknife:8.8.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
    //    EventBus
    compile 'org.greenrobot:eventbus:3.1.1'


    implementation 'com.android.support:design:26.1.0'
    implementation 'com.android.support:recyclerview-v7:26.1.0'


//    整个工程中的build.gradle中添加:
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'

AndroidMainfest添加权限:

<uses-permission android:name="android.permission.INTERNET" />
 <activity android:name=".activity.DetailActivity"></activity>












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值