Repository: developerHaoz/SleepHelper Branch: master Commit: 3cbe2f4d305f Files: 84 Total size: 146.5 KB Directory structure: gitextract_kuz2vkud/ ├── .gitignore ├── .idea/ │ ├── compiler.xml │ ├── copyright/ │ │ └── profiles_settings.xml │ ├── gradle.xml │ ├── misc.xml │ ├── modules.xml │ ├── runConfigurations.xml │ └── vcs.xml ├── README.md ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── libs/ │ │ └── volley.jar │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── example/ │ │ └── developerhaoz/ │ │ └── sleephelper/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── developerhaoz/ │ │ │ └── sleephelper/ │ │ │ ├── common/ │ │ │ │ ├── HomeActivity.java │ │ │ │ ├── SingleInstanceTestClass.java │ │ │ │ ├── SleepApplication.java │ │ │ │ ├── TestActivity.java │ │ │ │ ├── net/ │ │ │ │ │ ├── VolleyHelper.java │ │ │ │ │ └── VolleyResponseCallback.java │ │ │ │ ├── utils/ │ │ │ │ │ ├── AppManager.java │ │ │ │ │ ├── Check.java │ │ │ │ │ ├── GetRandom.java │ │ │ │ │ └── StatusBarCompat.java │ │ │ │ └── view/ │ │ │ │ ├── CommonPagerAdapter.java │ │ │ │ ├── CommonTabBean.java │ │ │ │ └── GlideHelper.java │ │ │ ├── diary/ │ │ │ │ ├── bean/ │ │ │ │ │ └── DiaryBean.java │ │ │ │ ├── db/ │ │ │ │ │ └── DiaryDatabaseHelper.java │ │ │ │ ├── event/ │ │ │ │ │ ├── RefreshViewEvent.java │ │ │ │ │ └── StartUpdateDiaryEvent.java │ │ │ │ ├── ui/ │ │ │ │ │ ├── AddDiaryActivity.java │ │ │ │ │ ├── DiaryAdapter.java │ │ │ │ │ ├── DiaryFragment.java │ │ │ │ │ └── UpdateDiaryActivity.java │ │ │ │ ├── utils/ │ │ │ │ │ ├── GetDate.java │ │ │ │ │ └── SpHelper.java │ │ │ │ └── widget/ │ │ │ │ └── LinedEditText.java │ │ │ ├── duanzi/ │ │ │ │ ├── api/ │ │ │ │ │ └── DuanziApi.java │ │ │ │ ├── bean/ │ │ │ │ │ ├── DuanziBean.java │ │ │ │ │ └── GroupBean.java │ │ │ │ ├── ui/ │ │ │ │ │ ├── DuanziAdapter.java │ │ │ │ │ └── DuanziFragment.java │ │ │ │ └── utils/ │ │ │ │ └── GsonHelper.java │ │ │ └── meizi/ │ │ │ ├── api/ │ │ │ │ └── MeiziApi.java │ │ │ ├── bean/ │ │ │ │ └── MeiziBean.java │ │ │ ├── event/ │ │ │ │ └── MeiziBeanListEvent.java │ │ │ ├── ui/ │ │ │ │ ├── DetailActivity.java │ │ │ │ ├── DetailFragment.java │ │ │ │ ├── MeiziAdapter.java │ │ │ │ └── MeiziFragment.java │ │ │ └── utils/ │ │ │ └── GsonHelper.java │ │ └── res/ │ │ ├── drawable/ │ │ │ ├── linear_style.xml │ │ │ └── shape_add_diary_title.xml │ │ ├── layout/ │ │ │ ├── activity_add_diary.xml │ │ │ ├── activity_detail.xml │ │ │ ├── activity_home.xml │ │ │ ├── activity_test.xml │ │ │ ├── activity_update_diary.xml │ │ │ ├── fragment_detail.xml │ │ │ ├── fragment_diary.xml │ │ │ ├── fragment_duanzi.xml │ │ │ ├── fragment_meizi.xml │ │ │ ├── item_duanzi.xml │ │ │ ├── item_first.xml │ │ │ ├── item_meizi.xml │ │ │ ├── item_rv_diary.xml │ │ │ ├── layout_app_divide.xml │ │ │ ├── layout_app_toolbar.xml │ │ │ └── layout_home_header.xml │ │ ├── menu/ │ │ │ └── menu_me.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── developerhaoz/ │ └── sleephelper/ │ ├── ExampleUnitTest.java │ └── common/ │ └── HomeActivityTest.java ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat └── settings.gradle ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.iml .gradle /local.properties /.idea/workspace.xml /.idea/libraries .DS_Store /build /captures .externalNativeBuild ================================================ FILE: .idea/compiler.xml ================================================ ================================================ FILE: .idea/copyright/profiles_settings.xml ================================================ ================================================ FILE: .idea/gradle.xml ================================================ ================================================ FILE: .idea/misc.xml ================================================ ================================================ FILE: .idea/modules.xml ================================================ ================================================ FILE: .idea/runConfigurations.xml ================================================ ================================================ FILE: .idea/vcs.xml ================================================ ================================================ FILE: README.md ================================================ ### 前言 > 从零开始,手把手带你实现一个「专注睡前的 APP」。睡觉之前如果能有一个 APP,能让我们写一写这一天的见闻或者心得,同时又能看一会段子、瞄一会好看的妹子,放松一下疲惫的身心那该多好,这也是我完成这个 APP 的原因。APP 的全部代码我已经分享到 Github 上了,需要的直接 [点击这里](https://github.com/developerHaoz/SleepHelper),如果喜欢的话,麻烦给个 star,谢谢啦。 在开始写正文之前,先来一波效果的展示,看看五天过后我们能实现怎样的效果 ![SleepHelper](http://upload-images.jianshu.io/upload_images/4334738-acaaea47739bc4b0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 本次的教程分为 5 天,内容分别为: - Day one,准备 - 功能需求 - 可行性分析 - Day two,UI 及公共类的封装 - 界面的设计及实现 - 公共类的实现 - Day three,日记模块 - 日记的展示 - 悬浮菜单的实现 - 日记增删改的实现 - Day four,妹子模块 - 图片的获取 - 图片的展示 - 详情页面的展示 - Day five,段子模块 - 段子数据的获取 - 段子的显示 ## Day one ----- 俗话说,万事开头难,在开始敲代码之前,先让我们来做一些必要的准备,这样才能事半功倍嘛! #### 一、功能需求 既然要做一个 APP,那我们首先还是得把 APP 的功能都列出来,有了方向才能更好的努力,因为我想做的是一个专门给睡觉前用的 APP,所以我觉得应该有以下的这些功能 - 1、日记的增删改 - 2、显示一些有趣好玩的段子 - 3、瀑布流展示漂亮的妹子 - 4、保存日记的内容以及缓存妹子图片 虽然说需求不多,但是却要运用到网络、数据存储、图片缓存、UI 设计等内容,相信整个 APP 完成下来,必定能巩固我们的 Android 基础。 #### 二、可行性分析 我们这个 APP 主要有三个模块,日记模块主要是运用到了数据库的知识,难度不大。但是,段子模块和妹子模块的数据要从哪来,这便是要好好考虑的了。幸好现在是个开源的时代,很多的数据,网上已经开源出来了。 我们先来看一下数据的内容 ``` group: { text: "教授在河边,常常看到两只龟,缩着一动不动。有天忍不住好奇,问一农 民:这两只乌龟在干吗?农民说:他们在pk。教授不解地问:动都没动过p什么 k。老农说:他们在比谁寿命长。教授说:可是壳上有甲骨文的那只,早就死了埃 这时,另一只猛然探出头来骂到:md,死了也不吭一声!有甲骨文的那只也伸 出头来:“专家说啥你信啥1", user: { user_id: 4669064575, name: "馒头啊", avatar_url: "http://p3.pstatp.com/medium/6237/7969345239", }, content: "教授在河边,常常看到两只龟,缩着一动不动。有天忍不住好奇,问 一农民:这两只乌龟在干吗?农民说:他们在pk。教授不解地问:动都没动过 p什么k。老农说:他们在比谁寿命长。教授说:可是壳上有甲骨文的那只,早 就死了埃这时,另一只猛然探出头来骂到:md,死了也不吭一声!有甲骨文 的那只也伸出头来:“专家说啥你信啥1", ... } ``` ``` { id: "56cc6d1d421aa95caa7076df", type: "福利", url: "http://ww1.sinaimg.cn/large/7a8aed7bgw1esxxi1vbq0j20qo0hstcu.jpg", used: true, who: "张涵宇" } ``` 上面那两段代码分别是段子和妹子模块的 json 类型的数据,我已经将一些没用的字段去掉了。剩下的都是我们想要的数据。可以看到段子数据中,有着段子的内容,以及发布者的头像和名字。而妹子数据中有着图片的 url、id、以及图片的类型。相信有了这么丰富的数据,我们想要完成这个 APP 也是有底气了。 ## Day two ----- #### 一、界面的设计及实现 既然我们想要完成一个好看的 APP,那么好看的界面便是必不可少的,这里我强烈推荐 APP 界面的设计必须尽量遵从 Google 提出的 [Material Design](http://wiki.jikexueyuan.com/project/material-design/material-design-intro/introduction.html),在这个推荐一个能够让我们实现 Material Design 变得更加简单的网站 [material design palette](https://www.materialpalette.com/light-blue/light-blue),我这个 APP 的配色就是用这个网站完成的,贴几张图片,让你感受一下它的强大 ![material design palette](http://upload-images.jianshu.io/upload_images/4334738-d4a209808204270e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ![Material Design 风格的图标](http://upload-images.jianshu.io/upload_images/4334738-f1a1e9f2847deb06.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 借助这个网站便能让我们完成 APP 的配色以及图标的收集,为下一步功能的实现,先打好了基础,至于界面的设计就仁者见仁智者见智了,篇幅有限,我就不多讲了。 APP 的最终设计效果如下: ![SleepHelper](http://upload-images.jianshu.io/upload_images/4334738-acaaea47739bc4b0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) #### 二、公共类的实现 因为这个项目有三个模块,有一些东西其实是可以通用的,如果我们先把这些能够通用的东西,封装起来,供给所有的模块调用的话,相信会大大提高我们的开发效率。 ##### 1、网络工具类的封装 这个 APP 中,很多地方都要用到网络请求,因此也就很有必要将网络请求封装起来,因为这个 APP 的规模比较小,因此我选择了 Volley 这个网络框架作为我们网络请求库,把网络请求封装起来,哪个地方需要,调用一下就行了。对于网络请求,我觉得每个程序员都该懂点 HTTP,这里附上一篇有关 HTTP 的文章 [程序员都该懂点 HTTP](http://www.jianshu.com/p/d86b66672ef4)。 先让我们来写个将网络请求进行回调的接口 ``` public interface VolleyResponseCallback { void onSuccess(String response); void onError(VolleyError error); } ``` 然后将网络请求封装起来 ``` public class VolleyHelper { /** * 用于发送 Get 请求的封装方法 * * @param context Activity 的实例 * @param url 请求的地址 * @param callback 用于网络回调的接口 */ public static void sendHttpGet(Context context, String url, final VolleyResponseCallback callback){ RequestQueue requestQueue = Volley.newRequestQueue(context); StringRequest stringRequest = new StringRequest(url , new Response.Listener() { @Override public void onResponse(String s) { callback.onSuccess(s); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { callback.onError(error); } }); requestQueue.add(stringRequest); } } ``` ##### 2、Json 解析的帮助类 因为我们这个 APP 中,获取到的数据都是 Json 格式的,因此也就有必要将有关的 Json 解析封装成一个工具类,传入一个 String 类型的数据,直接得到数据实体类的 List。 ``` public class CommonParser { /** * 用来解析列表性的JSON数据 * 如: * {"success":true,"fileList":[{"filename":"文件名1","fileSize":"文件大小1"}, * {"filename":"文件名2","fileSize":"文件大小2"}]} * * @param result 网络返回来的JSON数据 比如:上面的整串数据 * @param successKey 判断网络是否成功的字段 比如:上面的success字段 * @param arrKey 列表的字段 比如:上面的fileList字段 * @param clazz 需要解析成的Bean类型 * @param 需要解析成的Bean类型 * @return */ public static List parseForList(String result, String successKey, String arrKey, Class clazz) { List list = new ArrayList<>(); JSONObject rootJsonObject = null; try { rootJsonObject = new JSONObject(result); if (rootJsonObject.getBoolean(successKey)) { JSONArray rootJsonArray = rootJsonObject.getJSONArray(arrKey); Gson g = new Gson(); for (int i = 0; i < rootJsonArray.length(); i++) { T t = g.fromJson(rootJsonArray.getJSONObject(i).toString(), clazz); list.add(t); } } } catch (JSONException e) { e.printStackTrace(); } return list; } } ``` ##### 3、HomeActivity(主页面)的封装 主页面我用的是 TabLayout + ViewPager + Fragment,也是现在主流 APP 主页面的显示方式。主界面底部是我们三个模块的图标和名称,通过左右滑动能实现界面的跳转。 ###### 底部图标的实体类 CommonTabBean ``` public class CommonTabBean implements CustomTabEntity{ private int selectedIcon; private int unselectedIcon; private String title; public CommonTabBean(String title){ this.title = title; } public CommonTabBean(String title, int selectedIcon, int unselectedIcon) { this.title = title; this.selectedIcon = selectedIcon; this.unselectedIcon = unselectedIcon; } @Override public String getTabTitle() { return title; } @Override public int getTabSelectedIcon() { return selectedIcon; } @Override public int getTabUnselectedIcon() { return unselectedIcon; } } ``` ###### ViewPager + Fragment 通用的 Adapter ``` public class CommonPagerAdapter extends FragmentPagerAdapter { private List mFragments; public CommonPagerAdapter(FragmentManager fragmentManager, List mFragments){ super(fragmentManager); this.mFragments = mFragments; } @Override public Fragment getItem(int position) { return mFragments.get(position); } @Override public int getCount() { return mFragments.size(); } } ``` ## Day three ----- 关于日记模块的实现,其实我是复用了以前写过的一个[日记 APP](https://github.com/developerHaoz/WatermelonDiaryNew),具体的思路和做法,可以参考我的这篇文章 [Android 一款十分简洁、优雅的日记 APP](http://www.jianshu.com/p/b4fde6b835a3) ## Day four ----- #### 一、图片的获取 ##### 1、根据返回的数据来编写图片的实体类 ``` public class MeiziBean { @SerializedName("_id") private String id; @SerializedName("url") private String imageUrl; @SerializedName("who") private String who; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getImageUrl() { return imageUrl; } public MeiziBean(String imageUrl){ this.imageUrl = imageUrl; } } ``` ##### 2、图片的展示 可以看到我是用瀑布流的方式来实现图片的展示,效果还不错,但其实实现起来也是很简单的 先写个图片的布局作为 RecyclerView 的 Item ``` ``` 可以看到我在 ImageView 的外面加了一个 CardView,这个一种卡片式布局,能让图片看起来就像一张卡片一样,相当的优雅、美观。 接着编写 Adapter,将数据和界面进行绑定 ``` public class MeiziAdapter extends RecyclerView.Adapter { private List mMeiziBeanList; private Fragment mFragment; public MeiziAdapter(List mMeiziBeanList, Fragment mFragment){ this.mMeiziBeanList = mMeiziBeanList; this.mFragment = mFragment; } @Override public MeiziViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_meizi, null); return new MeiziViewHolder(view); } @Override public void onBindViewHolder(MeiziViewHolder holder, final int position) { Glide.with(mFragment) .load(mMeiziBeanList.get(position).getImageUrl()) .fitCenter() .dontAnimate() .diskCacheStrategy(DiskCacheStrategy.ALL) .into(holder.mIvMeizi); holder.mIvMeizi.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ArrayList resultList = new ArrayList(); for (MeiziBean meiziBean : mMeiziBeanList) { resultList.add(meiziBean.getImageUrl()); } DetailActivity.startActivity(mFragment.getActivity(), resultList, position); } }); } @Override public int getItemCount() { if(mMeiziBeanList.size() > 0){ return mMeiziBeanList.size(); } return 0; } public static class MeiziViewHolder extends RecyclerView.ViewHolder{ ImageView mIvMeizi; public MeiziViewHolder(View itemView) { super(itemView); mIvMeizi = (ImageView) itemView.findViewById(R.id.item_iv_meizi); } } } ``` 最后在 Fragment 进行数据的获取,以及布局的初始化就行了 ``` public class MeiziFragment extends Fragment { ...... @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_meizi, container, false); ButterKnife.bind(this, view); initView(); refreshMeizi(); return view; } /** * 刷新当前界面 */ private void refreshMeizi() { mRefresh.setColorSchemeResources(R.color.colorPrimary); mRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { initView(); mRefresh.setRefreshing(false); } }); } private void initView() { VolleyHelper.sendHttpGet(getActivity(), MeiziApi.getMeiziApi(), new VolleyResponseCallback() { @Override public void onSuccess(String s) { response = s; meiziBeanList = GsonHelper.getMeiziBean(response); mRvShowMeizi.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)); Collections.shuffle(meiziBeanList); mRvShowMeizi.setAdapter(new MeiziAdapter(meiziBeanList, MeiziFragment.this)); } @Override public void onError(VolleyError error) { Logger.d(error); } }); } ``` ##### 3、详情页面的展示 干巴巴的,整个模块只能显示妹子的图片怎么行呢!!!怎么着也得能查看大图,根据手势放大缩小,以及浏览下一张图片才行嘛,说干就干。 因为图片需要有根据手势来放大缩小的功能,因此我便想到了 [PhotoView](https://github.com/chrisbanes/PhotoView),这是网上一个大神写的,继承自 ImageView 的一个自定义控件。图片加载我用的是 Glide,如果没了解过这个库的,强烈推荐,一行代码就能搞定图片加载,你确定不研究一下。这里附上一篇有关 Glide 的文章 [Glide 一个强大的图片加载框架](http://www.jianshu.com/p/fae51d781987) ``` public class DetailFragment extends Fragment { public static DetailFragment newInstance(String imageUrl) { DetailFragment fragment = new DetailFragment(); Bundle bundle = new Bundle(); bundle.putString(IMAGE_URL, imageUrl); fragment.setArguments(bundle); return fragment; } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_detail, container, false); ButterKnife.bind(this, view); Bundle bundle = getArguments(); String imageUrl = bundle.getString(IMAGE_URL); Glide.with(this).load(imageUrl).into(mPvShowPhoto); mPvShowPhoto.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() { @Override public void onPhotoTap(View view, float v, float v1) { getActivity().finish(); } @Override public void onOutsidePhotoTap() { } }); return view; } } ``` ## Day five ----- #### 一、段子数据的获取 段子数据的获取其实跟妹子模块的方法基本一样 先编写实体类 ``` public class DuanziBean { @SerializedName("group") private GroupBean groupBean; private String type; public GroupBean getGroupBean() { return groupBean; } public void setGroupBean(GroupBean groupBean) { this.groupBean = groupBean; } public String getType() { return type; } public void setType(String type) { this.type = type; } } ``` ``` public class GroupBean { private String text; private long id; private UserBean user; public String getText() { return text; } public long getId() { return id; } public UserBean getUser() { return user; } public static class UserBean { private long user_id; private String name; private String avatar_url; public String getName() { return name; } public String getAvatar_url() { return avatar_url; } } } ``` 写好实体类之后,使用我们之前已经封装好的网络请求工具以及解析工具,便能将返回的数据,解析成一个包含段子实体类的 List。 #### 二、段子的显示 老规矩,先写个 RecyclerView 的 Item ``` ``` 然后编写将数据和界面进行绑定的 Adapter ``` public class DuanziAdapter extends RecyclerView.Adapter{ private Fragment mFragment; private List mDuanziBeanList; public DuanziAdapter(Fragment fragment, List duanziBeanList){ this.mFragment = fragment; this.mDuanziBeanList = duanziBeanList; } @Override public DuanziViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_duanzi, null); return new DuanziViewHolder(view); } @Override public void onBindViewHolder(DuanziViewHolder holder, int position) { try { DuanziBean duanziBean = mDuanziBeanList.get(position); Glide.with(mFragment).load(duanziBean.getGroupBean().getUser().getAvatar_url()).into(holder.mCivAvatar); holder.mTvContent.setText(duanziBean.getGroupBean().getText()); holder.mTvAuthor.setText(duanziBean.getGroupBean().getUser().getName()); } catch (Exception e) { e.printStackTrace(); } } @Override public int getItemCount() { return mDuanziBeanList.size(); } public static class DuanziViewHolder extends RecyclerView.ViewHolder{ private CircleImageView mCivAvatar; private TextView mTvAuthor; private TextView mTvContent; public DuanziViewHolder(View itemView) { super(itemView); mCivAvatar = (CircleImageView) itemView.findViewById(R.id.duanzi_civ_avatar); mTvAuthor = (TextView) itemView.findViewById(R.id.duanzi_tv_author); mTvContent = (TextView) itemView.findViewById(R.id.duanzi_tv_content); } } } ``` 最后段子页面中进行数据和获取以及界面的初始化 ``` public class DuanziFragment extends Fragment { @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_duanzi, container, false); ButterKnife.bind(this, view); initView(); initRefresh(); return view; } private void initRefresh() { mRefresh.setColorSchemeResources(R.color.colorPrimary); mRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { initView(); mRefresh.setRefreshing(false); } }); } private void initView() { VolleyHelper.sendHttpGet(getActivity(), DuanziApi.GET_DUANZI, new VolleyResponseCallback() { @Override public void onSuccess(String response) { List mDuanziBeanList = GsonHelper.getDuanziBeanList(response); mDuanziBeanList.remove(3); mRvShowDuanzi.setLayoutManager(new LinearLayoutManager(getActivity())); mRvShowDuanzi.setAdapter(new DuanziAdapter(DuanziFragment.this, mDuanziBeanList)); } @Override public void onError(VolleyError error) { Logger.d(error); } }); } } ``` 以上便是本文的全部内容,这个 APP 的全部代码我已经分享到 [Github](https://github.com/developerHaoz/SleepHelper) 上了,如果觉得对你有帮助的话,就赏个 star 吧。 ----- ### 猜你喜欢 - [Android 一款十分简洁、优雅的日记 APP](http://www.jianshu.com/p/b4fde6b835a3) - [Android 能让你少走弯路的干货整理](http://www.jianshu.com/p/514656c383a2) - [Android 撸起袖子,自己封装 DialogFragment](http://www.jianshu.com/p/c9f20ec7277a) ================================================ FILE: app/.gitignore ================================================ /build ================================================ FILE: app/build.gradle ================================================ apply plugin: 'com.android.application' android { compileSdkVersion 25 buildToolsVersion "25.0.3" defaultConfig { applicationId "com.example.developerhaoz.sleephelper" minSdkVersion 18 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.3.1' compile 'com.android.support.constraint:constraint-layout:1.0.2' testCompile 'junit:junit:4.12' compile files('libs/volley.jar') compile 'com.google.code.gson:gson:2.4' compile 'com.flyco.tablayout:FlycoTabLayout_Lib:2.0.8@aar' compile 'org.greenrobot:eventbus:3.0.0' compile 'com.jakewharton:butterknife:7.0.1' compile 'de.hdodenhof:circleimageview:2.1.0' compile 'com.orhanobut:logger:1.15' compile 'com.android.support:design:25.3.1' compile 'com.getbase:floatingactionbutton:1.5.1' compile 'com.github.clans:fab:1.6.4' compile 'com.oguzdev:CircularFloatingActionMenu:1.0.2' compile 'io.github.yavski:fab-speed-dial:1.0.1' compile 'cc.trity.floatingactionbutton:library:1.0.0' compile 'com.parse.bolts:bolts-tasks:1.4.0' compile 'com.github.bumptech.glide:glide:3.7.0' compile 'com.github.chrisbanes:PhotoView:1.2.6' debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' } ================================================ FILE: app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in C:\Users\Administrator\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: app/src/androidTest/java/com/example/developerhaoz/sleephelper/ExampleInstrumentedTest.java ================================================ package com.example.developerhaoz.sleephelper; import android.content.Context; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.*; /** * Instrumentation test, which will execute on an Android device. * * @see Testing documentation */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { @Test public void useAppContext() throws Exception { // Context of the app under test. Context appContext = InstrumentationRegistry.getTargetContext(); assertEquals("com.example.developerhaoz.sleephelper", appContext.getPackageName()); } } ================================================ FILE: app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/common/HomeActivity.java ================================================ package com.example.developerhaoz.sleephelper.common; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.support.design.widget.NavigationView; import android.support.v4.app.Fragment; import android.support.v4.view.ViewPager; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import com.example.developerhaoz.sleephelper.R; import com.example.developerhaoz.sleephelper.common.view.CommonPagerAdapter; import com.example.developerhaoz.sleephelper.common.view.CommonTabBean; import com.example.developerhaoz.sleephelper.diary.bean.DiaryBean; import com.example.developerhaoz.sleephelper.diary.event.StartUpdateDiaryEvent; import com.example.developerhaoz.sleephelper.diary.ui.DiaryFragment; import com.example.developerhaoz.sleephelper.diary.ui.UpdateDiaryActivity; import com.example.developerhaoz.sleephelper.duanzi.ui.DuanziFragment; import com.example.developerhaoz.sleephelper.meizi.ui.MeiziFragment; import com.flyco.tablayout.CommonTabLayout; import com.flyco.tablayout.listener.CustomTabEntity; import com.flyco.tablayout.listener.OnTabSelectListener; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import java.util.ArrayList; import java.util.List; import butterknife.Bind; import butterknife.ButterKnife; /** * 主页面的 Activity *

