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

xiaoxiao2021-02-28  52

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

2017年01月31日 16:27:08 阅读数:4333

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

效果图


开源项目


nameintroductionbutterknifeAnnotate 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 devicesmaterialdatetimepickerPick a date or time on Android in styleagendacalendarviewThis 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) ); } 12345678910111213141516171819202122232425262728293031

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

日历的实现来自wdullaer/MaterialDateTimePicker 

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

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

知乎日报的数据


来自知乎日报 API 分析

最新消息

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

过往消息

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

响应为

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

消息内容获取与离线下载

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

利用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); } 12345678910111213141516

基础url

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

进行封装

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); } ... } 123456789101112131415161718192021222324252627282930313233343536373839404142

把列表的界面作为例子

定义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); } } 1234567891011121314151617

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("%ddd", year, monthOfYear + 1, dayOfMonth); presenter.getBeforeNews(date); } } 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758

定义一个回调接口

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

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

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

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

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

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

转载请注明原文地址: https://www.6miu.com/read-2627367.html

最新回复(0)