Android-MVP+Retrofit+Rxjava实现一个知乎日报客户端

使用MVP+Retrofit+Rxjava实现一个知乎日报客户端,界面基于Material design,还没有全部完成orz,,放假太懒

效果图


这里写图片描述

开源项目


nameintroduction
butterknifeAnnotate fields with @BindView and a view ID for Butter Knife to find and automatically cast the corresponding view in your layout.
MaterialTabsCustom Tabs with Material Design animations for pre-Lollipop devices
materialdatetimepickerPick a date or time on Android in style
agendacalendarviewThis library replicates the basic features of the Calendar and Agenda views from the Sunrise Calendar (now Outlook) app, coupled with some small design touch from the Google Calendar app.

使用Material Design


可以参考我的另外一篇文章Android-Material Design的使用

列表使用的为recyclerView,这个就不解释了

tabs标题栏的实现采用了开源项目neokree/MaterialTabs

需和ViewPager一起使用。在ViewPager中添加Fragment
Activity需要 implements MaterialTabListener

fragmentList = new ArrayList<>();
        fragmentList.add(new NewsFragment());
        fragmentList.add(new TestFragment());
        fragmentList.add(new TestFragment());

        tabHost = (MaterialTabHost) this.findViewById(R.id.materialTabHost);
        pager = (ViewPager) this.findViewById(R.id.viewpager);

        // init view pager
        fragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), fragmentList);
        pager.setAdapter(fragmentPagerAdapter);
        pager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                // when user do a swipe the selected tab change
                tabHost.setSelectedNavigationItem(position);
            }
        });

        // insert all tabs from pagerAdapter data
        List<String> tabsNames = new ArrayList<>();
        tabsNames.add("zhihu");
        tabsNames.add("schedule");
        tabsNames.add("timeTable");
        for (int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
            tabHost.addTab(
                    tabHost.newTab()
                            .setText(tabsNames.get(i))
                            .setTabListener(this)
            );
        }

点击fab出现日历来选择时间,用来查询过往的日报

日历的实现来自wdullaer/MaterialDateTimePicker

返回的日期需要格式化,使用在知乎日报的API中

 String date = String.format("%d%02d%02d", year, monthOfYear + 1, dayOfMonth);

知乎日报的数据


来自知乎日报 API 分析

最新消息

URL: http://news-at.zhihu.com/api/4/news/latest

过往消息

URL: http://news-at.zhihu.com/api/4/news/before/20131119

响应为

{
    date: "20140523",
    stories: [
        {
            title: "中国古代家具发展到今天有两个高峰,一个两宋一个明末(多图)",
            ga_prefix: "052321",
            images: [
                "http://p1.zhimg.com/45/b9/45b9f057fc1957ed2c946814342c0f02.jpg"
            ],
            type: 0,
            id: 3930445
        },
    ...
    ],
    ...
}

消息内容获取与离线下载

URL: http://news-at.zhihu.com/api/4/news/{id}

利用Android studio的插件GsonFormat,来解析返回的json数据

MVP+Retrofit+Rxjava


MVP

可以参考
java-mvp模式简单实现
浅谈Andorid开发中的MVP模式

Retrofit

Android网络请求库 - Say hello to retrofit
RxJava 与 Retrofit 结合的最佳实践

Rxjava

给 Android 开发者的 RxJava 详解

定义接口

public interface ZhiHuService {
    @GET("api/4/news/latest")
    Observable<LatestNews> getLatestNews();

    @GET("api/4/news/before/{date}")
    Observable<LatestNews> getBeforeNews(@Path("date") String dateString);

    @GET("api/4/news/{id}")
    Observable<News> getNews(@Path("id") int id);

    @GET("api/4/story/{id}/long-comments")
    Observable<Comment> getComments(@Path("id") int id);

    @GET("api/4/story-extra/{id}")
    Observable<StoryExtra> getStroyExtra(@Path("id") int id);
}

基础url

public class Config {
    public final static String ZHIHU_URL = "http://news-at.zhihu.com/";
}

进行封装

public class ZhiHuApi {

    private static final int DEFAULT_TIMEOUT = 5;
    private ZhiHuService zhiHuService;
    private static ZhiHuApi zhiHuApi;
    private Retrofit retrofit;

    private ZhiHuApi() {
        //设置超时时间
        OkHttpClient.Builder httpcientBuilder = new OkHttpClient.Builder();

        Retrofit retrofit = new Retrofit.Builder()
                .client(httpcientBuilder.build())//
                .baseUrl(Config.ZHIHU_URL)
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();

       zhiHuService = retrofit.create(ZhiHuService.class);
    }


    public static ZhiHuApi getInstance(){
        if (zhiHuApi == null) {
            synchronized (ZhiHuApi.class){
                if (zhiHuApi == null){
                   zhiHuApi = new ZhiHuApi();
                }
            }
        }
        return zhiHuApi;
    }

    public void getLatestNews(Subscriber<LatestNews> subscriber){
        zhiHuService.getLatestNews()
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);
    }
...
}

把列表的界面作为例子

定义Contract接口

public interface NewsContract {

    interface View{
        void refreshRecyclerVew(List<LatestNews.StoriesBean> storiesList);
    }

    interface Presenter{
        void getBeforeNews(String date);
        void getLatestNews();
    }

    interface model{
        void getBeforeNews(CallBackLatestNews callback, String date);
        void getLatestNews(CallBackLatestNews callback);
    }

}

View层

public class NewsFragment extends Fragment implements NewsContract.View, DatePickerDialog.OnDateSetListener {

    private static final String TAG = "NewsFragment";
    RecyclerView recyclerView;
    private NewsContract.Presenter presenter;