* Created by developerHaoz */ public class HomeActivity extends AppCompatActivity { @Bind(R.id.home_view_pager) ViewPager mHomeVp; @Bind(R.id.home_tab_layout) CommonTabLayout mHomeTabLayout; @Bind(R.id.home_dl) DrawerLayout mDrawerLayout; @Bind(R.id.home_navigation_view) NavigationView mNavigationView; @Bind(R.id.home_iv_draw) ImageView mIvDraw; @Bind(R.id.home_tv_title_normal) TextView mTvNormal; @Bind(R.id.home_tv_title_center) TextView mTvCenter; @Bind(R.id.home_iv_menu) ImageView mIvMenu; @Bind(R.id.contacts_tab_rl) LinearLayout mContactsTabRl; private static final int[] SELECTED_ICONS = new int[]{R.drawable.diary_selected, R.drawable.duanzi_selected, R.drawable.meizi_selected}; private static final int[] UN_SELECTED_ICONS = new int[]{R.drawable.diary_unselected, R.drawable.duanzi_unselected, R.drawable.meizi_unselected}; private static final String[] TITLES = new String[]{"日记", "段子", "风景"}; private List mFragments; public static void startActivity(Context context) { Intent intent = new Intent(context, HomeActivity.class); context.startActivity(intent); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); ButterKnife.bind(this); EventBus.getDefault().register(this); initTabLayout(); initVierPager(); initToolbar(); } private void initToolbar() { mIvDraw.setVisibility(View.GONE); mIvMenu.setVisibility(View.GONE); mTvCenter.setVisibility(View.VISIBLE); mTvNormal.setVisibility(View.GONE); } private void initVierPager() { mFragments = new ArrayList<>(); mFragments.add(DiaryFragment.newInstance()); mFragments.add(DuanziFragment.newInstance()); mFragments.add(MeiziFragment.newInstance()); CommonPagerAdapter adapter = new CommonPagerAdapter(getSupportFragmentManager(), mFragments); mHomeVp.setAdapter(adapter); } private void initTabLayout() { ArrayList tabEntityList = new ArrayList<>(); for (int i = 0; i < TITLES.length; i++) { tabEntityList.add(new CommonTabBean(TITLES[i] , SELECTED_ICONS[i] , UN_SELECTED_ICONS[i])); } mHomeTabLayout.setTabData(tabEntityList); mHomeTabLayout.setOnTabSelectListener(new OnTabSelectListener() { @Override public void onTabSelect(int position) { mHomeVp.setCurrentItem(position); } @Override public void onTabReselect(int position) { } }); mHomeVp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { mHomeTabLayout.setCurrentTab(position); } @Override public void onPageScrollStateChanged(int state) { } }); mHomeVp.setOffscreenPageLimit(4); mHomeVp.setCurrentItem(1); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Subscribe public void startUpdateDiaryActivity(StartUpdateDiaryEvent event) { DiaryBean diaryBean = event.getDiaryBean(); String title = diaryBean.getTitle(); String content = diaryBean.getContent(); String tag = diaryBean.getTag(); UpdateDiaryActivity.startActivity(this, title, content, tag); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); } @Override public void onBackPressed() { super.onBackPressed(); // TODO: 在主页面按返回键时弹出对话框,提示用户是否退出程序 } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/common/SingleInstanceTestClass.java ================================================ package com.example.developerhaoz.sleephelper.common; /** * Created by developerHaoz on 2017/7/19. */ public class SingleInstanceTestClass { private static SingleInstanceTestClass sInstance; // 懒汉式 private SingleInstanceTestClass(){ } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/common/SleepApplication.java ================================================ package com.example.developerhaoz.sleephelper.common; import android.app.Application; import android.content.Context; import com.android.volley.RequestQueue; import com.android.volley.toolbox.Volley; /** * 自定义的 Application * * Created by developerHaoz on 2017/5/3. */ public class SleepApplication extends Application { private static SleepApplication mContext; private static RequestQueue requestQueue; @Override public void onCreate() { super.onCreate(); mContext = this; requestQueue = Volley.newRequestQueue(mContext); } public static Context getContext(){ return mContext; } public RequestQueue getRequestQueue(){ if (requestQueue == null){ requestQueue = Volley.newRequestQueue(getApplicationContext()); } return requestQueue; } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/common/TestActivity.java ================================================ package com.example.developerhaoz.sleephelper.common; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.widget.ImageView; import com.bumptech.glide.Glide; import com.example.developerhaoz.sleephelper.R; import butterknife.ButterKnife; /** * 用于测试的 Activity *

* Created by developerHaoz on 2017/5/3. */ public class TestActivity extends AppCompatActivity { private static final String IMAGE_URL = "imageUrl"; public static void startActivity(Context context, String imageUrl, int position) { Intent intent = new Intent(context, TestActivity.class); intent.putExtra(IMAGE_URL, imageUrl); context.startActivity(intent); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); ButterKnife.bind(this); ImageView mIvVideo = (ImageView) findViewById(R.id.test_iv_video); Glide.with(this).load("http://p3.pstatp.com/large/1fd90000bdf1766aaa29") .into(mIvVideo); } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/common/net/VolleyHelper.java ================================================ package com.example.developerhaoz.sleephelper.common.net; import android.content.Context; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.StringRequest; import com.android.volley.toolbox.Volley; /** * 利用 Volley 进行网络请求的封装类 * * Created by developerHaoz on 2017/5/5. */ public class VolleyHelper { private static String response; /** * 用于发送 Get 请求的封装方法 * * @param context Activity 的实例 * @param url 请求的地址 * @param callback 用于网络回调的接口 */ public static void sendHttpGet(Context context, String url, final VolleyResponseCallback callback){ RequestQueue requestQueue = Volley.newRequestQueue(context); StringRequest stringRequest = new StringRequest(url , new Response.Listener() { @Override public void onResponse(String s) { callback.onSuccess(s); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { callback.onError(error); } }); requestQueue.add(stringRequest); } public static String sendHttpGet(Context context, String url){ RequestQueue requestQueue = Volley.newRequestQueue(context); StringRequest stringRequest = new StringRequest(url , new Response.Listener() { @Override public void onResponse(String s) { response = s; } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); requestQueue.add(stringRequest); return response; } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/common/net/VolleyResponseCallback.java ================================================ package com.example.developerhaoz.sleephelper.common.net; import com.android.volley.VolleyError; /** * 用于网络请求的回调 * * Created by developerHaoz on 2017/5/3. */ public interface VolleyResponseCallback { void onSuccess(String response); void onError(VolleyError error); } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/common/utils/AppManager.java ================================================ package com.example.developerhaoz.sleephelper.common.utils; import android.app.ActivityManager; import android.content.Context; import android.support.v7.app.AppCompatActivity; import java.util.Stack; /** * Created by developerHaoz on 2017/5/9. */ public class AppManager { private static Stack activityStack; private static AppManager instance; private AppManager(){} public static AppManager getAppManager(){ if(instance == null){ synchronized (AppManager.class){ if(instance == null){ instance = new AppManager(); } } } return instance; } public void addActivity(AppCompatActivity activity){ if(activityStack == null){ activityStack = new Stack<>(); } activityStack.add(activity); } /** * 获得当前Activity(栈顶Activity) * * @return */ public AppCompatActivity currentActivity(){ if(activityStack == null || activityStack.isEmpty()){ return null; } AppCompatActivity acitivity = activityStack.lastElement(); return acitivity; } public AppCompatActivity findActivity(Class cls){ AppCompatActivity activity = null; for (AppCompatActivity appCompatActivity : activityStack) { if(appCompatActivity.getClass().equals(cls)){ activity = appCompatActivity; break; } } return activity; } public void finishActivity(){ AppCompatActivity activity = activityStack.lastElement(); finishActivity(activity); } public void finishActivity(AppCompatActivity activity){ if(activity != null){ activityStack.remove(activity); activity.finish(); activity = null; } } public void finishActivity(Class cls){ for (AppCompatActivity activity : activityStack) { if(activity.getClass().equals(cls)){ finishActivity(activity); } } } public void finishAllActivity(){ for (int i = 0, size = activityStack.size(); i < size; i++) { if (null != activityStack.get(i)) { activityStack.get(i).finish(); } } activityStack.clear(); } public void AppExit(Context context){ try{ finishAllActivity(); ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); activityManager.killBackgroundProcesses(context.getPackageName()); System.exit(0); }catch (Exception e){ e.printStackTrace(); } } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/common/utils/Check.java ================================================ package com.example.developerhaoz.sleephelper.common.utils; import java.util.Collection; import java.util.Map; /** * 辅助检查对象是否为空 * * Created by developerHaoz on 2017/5/3. */ public class Check { public static boolean isNull(Object o){ return o == null; } public static boolean isEmpty(CharSequence str){ return isNull(str) || str.length() ==0; } public static boolean isEmpty(Object[] objects){ return isNull(objects) || objects.length == 0; } public static boolean isEmpty(Collection collection){ return isNull(collection) || collection.isEmpty(); } public static boolean isEmpty(Map map){ return isNull(map) || map.isEmpty(); } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/common/utils/GetRandom.java ================================================ package com.example.developerhaoz.sleephelper.common.utils; /** * 获取随机数的工具类 * * Created by developerHaoz on 2017/5/3. */ public class GetRandom { /** * 获取一个 0 到 48 之间的随机整数 * * @return 一个 随机整数 */ public static int getRandom(){ double random = Math.random(); int result = (int)(random * 50 - 20); return Math.abs(result); } // // /** // * 获取一个 10 到 20 之间的随机整数 // * // * @return // */ // public static int getRandom20(){ // double random = Math.random(); // int result = (int)(random * 10 + 10); // return result; // } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/common/utils/StatusBarCompat.java ================================================ package com.example.developerhaoz.sleephelper.common.utils; import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.os.Build; import android.view.View; import android.view.ViewGroup; /** * 修改状态栏的工具类 * * Created by developerHaoz on 2017/5/3. */ public class StatusBarCompat { private static final int INVALID_VAL = -1; private static final int COLOR_DEFAULT = Color.parseColor("#20000000"); @TargetApi(Build.VERSION_CODES.LOLLIPOP) public static void compat(Activity activity, int statusColor) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (statusColor != INVALID_VAL) { activity.getWindow().setStatusBarColor(statusColor); } return; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { int color = COLOR_DEFAULT; ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content); if (statusColor != INVALID_VAL) { color = statusColor; } View statusBarView = contentView.getChildAt(0); //改变颜色时避免重复添加statusBarView if (statusBarView != null && statusBarView.getMeasuredHeight() == getStatusBarHeight(activity)) { statusBarView.setBackgroundColor(color); return; } statusBarView = new View(activity); ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity)); statusBarView.setBackgroundColor(color); contentView.addView(statusBarView, lp); } } public static void compat(Activity activity) { compat(activity, INVALID_VAL); } private static int getStatusBarHeight(Context context) { int result = 0; int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = context.getResources().getDimensionPixelSize(resourceId); } return result; } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/common/view/CommonPagerAdapter.java ================================================ package com.example.developerhaoz.sleephelper.common.view; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import java.util.List; /** * ViewPager + Fragment 通用的 Adapter * * Created by developerHaoz on 2017/5/2. */ public class CommonPagerAdapter extends FragmentPagerAdapter { private List mFragments; public CommonPagerAdapter(FragmentManager fragmentManager, List mFragments){ super(fragmentManager); this.mFragments = mFragments; } @Override public Fragment getItem(int position) { return mFragments.get(position); } @Override public int getCount() { return mFragments.size(); } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/common/view/CommonTabBean.java ================================================ package com.example.developerhaoz.sleephelper.common.view; import com.flyco.tablayout.listener.CustomTabEntity; /** * * * Created by developerHaoz on 2017/5/3. */ public class CommonTabBean implements CustomTabEntity{ private int selectedIcon; private int unselectedIcon; private String title; public CommonTabBean(String title){ this.title = title; } public CommonTabBean(String title, int selectedIcon, int unselectedIcon) { this.title = title; this.selectedIcon = selectedIcon; this.unselectedIcon = unselectedIcon; } @Override public String getTabTitle() { return title; } @Override public int getTabSelectedIcon() { return selectedIcon; } @Override public int getTabUnselectedIcon() { return unselectedIcon; } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/common/view/GlideHelper.java ================================================ package com.example.developerhaoz.sleephelper.common.view; import android.content.Context; import com.bumptech.glide.Glide; import com.bumptech.glide.request.FutureTarget; import com.bumptech.glide.request.target.Target; import java.io.File; import java.util.concurrent.ExecutionException; /** * Glide 相关的帮助类 * * Created by developerHaoz on 2017/5/6. */ public class GlideHelper { /** * 根据图片的网络地址,拿到使用 Glide 进行缓存后的图片缓存地址 * 注意!!! 该方法要在子线程中调用,否则会出错 * * @param imageUrl 图片的网络地址 * @return 图片的缓存地址 */ public static String getImagePathFromCache(String imageUrl, Context context) { FutureTarget futureTarget = Glide.with(context) .load(imageUrl) .downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL); File cacheFile; try { cacheFile = futureTarget.get(); return cacheFile.getAbsolutePath(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } return null; } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/diary/bean/DiaryBean.java ================================================ package com.example.developerhaoz.sleephelper.diary.bean; /** * 日记的实体类 * * Created by developerHaoz on 2017/5/3. */ public class DiaryBean { private String date; private String title; private String content; private String tag; public DiaryBean(String date, String title, String content, String tag) { this.date = date; this.title = title; this.content = content; this.tag = tag; } public String getTag() { return tag; } public String getDate() { return date; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/diary/db/DiaryDatabaseHelper.java ================================================ package com.example.developerhaoz.sleephelper.diary.db; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; /** * 数据库的帮助类 * * Created by developerHaoz on 2017/5/3. */ public class DiaryDatabaseHelper extends SQLiteOpenHelper{ private Context mContext; private static final String CREATE_DIARY = "create table Diary(" + "id integer primary key autoincrement, " + "date text, " + "title text, " + "tag text, " + "content text)"; public DiaryDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version){ super(context, name, factory, version); this.mContext = context; } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_DIARY); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("drop table if exists Diary"); onCreate(db); } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/diary/event/RefreshViewEvent.java ================================================ package com.example.developerhaoz.sleephelper.diary.event; /** * 刷新日记界面的事件 * * Created by developerHaoz on 2017/5/5. */ public class RefreshViewEvent { } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/diary/event/StartUpdateDiaryEvent.java ================================================ package com.example.developerhaoz.sleephelper.diary.event; import com.example.developerhaoz.sleephelper.diary.bean.DiaryBean; /** * 打开「修改日记」的界面 * * Created by developerHaoz on 2017/5/3. */ public class StartUpdateDiaryEvent { private DiaryBean mDiaryBean; public StartUpdateDiaryEvent(DiaryBean diaryBean) { mDiaryBean = diaryBean; } public DiaryBean getDiaryBean() { return mDiaryBean; } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/diary/ui/AddDiaryActivity.java ================================================ package com.example.developerhaoz.sleephelper.diary.ui; import android.content.ContentValues; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import com.example.developerhaoz.sleephelper.R; import com.example.developerhaoz.sleephelper.diary.db.DiaryDatabaseHelper; import com.example.developerhaoz.sleephelper.diary.utils.GetDate; import com.example.developerhaoz.sleephelper.diary.widget.LinedEditText; import butterknife.Bind; import butterknife.ButterKnife; import butterknife.OnClick; import cc.trity.floatingactionbutton.FloatingActionButton; import cc.trity.floatingactionbutton.FloatingActionsMenu; /** * 添加日记的 Activity *

* Created by developerHaoz on 2017/5/3. */ public class AddDiaryActivity extends AppCompatActivity { @Bind(R.id.add_diary_et_title) EditText mAddDiaryEtTitle; @Bind(R.id.add_diary_et_content) LinedEditText mAddDiaryEtContent; @Bind(R.id.add_diary_fab_back) FloatingActionButton mAddDiaryFabBack; @Bind(R.id.add_diary_fab_add) FloatingActionButton mAddDiaryFabAdd; @Bind(R.id.right_labels) FloatingActionsMenu mRightLabels; @Bind(R.id.home_iv_draw) ImageView mIvDraw; @Bind(R.id.home_tv_title_normal) TextView mTvTitle; @Bind(R.id.home_iv_menu) ImageView mIvMenu; @Bind(R.id.contacts_tab_rl) LinearLayout mContactsTabRl; private DiaryDatabaseHelper mHelper; public static void startActivity(Context context) { Intent intent = new Intent(context, AddDiaryActivity.class); context.startActivity(intent); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_add_diary); ButterKnife.bind(this); Intent intent = getIntent(); initToolbar(); initView(intent); mHelper = new DiaryDatabaseHelper(this, "Diary.db", null, 1); } private void initToolbar() { mIvDraw.setImageResource(R.drawable.app_back); mTvTitle.setText("添加日记"); mIvMenu.setVisibility(View.GONE); } private void initView(Intent intent) { mAddDiaryEtTitle.setText(intent.getStringExtra("title")); mAddDiaryEtContent.setText(intent.getStringExtra("content")); } @OnClick({R.id.home_iv_draw, R.id.add_diary_et_title, R.id.add_diary_et_content, R.id.add_diary_fab_back, R.id.add_diary_fab_add}) public void onClick(View view) { switch (view.getId()) { case R.id.home_iv_draw: backToDiaryFragment(); case R.id.add_diary_et_title: break; case R.id.add_diary_et_content: break; case R.id.add_diary_fab_back: String date = GetDate.getDate().toString(); String tag = String.valueOf(System.currentTimeMillis()); String title = mAddDiaryEtTitle.getText().toString() + ""; String content = mAddDiaryEtContent.getText().toString() + ""; if (!title.equals("") || !content.equals("")) { SQLiteDatabase db = mHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("date", date); values.put("title", title); values.put("content", content); values.put("tag", tag); db.insert("Diary", null, values); values.clear(); } finish(); break; case R.id.add_diary_fab_add: backToDiaryFragment(); break; } } private void backToDiaryFragment() { final String dateBack = GetDate.getDate().toString(); final String titleBack = mAddDiaryEtTitle.getText().toString(); final String contentBack = mAddDiaryEtContent.getText().toString(); if (!titleBack.isEmpty() || !contentBack.isEmpty()) { AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this); alertDialogBuilder.setMessage("是否保存日记内容?").setPositiveButton("确定", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { SQLiteDatabase db = mHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("date", dateBack); values.put("title", titleBack); values.put("content", contentBack); db.insert("Diary", null, values); values.clear(); finish(); } }).setNegativeButton("取消", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { finish(); } }).show(); } else { finish(); } } @Override public void onBackPressed() { super.onBackPressed(); finish(); } @OnClick(R.id.home_iv_draw) public void onViewClicked() { finish(); } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/diary/ui/DiaryAdapter.java ================================================ package com.example.developerhaoz.sleephelper.diary.ui; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import com.example.developerhaoz.sleephelper.R; import com.example.developerhaoz.sleephelper.diary.bean.DiaryBean; import com.example.developerhaoz.sleephelper.diary.event.StartUpdateDiaryEvent; import com.example.developerhaoz.sleephelper.diary.utils.GetDate; import org.greenrobot.eventbus.EventBus; import java.util.List; /** * 日记界面的 Adapter * * Created by developerHaoz on 2017/5/3. */ public class DiaryAdapter extends RecyclerView.Adapter { private Context mContext; private LayoutInflater mLayoutInflater; private List mDiaryBeanList; private int mEditPosition = -1; public DiaryAdapter(Context context, List mDiaryBeanList){ mContext = context; this.mLayoutInflater = LayoutInflater.from(context); this.mDiaryBeanList = mDiaryBeanList; } @Override public DiaryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new DiaryViewHolder(mLayoutInflater.inflate(R.layout.item_rv_diary, parent, false)); } @Override public void onBindViewHolder(final DiaryViewHolder holder, final int position) { String dateSystem = GetDate.getDate().toString(); if(mDiaryBeanList.get(position).getDate().equals(dateSystem)){ holder.mIvCircle.setImageResource(R.drawable.circle_orange); } holder.mTvDate.setText(mDiaryBeanList.get(position).getDate()); holder.mTvTitle.setText(mDiaryBeanList.get(position).getTitle()); holder.mTvContent.setText(" " + mDiaryBeanList.get(position).getContent()); holder.mIvEdit.setVisibility(View.INVISIBLE); if(mEditPosition == position){ holder.mIvEdit.setVisibility(View.VISIBLE); }else { holder.mIvEdit.setVisibility(View.GONE); } holder.mLl.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(holder.mIvEdit.getVisibility() == View.VISIBLE){ holder.mIvEdit.setVisibility(View.GONE); }else { holder.mIvEdit.setVisibility(View.VISIBLE); } if(mEditPosition != position){ notifyItemChanged(mEditPosition); } mEditPosition = position; } }); holder.mIvEdit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EventBus.getDefault().post(new StartUpdateDiaryEvent(mDiaryBeanList.get(position))); } }); } @Override public int getItemCount() { return mDiaryBeanList.size(); } public static class DiaryViewHolder extends RecyclerView.ViewHolder{ TextView mTvDate; TextView mTvTitle; TextView mTvContent; ImageView mIvEdit; LinearLayout mLlTitle; LinearLayout mLl; ImageView mIvCircle; LinearLayout mLlControl; RelativeLayout mRlEdit; DiaryViewHolder(View view){ super(view); mIvCircle = (ImageView) view.findViewById(R.id.main_iv_circle); mTvDate = (TextView) view.findViewById(R.id.main_tv_date); mTvTitle = (TextView) view.findViewById(R.id.main_tv_title); mTvContent = (TextView) view.findViewById(R.id.main_tv_content); mIvEdit = (ImageView) view.findViewById(R.id.main_iv_edit); mLlTitle = (LinearLayout) view.findViewById(R.id.main_ll_title); mLl = (LinearLayout) view.findViewById(R.id.item_ll); mLlControl = (LinearLayout) view.findViewById(R.id.item_ll_control); mRlEdit = (RelativeLayout) view.findViewById(R.id.item_rl_edit); } } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/diary/ui/DiaryFragment.java ================================================ package com.example.developerhaoz.sleephelper.diary.ui; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import com.example.developerhaoz.sleephelper.R; import com.example.developerhaoz.sleephelper.diary.bean.DiaryBean; import com.example.developerhaoz.sleephelper.diary.db.DiaryDatabaseHelper; import com.example.developerhaoz.sleephelper.diary.utils.GetDate; import java.util.ArrayList; import java.util.List; import butterknife.Bind; import butterknife.ButterKnife; import butterknife.OnClick; /** * 有关日记的 Fragment * * Created by developerHaoz on 2017/5/2. */ public class DiaryFragment extends Fragment { @Bind(R.id.main_iv_circle) ImageView mIvCircle; @Bind(R.id.main_tv_date) TextView mTvDate; @Bind(R.id.main_tv_content) TextView mTvContent; @Bind(R.id.item_ll_control) LinearLayout mLlControl; @Bind(R.id.item_first) LinearLayout mItemFirst; @Bind(R.id.main_rv_show_diary) RecyclerView mRvShowDiary; @Bind(R.id.main_ll_main) LinearLayout mLlMain; @Bind(R.id.main_fab_enter_edit) FloatingActionButton mFabEnterEdit; @Bind(R.id.main_rl_main) RelativeLayout mRlMain; @Bind(R.id.main_ll_date) LinearLayout mLlDate; @Bind(R.id.main_ll_content) LinearLayout mLlContent; private List mDiaryBeanList; private DiaryDatabaseHelper mDatabaseHelper; private static final String DB_DIARY_NAME = "Diary.db"; public static DiaryFragment newInstance() { return new DiaryFragment(); } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_diary, container, false); ButterKnife.bind(this, view); mDatabaseHelper = new DiaryDatabaseHelper(getActivity(), DB_DIARY_NAME, null, 1); getDiaryBeanList(); initView(); return view; } private void initView() { mTvDate.setText(GetDate.getDate()); mRvShowDiary.setLayoutManager(new LinearLayoutManager(getActivity())); mRvShowDiary.setAdapter(new DiaryAdapter(getActivity(), mDiaryBeanList)); } private void getDiaryBeanList() { mDiaryBeanList = new ArrayList<>(); List diaryList = new ArrayList<>(); SQLiteDatabase sqliteDatabase = mDatabaseHelper.getWritableDatabase(); Cursor cursor = sqliteDatabase.query("Diary", null, null, null, null, null, null); if (cursor.moveToFirst()) { do { String date = cursor.getString(cursor.getColumnIndex("date")); String dateSystem = GetDate.getDate().toString(); if (date.equals(dateSystem)) { mLlMain.removeView(mItemFirst); break; } } while (cursor.moveToNext()); } if (cursor.moveToFirst()) { do { String date = cursor.getString(cursor.getColumnIndex("date")); String title = cursor.getString(cursor.getColumnIndex("title")); String content = cursor.getString(cursor.getColumnIndex("content")); String tag = cursor.getString(cursor.getColumnIndex("tag")); mDiaryBeanList.add(new DiaryBean(date, title, content, tag)); } while (cursor.moveToNext()); } cursor.close(); for (int i = mDiaryBeanList.size() - 1; i >= 0; i--) { diaryList.add(mDiaryBeanList.get(i)); } mDiaryBeanList = diaryList; } @Override public void onResume() { super.onResume(); getDiaryBeanList(); initView(); } @Override public void onDestroyView() { super.onDestroyView(); ButterKnife.unbind(this); } @OnClick(R.id.main_fab_enter_edit) public void onViewClicked() { AddDiaryActivity.startActivity(getActivity()); } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/diary/ui/UpdateDiaryActivity.java ================================================ package com.example.developerhaoz.sleephelper.diary.ui; import android.content.ContentValues; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import com.example.developerhaoz.sleephelper.R; import com.example.developerhaoz.sleephelper.common.HomeActivity; import com.example.developerhaoz.sleephelper.diary.db.DiaryDatabaseHelper; import com.example.developerhaoz.sleephelper.diary.event.RefreshViewEvent; import com.example.developerhaoz.sleephelper.diary.utils.GetDate; import com.example.developerhaoz.sleephelper.diary.widget.LinedEditText; import com.orhanobut.logger.Logger; import org.greenrobot.eventbus.EventBus; import butterknife.Bind; import butterknife.ButterKnife; import butterknife.OnClick; import cc.trity.floatingactionbutton.FloatingActionButton; import cc.trity.floatingactionbutton.FloatingActionsMenu; /** * 修改日记的 Activity *

* Created by developerHaoz on 2017/5/3. */ public class UpdateDiaryActivity extends AppCompatActivity { @Bind(R.id.update_diary_tv_date) TextView mUpdateDiaryTvDate; @Bind(R.id.update_diary_et_title) EditText mUpdateDiaryEtTitle; @Bind(R.id.update_diary_et_content) LinedEditText mUpdateDiaryEtContent; @Bind(R.id.update_diary_fab_back) FloatingActionButton mUpdateDiaryFabBack; @Bind(R.id.update_diary_fab_add) FloatingActionButton mUpdateDiaryFabAdd; @Bind(R.id.update_diary_fab_delete) FloatingActionButton mUpdateDiaryFabDelete; @Bind(R.id.right_labels) FloatingActionsMenu mRightLabels; @Bind(R.id.update_diary_tv_tag) TextView mTvTag; @Bind(R.id.home_iv_draw) ImageView mIvDraw; @Bind(R.id.home_tv_title_normal) TextView mTvTitle; @Bind(R.id.home_tv_title_center) TextView mTvCenter; @Bind(R.id.home_iv_menu) ImageView mIvMenu; @Bind(R.id.contacts_tab_rl) LinearLayout mContactsTabRl; private DiaryDatabaseHelper mHelper; public static void startActivity(Context context, String title, String content, String tag) { Intent intent = new Intent(context, UpdateDiaryActivity.class); intent.putExtra("title", title); intent.putExtra("content", content); intent.putExtra("tag", tag); context.startActivity(intent); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_update_diary); ButterKnife.bind(this); mHelper = new DiaryDatabaseHelper(this, "Diary.db", null, 1); Intent intent = getIntent(); initToolbar(); initView(intent); String url = "http://ww3.sinaimg.cn/large/7a8aed7bgw1eswencfur6j20hq0qodhs.jpg"; Logger.d(mIvDraw.getContext() + " Activity"); } private void initToolbar() { mIvDraw.setImageResource(R.drawable.app_back); mIvDraw.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); mTvTitle.setText("修改日记"); mIvMenu.setVisibility(View.GONE); } private void initView(Intent intent) { mUpdateDiaryTvDate.setText("今天," + GetDate.getDate()); mUpdateDiaryEtTitle.setText(intent.getStringExtra("title")); mUpdateDiaryEtContent.setText(intent.getStringExtra("content")); mTvTag.setText(intent.getStringExtra("tag")); } @OnClick({R.id.home_iv_draw, R.id.update_diary_fab_back, R.id.update_diary_fab_add, R.id.update_diary_fab_delete}) public void onClick(View view) { switch (view.getId()) { case R.id.home_iv_draw: finish(); case R.id.update_diary_fab_back: showTips(); break; case R.id.update_diary_fab_add: SQLiteDatabase dbUpdate = mHelper.getWritableDatabase(); ContentValues valuesUpdate = new ContentValues(); String title = mUpdateDiaryEtTitle.getText().toString(); String content = mUpdateDiaryEtContent.getText().toString(); valuesUpdate.put("title", title); valuesUpdate.put("content", content); dbUpdate.update("Diary", valuesUpdate, "title = ?", new String[]{title}); dbUpdate.update("Diary", valuesUpdate, "content = ?", new String[]{content}); finish(); break; case R.id.update_diary_fab_delete: finish(); break; } } private void showTips() { AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this); alertDialogBuilder.setMessage("确定要删除该日记吗?").setPositiveButton("确定", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { String tag = mTvTag.getText().toString(); SQLiteDatabase dbDelete = mHelper.getWritableDatabase(); dbDelete.delete("Diary", "tag = ?", new String[]{tag}); finish(); HomeActivity.startActivity(UpdateDiaryActivity.this); } }).setNegativeButton("取消", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { } }).show(); EventBus.getDefault().post(new RefreshViewEvent()); } @Override public void onBackPressed() { super.onBackPressed(); finish(); } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/diary/utils/GetDate.java ================================================ package com.example.developerhaoz.sleephelper.diary.utils; import java.util.Calendar; /** * 获取当前的日期,格式为:2017 年 5 月 4 日 * * Created by developerHaoz on 2017/5/3. */ public class GetDate { public static StringBuilder getDate(){ StringBuilder stringBuilder = new StringBuilder(); Calendar now = Calendar.getInstance(); stringBuilder.append(now.get(Calendar.YEAR) + " 年 "); stringBuilder.append((int)(now.get(Calendar.MONTH) + 1) + " 月 "); stringBuilder.append(now.get(Calendar.DAY_OF_MONTH) + " 日"); return stringBuilder; } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/diary/utils/SpHelper.java ================================================ package com.example.developerhaoz.sleephelper.diary.utils; import android.content.Context; import android.content.SharedPreferences; /** * SharedPreferences 的辅助类 * * Created by developerHaoz on 2017/5/3. */ public class SpHelper { private static final String SP_NAME = "sp_name"; private static SpHelper mSpHelper; private Context mAppContext; private SharedPreferences mSharedPreferences; private String info; private SpHelper(Context context){ mAppContext = context.getApplicationContext(); } //获取SpHelper的实例 public static SpHelper getInstance(Context context){ if(mSpHelper == null){ synchronized (SpHelper.class){ if(mSpHelper == null){ mSpHelper = new SpHelper(context); } } } return mSpHelper; } private SharedPreferences getSharePreferences(){ if(mSharedPreferences == null){ mSharedPreferences = mAppContext.getSharedPreferences(SP_NAME, Context.MODE_APPEND); } return mSharedPreferences; } public void setInfo(String info){ this.info = info; getSharePreferences().edit().putString("info", info).apply(); } public String getInfo(){ if(info.equals("") || info.length() == 0){ info = getSharePreferences().getString("info", ""); } return info; } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/diary/widget/LinedEditText.java ================================================ package com.example.developerhaoz.sleephelper.diary.widget; import android.annotation.TargetApi; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.DashPathEffect; import android.graphics.Paint; import android.graphics.PathEffect; import android.os.Build; import android.util.AttributeSet; /** * Created by developerHaoz on 2017/5/3. */ public class LinedEditText extends android.support.v7.widget.AppCompatEditText{ public LinedEditText(Context context) { super(context); initPaint(); } public LinedEditText(Context context, AttributeSet attrs) { super(context, attrs); initPaint(); } public LinedEditText(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initPaint(); } private void initPaint() { } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override protected void onDraw(Canvas canvas) { Paint mPaint = new Paint(); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(Color.LTGRAY); PathEffect effects = new DashPathEffect(new float[]{5, 5, 5, 5}, 5); mPaint.setPathEffect(effects); int left = getLeft(); int right = getRight(); int paddingTop = getPaddingTop(); int paddingBottom = getPaddingBottom(); int paddingLeft = getPaddingLeft(); int paddingRight = getPaddingRight(); int height = getHeight(); int lineHeight = getLineHeight(); int spcingHeight = (int) getLineSpacingExtra(); int count = (height - paddingTop - paddingBottom) / lineHeight; for (int i = 0; i < count; i++) { int baseline = lineHeight * (i + 1) + paddingTop - spcingHeight / 2; canvas.drawLine(paddingLeft, (int) (baseline * 1.0), right - paddingRight * (int) 1.8, (int) (baseline * 1.0), mPaint); } super.onDraw(canvas); } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/duanzi/api/DuanziApi.java ================================================ package com.example.developerhaoz.sleephelper.duanzi.api; /** * 有关段子的 Api * * Created by developerHaoz on 2017/5/7. */ public class DuanziApi { public static final String GET_DUANZI = "http://is.snssdk.com/neihan/stream/mix/v1/?mpic=1&webp=1&essence=1&content_type=-102&message_cursor=-1&am_longitude=110&am_latitude=120&am_city=%E5%8C%97%E4%BA%AC%E5%B8%82&am_loc_time=1489226058493&count=30&min_time=1489205901&screen_width=1450&do00le_col_mode=0&iid=3216590132&device_id=32613520945&ac=wifi&channel=360&aid=7&app_name=joke_essay&version_code=612&version_name=6.1.2&device_platform=android&ssmix=a&device_type=sansung&device_brand=xiaomi&os_api=28&os_version=6.10.1&uuid=326135942187625&openudid=3dg6s95rhg2a3dg5&manifest_version_code=612&resolution=1450*2800&dpi=620&update_version_code=6120"; } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/duanzi/bean/DuanziBean.java ================================================ package com.example.developerhaoz.sleephelper.duanzi.bean; import com.google.gson.annotations.SerializedName; /** * 段子的实体类 * * Created by developerHaoz on 2017/5/7. */ public class DuanziBean { @SerializedName("group") private GroupBean groupBean; private String type; public GroupBean getGroupBean() { return groupBean; } public void setGroupBean(GroupBean groupBean) { this.groupBean = groupBean; } public String getType() { return type; } public void setType(String type) { this.type = type; } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/duanzi/bean/GroupBean.java ================================================ package com.example.developerhaoz.sleephelper.duanzi.bean; /** * 段子中实体类 * * Created by developerHaoz on 2017/5/7. */ public class GroupBean { private String text; private long id; private UserBean user; public String getText() { return text; } public long getId() { return id; } public UserBean getUser() { return user; } public static class UserBean { private long user_id; private String name; private String avatar_url; public String getName() { return name; } public String getAvatar_url() { return avatar_url; } } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/duanzi/ui/DuanziAdapter.java ================================================ package com.example.developerhaoz.sleephelper.duanzi.ui; import android.support.v4.app.Fragment; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.bumptech.glide.Glide; import com.example.developerhaoz.sleephelper.R; import com.example.developerhaoz.sleephelper.common.utils.Check; import com.example.developerhaoz.sleephelper.duanzi.bean.DuanziBean; import java.util.List; import de.hdodenhof.circleimageview.CircleImageView; /** * 段子界面的 Adapter * * Created by developerHaoz on 2017/5/7. */ public class DuanziAdapter extends RecyclerView.Adapter{ private OnItemClickCallback mCallback; public interface OnItemClickCallback{ void onItemClick(int position); } private Fragment mFragment; private List mDuanziBeanList; public DuanziAdapter(Fragment fragment, List duanziBeanList, OnItemClickCallback callback){ this.mFragment = fragment; this.mDuanziBeanList = duanziBeanList; this.mCallback = callback; } @Override public DuanziViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_duanzi, null); return new DuanziViewHolder(view); } @Override public void onBindViewHolder(DuanziViewHolder holder, int position) { RecyclerView rvTest = (RecyclerView) holder.itemView.getParent(); try { DuanziBean duanziBean = mDuanziBeanList.get(position); if (!Check.isEmpty(duanziBean.getGroupBean().getUser().getAvatar_url())) { Glide.with(mFragment).load(duanziBean.getGroupBean().getUser().getAvatar_url()).into(holder.mCivAvatar); } holder.mTvContent.setText(duanziBean.getGroupBean().getText()); holder.mTvAuthor.setText(duanziBean.getGroupBean().getUser().getName()); } catch (Exception e) { e.printStackTrace(); } } @Override public int getItemCount() { return mDuanziBeanList.size(); } class DuanziViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ private CircleImageView mCivAvatar; private TextView mTvAuthor; private TextView mTvContent; public DuanziViewHolder(View itemView) { super(itemView); mCivAvatar = (CircleImageView) itemView.findViewById(R.id.duanzi_civ_avatar); mTvAuthor = (TextView) itemView.findViewById(R.id.duanzi_tv_author); mTvContent = (TextView) itemView.findViewById(R.id.duanzi_tv_content); } @Override public void onClick(View v) { mCallback.onItemClick(getAdapterPosition()); } } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/duanzi/ui/DuanziFragment.java ================================================ package com.example.developerhaoz.sleephelper.duanzi.ui; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import com.android.volley.VolleyError; import com.example.developerhaoz.sleephelper.R; import com.example.developerhaoz.sleephelper.common.net.VolleyHelper; import com.example.developerhaoz.sleephelper.common.net.VolleyResponseCallback; import com.example.developerhaoz.sleephelper.duanzi.api.DuanziApi; import com.example.developerhaoz.sleephelper.duanzi.bean.DuanziBean; import com.example.developerhaoz.sleephelper.duanzi.utils.GsonHelper; import com.orhanobut.logger.Logger; import java.util.List; import butterknife.Bind; import butterknife.ButterKnife; /** * 有关段子的 Fragment * * Created by developerHaoz on 2017/5/2. */ public class DuanziFragment extends Fragment implements DuanziAdapter.OnItemClickCallback{ @Bind(R.id.duanzi_rv_show_duanzi) RecyclerView mRvShowDuanzi; @Bind(R.id.duanzi_refresh) SwipeRefreshLayout mRefresh; public static DuanziFragment newInstance() { return new DuanziFragment(); } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_duanzi, container, false); ButterKnife.bind(this, view); initView(); initRefresh(); return view; } private void initRefresh() { mRefresh.setColorSchemeResources(R.color.colorPrimary); mRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { initView(); mRefresh.setRefreshing(false); } }); } private void initView() { VolleyHelper.sendHttpGet(getActivity(), DuanziApi.GET_DUANZI, new VolleyResponseCallback() { @Override public void onSuccess(String response) { List mDuanziBeanList = GsonHelper.getDuanziBeanList(response); if(mDuanziBeanList.size() > 4){ mDuanziBeanList.remove(3); } mRvShowDuanzi.setLayoutManager(new LinearLayoutManager(getActivity())); mRvShowDuanzi.setAdapter(new DuanziAdapter(DuanziFragment.this, mDuanziBeanList, DuanziFragment.this)); } @Override public void onError(VolleyError error) { Logger.d(error); } }); } @Override public void onDestroyView() { super.onDestroyView(); ButterKnife.unbind(this); } @Override public void onItemClick(int position) { Toast.makeText(getActivity(), position, Toast.LENGTH_SHORT).show(); } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/duanzi/utils/GsonHelper.java ================================================ package com.example.developerhaoz.sleephelper.duanzi.utils; import com.example.developerhaoz.sleephelper.duanzi.bean.DuanziBean; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import org.json.JSONException; import org.json.JSONObject; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; /** * 用于 Json 解析的帮助类 * * Created by developerHaoz on 2017/5/7. */ public class GsonHelper { public static List getDuanziBeanList(String response){ List mDuanziBeanList = new ArrayList<>(); try { JSONObject jsonObject = new JSONObject(response); String dataArrayStr = jsonObject.getJSONObject("data").getString("data"); Type type = new TypeToken>(){}.getType(); Gson gson = new Gson(); mDuanziBeanList = gson.fromJson(dataArrayStr, type); return mDuanziBeanList; } catch (JSONException e) { e.printStackTrace(); } return mDuanziBeanList; } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/meizi/api/MeiziApi.java ================================================ package com.example.developerhaoz.sleephelper.meizi.api; import android.content.Context; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.StringRequest; import com.android.volley.toolbox.Volley; import com.example.developerhaoz.sleephelper.common.SleepApplication; import com.example.developerhaoz.sleephelper.common.utils.GetRandom; import com.example.developerhaoz.sleephelper.meizi.bean.MeiziBean; import com.orhanobut.logger.Logger; import java.util.ArrayList; import java.util.List; import java.util.Random; /** * 获取妹子图的 Api * * Created by developerHaoz on 2017/5/3. */ public class MeiziApi { private static String meiziData = ""; private static final int IMAGE_AMOUNT= 20; public final static String[] imageUrls = new String[] { "http://img.my.csdn.net/uploads/201309/01/1378037235_3453.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037235_9280.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037234_3539.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037234_6318.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037194_2965.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037193_1687.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037193_1286.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037192_8379.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037178_9374.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037177_1254.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037177_6203.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037152_6352.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037151_9565.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037151_7904.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037148_7104.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037129_8825.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037128_5291.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037128_3531.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037127_1085.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037095_7515.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037094_8001.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037093_7168.jpg", "http://img.my.csdn.net/uploads/201309/01/1378037091_4950.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949643_6410.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949642_6939.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949630_4505.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949630_4593.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949629_7309.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949629_8247.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949615_1986.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949614_8482.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949614_3743.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949614_4199.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949599_3416.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949599_5269.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949598_7858.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949598_9982.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949578_2770.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949578_8744.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949577_5210.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949577_1998.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949482_8813.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949481_6577.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949480_4490.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949455_6792.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949455_6345.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949442_4553.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949441_8987.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949441_5454.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949454_6367.jpg", "http://img.my.csdn.net/uploads/201308/31/1377949442_4562.jpg" }; /** * 返回一个随机生成的妹子 Api * * @return meizi Api */ public static String getMeiziApi(){ StringBuilder meiziApi = new StringBuilder(); meiziApi.append("http://gank.io/api/data/%E7%A6%8F%E5%88%A9/").append("15").append("/" + GetRandom.getRandom()); return String.valueOf(meiziApi); } public static List getMeiziBeanList(){ List meiziBeanList = new ArrayList<>(); List randomIntList = new ArrayList<>(); for (int i = 0; i < IMAGE_AMOUNT; i++) { randomIntList.add(getRandom(IMAGE_AMOUNT)); meiziBeanList.add(new MeiziBean(imageUrls[getRandom(IMAGE_AMOUNT)])); } return meiziBeanList; } /** * 获取一个小于 IMAGE_AMOUNT * * @return */ private static int getRandom(int size){ Random random = new Random(); float randomInt = random.nextFloat(); return Integer.valueOf((int) (randomInt * size)); } public static String getMeiziData(Context context){ String url = getMeiziApi(); RequestQueue requestQueue = Volley.newRequestQueue(context); StringRequest stringRequest = new StringRequest(url, new Response.Listener() { @Override public void onResponse(String s) { meiziData = s; } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Logger.d(error); } }); SleepApplication sleepApplication = new SleepApplication(); requestQueue.add(stringRequest); return meiziData; } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/meizi/bean/MeiziBean.java ================================================ package com.example.developerhaoz.sleephelper.meizi.bean; import com.google.gson.annotations.SerializedName; /** * 妹子的实体类 * * Created by developerHaoz on 2017/5/3. */ public class MeiziBean { @SerializedName("_id") private String id; @SerializedName("url") private String imageUrl; @SerializedName("who") private String who; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getImageUrl() { return imageUrl; } public void setImageUrl(String imageUrl){ this.imageUrl = imageUrl; } public MeiziBean(String imageUrl){ this.imageUrl = imageUrl; } public MeiziBean(){ } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/meizi/event/MeiziBeanListEvent.java ================================================ package com.example.developerhaoz.sleephelper.meizi.event; import com.example.developerhaoz.sleephelper.meizi.bean.MeiziBean; import java.util.List; /** * 包含妹子信息的 Event * * Created by developerHaoz on 2017/5/3. */ public class MeiziBeanListEvent { private List mMeiziBeanList; public MeiziBeanListEvent(List meiziBeanList) { mMeiziBeanList = meiziBeanList; } public List getMeiziBeanList() { return mMeiziBeanList; } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/meizi/ui/DetailActivity.java ================================================ package com.example.developerhaoz.sleephelper.meizi.ui; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import com.example.developerhaoz.sleephelper.R; import com.example.developerhaoz.sleephelper.common.utils.Check; import com.example.developerhaoz.sleephelper.common.view.CommonPagerAdapter; import com.example.developerhaoz.sleephelper.common.view.GlideHelper; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import bolts.Continuation; import bolts.Task; import butterknife.Bind; import butterknife.ButterKnife; /** * 查看大图的 Activity * * Created by developerHaoz on 2017/5/5. */ public class DetailActivity extends AppCompatActivity { /** * 保存图片网络地址的 List */ private List mImageUrlList; /** * ViewPager 中所有的 Fragment */ private List mFragments; /** * 保存图片缓存地址的 List */ private List mCachePathList; private static final String IMAGE_URL_LIST = "imageUrlList"; private static final String POSITION = "position"; @Bind(R.id.detail_vp_show_photo) ViewPager mVpShowPhoto; public static void startActivity(Context context, ArrayList imageUrlList, int position) { Intent intent = new Intent(context, DetailActivity.class); Bundle bundle = new Bundle(); bundle.putStringArrayList(IMAGE_URL_LIST, imageUrlList); bundle.putInt(POSITION, position); intent.putExtras(bundle); context.startActivity(intent); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_detail); ButterKnife.bind(this); Bundle bundle = getIntent().getExtras(); mImageUrlList = new ArrayList<>(); mFragments = new ArrayList<>(); mCachePathList = new ArrayList<>(); int position = getIntent().getIntExtra(POSITION, -1); mImageUrlList = getIntent().getStringArrayListExtra(IMAGE_URL_LIST); initViewWithCache(position); } /** * 通过图片的缓存地址来初始化界面 */ private void initViewWithCache(final int position) { Task.call(new Callable>() { @Override public List call() throws Exception { for (String imageUrl : mImageUrlList) { mCachePathList.add(GlideHelper.getImagePathFromCache(imageUrl, DetailActivity.this)); } return mCachePathList; } }, Task.BACKGROUND_EXECUTOR).continueWith(new Continuation, Object>() { @Override public Object then(Task> task) throws Exception { List mCachePathList = task.getResult(); if(!Check.isEmpty(mCachePathList)){ for (String cachePath : mCachePathList) { DetailFragment fragment = DetailFragment.newInstance(cachePath); mFragments.add(fragment); } CommonPagerAdapter adapter = new CommonPagerAdapter(getSupportFragmentManager(), mFragments); mVpShowPhoto.setAdapter(adapter); mVpShowPhoto.setCurrentItem(position); } return null; } }, Task.UI_THREAD_EXECUTOR); } @Override public void onBackPressed() { super.onBackPressed(); finish(); } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/meizi/ui/DetailFragment.java ================================================ package com.example.developerhaoz.sleephelper.meizi.ui; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.bumptech.glide.Glide; import com.example.developerhaoz.sleephelper.R; import butterknife.Bind; import butterknife.ButterKnife; import uk.co.senab.photoview.PhotoView; import uk.co.senab.photoview.PhotoViewAttacher; /** * 显示大图的 Fragment * * Created by developerHaoz on 2017/5/5. */ public class DetailFragment extends Fragment { private static final String IMAGE_URL = "imageUrl"; @Bind(R.id.detail_pv_show_photo) PhotoView mPvShowPhoto; public static DetailFragment newInstance(String imageUrl) { DetailFragment fragment = new DetailFragment(); Bundle bundle = new Bundle(); bundle.putString(IMAGE_URL, imageUrl); fragment.setArguments(bundle); return fragment; } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_detail, container, false); ButterKnife.bind(this, view); Bundle bundle = getArguments(); String imageUrl = bundle.getString(IMAGE_URL); Glide.with(this).load(imageUrl).into(mPvShowPhoto); mPvShowPhoto.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() { @Override public void onPhotoTap(View view, float v, float v1) { getActivity().finish(); } @Override public void onOutsidePhotoTap() { } }); return view; } @Override public void onDestroyView() { super.onDestroyView(); ButterKnife.unbind(this); } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/meizi/ui/MeiziAdapter.java ================================================ package com.example.developerhaoz.sleephelper.meizi.ui; import android.support.v4.app.Fragment; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.example.developerhaoz.sleephelper.R; import com.example.developerhaoz.sleephelper.meizi.bean.MeiziBean; import java.util.ArrayList; import java.util.List; /** * MeiziFragment 的 Adapter * * Created by developerHaoz on 2017/5/3. */ public class MeiziAdapter extends RecyclerView.Adapter { private List mMeiziBeanList; private Fragment mFragment; public MeiziAdapter(List mMeiziBeanList, Fragment mFragment){ this.mMeiziBeanList = mMeiziBeanList; this.mFragment = mFragment; } @Override public MeiziViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_meizi, null); return new MeiziViewHolder(view); } @Override public void onBindViewHolder(MeiziViewHolder holder, final int position) { Glide.with(mFragment) .load(mMeiziBeanList.get(position).getImageUrl()) .fitCenter() .dontAnimate() .diskCacheStrategy(DiskCacheStrategy.ALL) .into(holder.mIvMeizi); holder.mIvMeizi.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ArrayList resultList = new ArrayList(); for (MeiziBean meiziBean : mMeiziBeanList) { resultList.add(meiziBean.getImageUrl()); } DetailActivity.startActivity(mFragment.getActivity(), resultList, position); } }); } @Override public int getItemCount() { if(mMeiziBeanList.size() > 0){ return mMeiziBeanList.size(); } return 0; } public static class MeiziViewHolder extends RecyclerView.ViewHolder{ ImageView mIvMeizi; public MeiziViewHolder(View itemView) { super(itemView); mIvMeizi = (ImageView) itemView.findViewById(R.id.item_iv_meizi); } } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/meizi/ui/MeiziFragment.java ================================================ package com.example.developerhaoz.sleephelper.meizi.ui; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.example.developerhaoz.sleephelper.R; import com.example.developerhaoz.sleephelper.meizi.api.MeiziApi; import com.example.developerhaoz.sleephelper.meizi.bean.MeiziBean; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import butterknife.Bind; import butterknife.ButterKnife; /** * 有关妹子的 Fragment *

* Created by developerHaoz on 2017/5/2. */ public class MeiziFragment extends Fragment { @Bind(R.id.meizi_rv_show_meizi) RecyclerView mRvShowMeizi; @Bind(R.id.meizi_refresh) SwipeRefreshLayout mRefresh; List meiziBeanList = new ArrayList<>(); private static String response = ""; public static MeiziFragment newInstance() { return new MeiziFragment(); } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_meizi, container, false); ButterKnife.bind(this, view); initView(); refreshMeizi(); return view; } /** * 刷新当前界面 */ private void refreshMeizi() { mRefresh.setColorSchemeResources(R.color.colorPrimary); mRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { initView(); mRefresh.setRefreshing(false); } }); } private void initView() { Set meiziSet = new HashSet<>(); meiziSet.addAll(MeiziApi.getMeiziBeanList()); meiziBeanList.clear(); meiziBeanList.addAll(meiziSet); Collections.shuffle(meiziBeanList); mRvShowMeizi.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)); mRvShowMeizi.setAdapter(new MeiziAdapter(meiziBeanList, MeiziFragment.this)); // VolleyHelper.sendHttpGet(getActivity(), MeiziApi.getMeiziApi(), new VolleyResponseCallback() { // @Override // public void onSuccess(String s) { // response = s; // meiziBeanList = GsonHelper.getMeiziBean(response); // mRvShowMeizi.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)); // Collections.shuffle(meiziBeanList); // mRvShowMeizi.setAdapter(new MeiziAdapter(meiziBeanList, MeiziFragment.this)); // } // // @Override // public void onError(VolleyError error) { // Logger.d(error); // } // }); } @Override public void onDestroyView() { super.onDestroyView(); ButterKnife.unbind(this); } } ================================================ FILE: app/src/main/java/com/example/developerhaoz/sleephelper/meizi/utils/GsonHelper.java ================================================ package com.example.developerhaoz.sleephelper.meizi.utils; import com.example.developerhaoz.sleephelper.meizi.bean.MeiziBean; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import org.json.JSONException; import org.json.JSONObject; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; /** * Gson 的处理类 * * Created by developerHaoz on 2017/5/3. */ public class GsonHelper { /** * 将一个 String 类型的数据解析成一个 List * * @param response 包含妹子信息的 String * @return List */ public static List getMeiziBean(String response){ List meiziBeanList = new ArrayList<>(); try { JSONObject jsonObject = new JSONObject(response); String meiziArrayStr = jsonObject.getString("results"); Type meiziListType = new TypeToken>(){}.getType(); Gson gson = new Gson(); meiziBeanList = gson.fromJson(meiziArrayStr, meiziListType); } catch (JSONException e) { e.printStackTrace(); } return meiziBeanList; } } ================================================ FILE: app/src/main/res/drawable/linear_style.xml ================================================ ================================================ FILE: app/src/main/res/drawable/shape_add_diary_title.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_add_diary.xml ================================================ /> ================================================ FILE: app/src/main/res/layout/activity_detail.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_home.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_test.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_update_diary.xml ================================================ ================================================ FILE: app/src/main/res/layout/fragment_detail.xml ================================================ ================================================ FILE: app/src/main/res/layout/fragment_diary.xml ================================================ ================================================ FILE: app/src/main/res/layout/fragment_duanzi.xml ================================================ ================================================ FILE: app/src/main/res/layout/fragment_meizi.xml ================================================ ================================================ FILE: app/src/main/res/layout/item_duanzi.xml ================================================ ================================================ FILE: app/src/main/res/layout/item_first.xml ================================================ ================================================ FILE: app/src/main/res/layout/item_meizi.xml ================================================ ================================================ FILE: app/src/main/res/layout/item_rv_diary.xml ================================================ ================================================ FILE: app/src/main/res/layout/layout_app_divide.xml ================================================ ================================================ FILE: app/src/main/res/layout/layout_app_toolbar.xml ================================================ ================================================ FILE: app/src/main/res/layout/layout_home_header.xml ================================================ ================================================ FILE: app/src/main/res/menu/menu_me.xml ================================================

================================================ FILE: app/src/main/res/values/colors.xml ================================================ #2196F3 #1976D2 #BBDEFB #FF4081 #448AFF #212121 #757575 #FFFFFF #BDBDBD #bbafb4 #ffffff #000000 #f4f4f4 #cdcdcd ================================================ FILE: app/src/main/res/values/strings.xml ================================================ SleepHelper drawer_open drawer_close 看爸爸的帅照 切换夜间模式 关于我们 反馈 ================================================ FILE: app/src/main/res/values/styles.xml ================================================ ================================================ FILE: app/src/test/java/com/example/developerhaoz/sleephelper/ExampleUnitTest.java ================================================ package com.example.developerhaoz.sleephelper; import org.junit.Test; import static org.junit.Assert.*; /** * Example local unit test, which will execute on the development machine (host). * * @see Testing documentation */ public class ExampleUnitTest { @Test public void addition_isCorrect() throws Exception { assertEquals(4, 2 + 2); } } ================================================ FILE: app/src/test/java/com/example/developerhaoz/sleephelper/common/HomeActivityTest.java ================================================ package com.example.developerhaoz.sleephelper.common; import org.junit.Test; /** * Created by developerHaoz on 2017/10/18. */ public class HomeActivityTest { @Test public void startActivity() throws Exception { } @Test public void onCreate() throws Exception { } @Test public void startUpdateDiaryActivity() throws Exception { } @Test public void onDestroy() throws Exception { } @Test public void onBackPressed() throws Exception { } } ================================================ FILE: build.gradle ================================================ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.3.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { jcenter() maven { url "https://jitpack.io" } } } task clean(type: Delete) { delete rootProject.buildDir } ================================================ FILE: gradle/wrapper/gradle-wrapper.properties ================================================ #Tue May 02 11:05:07 CST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip ================================================ FILE: gradle.properties ================================================ # Project-wide Gradle settings. # IDE (e.g. Android Studio) users: # Gradle settings configured through the IDE *will override* # any settings specified in this file. # For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. org.gradle.jvmargs=-Xmx1536m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true ================================================ FILE: gradlew ================================================ #!/usr/bin/env bash ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn ( ) { echo "$*" } die ( ) { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; esac # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=$((i+1)) done case $i in (0) set -- ;; (1) set -- "$args0" ;; (2) set -- "$args0" "$args1" ;; (3) set -- "$args0" "$args1" "$args2" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules function splitJvmOpts() { JVM_OPTS=("$@") } eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" ================================================ FILE: gradlew.bat ================================================ @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS= set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windowz variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* goto execute :4NT_args @rem Get arguments from the 4NT Shell from JP Software set CMD_LINE_ARGS=%$ :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: settings.gradle ================================================ include ':app'