    public NewsFragment() {
        presenter = new NewsPresenter(this);
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_zhihu_daily, container, false);

        FloatingActionButton fab = (FloatingActionButton) view.findViewById(R.id.fab);
        fab.setImageResource(R.drawable.add);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //显示日历选项
                Calendar now = Calendar.getInstance();
                DatePickerDialog dpd = DatePickerDialog.newInstance(
                        NewsFragment.this,
                        now.get(Calendar.YEAR),
                        now.get(Calendar.MONTH),
                        now.get(Calendar.DAY_OF_MONTH)
                );
                dpd.show(getActivity().getFragmentManager(), "Datepickerdialog");
            }
        });

        recyclerView = (RecyclerView) view.findViewById(R.id.latest_news_recyclerview);
        //StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
        LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
        recyclerView.setLayoutManager(layoutManager);
       presenter.getLatestNews();

        return view;
    }

    @Override
    public void refreshRecyclerVew(List<LatestNews.StoriesBean> storiesList) {
        Log.d(TAG, "refreshRecyclerVew: ");
        NewsSummaryAdapter adapter = new NewsSummaryAdapter(storiesList);
        recyclerView.setAdapter(adapter);
    }


    @Override
    public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) {
        //String date = "You picked the following date: "+dayOfMonth+"/"+(monthOfYear+1)+"/"+year;
        String date = String.format("%d%02d%02d", year, monthOfYear + 1, dayOfMonth);
        presenter.getBeforeNews(date);
    }
}

定义一个回调接口

public interface CallBackLatestNews {
    public void result(List<LatestNews.StoriesBean> list);
}

Presenter层

public class NewsPresenter implements NewsContract.Presenter {

    private static final String TAG = "NewsPresenter";
    private NewsContract.View view;
    private NewsContract.model model;

    public NewsPresenter(NewsContract.View view) {
        this.view = view;
        model = new NewsModel();
    }


    @Override
    public void getBeforeNews(String date) {
        model.getBeforeNews(new CallBackLatestNews() {
            @Override
            public void result(List<LatestNews.StoriesBean> list) {
                view.refreshRecyclerVew(list);
            }
        }, date);
    }

    @Override
    public void getLatestNews() {
        Log.d(TAG, "getLatestNews: ");
        model.getLatestNews(new CallBackLatestNews() {
            @Override
            public void result(List<LatestNews.StoriesBean> list) {
                view.refreshRecyclerVew(list);
            }
        });
    }
}

model层

public class NewsModel implements NewsContract.model {

    private static final String TAG = "NewsModel";


    @Override
    public void getBeforeNews(final CallBackLatestNews callback, String date) {
        Subscriber subscriber = new Subscriber<LatestNews>() {

            @Override
            public void onCompleted() {
                Log.d(TAG, "onCompleted: ");
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(LatestNews latestNews) {
                callback.result(latestNews.getStories());
            }
        };
        ZhiHuApi.getInstance().getBeforeNews(subscriber, date);
    }

    @Override
    public void getLatestNews(final CallBackLatestNews callback) {
        Subscriber subscriber = new Subscriber<LatestNews>() {

            @Override
            public void onCompleted() {
                Log.d(TAG, "onCompleted: ");
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(LatestNews latestNews) {
                Log.d(TAG, "onNext: ");
               callback.result(latestNews.getStories());
            }
        };
        ZhiHuApi.getInstance().getLatestNews(subscriber);
    }

}

暂时只实现了知乎日报的功能,schedule和timetable还未实现。

添加了便签的功能,具体实现可以看 Android-使用LitePal实现一个便笺功能

这里写图片描述

github:https://github.com/linsawako/oneDay

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
好的,以下是一个使用 OkHttp、RetrofitRxJava 的简单 Android 示例。 首先,你需要在你的 build.gradle 文件中添加以下依赖: ``` dependencies { implementation 'com.squareup.okhttp3:okhttp:4.9.1' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'io.reactivex.rxjava2:rxjava:2.2.19' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' } ``` 这样就可以使用 OkHttp、RetrofitRxJava 的类和方法了。 接下来,你可以在你的代码中定义一个 Retrofit 接口: ``` public interface ApiService { @GET("users/{username}") Observable<User> getUser(@Path("username") String username); } ``` 在这个接口中,我们定义了一个 GET 请求,用于获取一个用户的信息。该请求的 URL 是 "https://api.github.com/users/{username}",其中 {username} 参数将会被替换为实际的用户名。接口返回的数据类型是 User,这是一个简单的类,如下所示: ``` public class User { public final String login; public final int id; public final String avatarUrl; public final String htmlUrl; public User(String login, int id, String avatarUrl, String htmlUrl) { this.login = login; this.id = id; this.avatarUrl = avatarUrl; this.htmlUrl = htmlUrl; } } ``` 现在,你可以在你的 Activity 或 Fragment 中调用这个接口: ``` ApiService apiService = RetrofitClient.getInstance().create(ApiService.class); apiService.getUser("octocat") .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(user -> { // 在这里处理获取到的用户信息 }, throwable -> { // 在这里处理请求失败的情况 }); ``` 该示例将会获取一个名为 "octocat" 的用户的信息,并在获取到数据后将其打印出来。需要注意的是,这个网络请求是在一个新的线程中执行的,以避免阻塞主线程。获取到数据后,我们转换到主线程中,并在观察者的 onNext 回调中处理数据。如果请求失败,则在观察者的 onError 回调中处理错误情况。 希望这个简单的示例可以帮助你理解如何在 Android 中使用 OkHttp、RetrofitRxJava

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值