项目总结

  • 不熟练的地方
  • 运用到的知识
  • 工具库的封装

待提高的地方

  • 将设计稿100%实现

遇见的问题与解决

需求:实现图片按钮的需求。要求在一个按钮的实现图片加文本居中显示。

实现:自定义控件ImageButton。ImageButton继承了LinearLayout,加载了R.layout.ui_imagebutton_h布局,R.layout.ui_imagebutton_h里定义了一个ImageViewTextView,暴露设置文字,文字大小,文字颜色,图片等设置的接口。问题解决。

当初的思路有其他两种实现方式:

  1. 自定义控件继承与Button或ImageButton,重写onDraw()方法,绘制图片与文字。这种思路可以保留Button的系统定义的功能,不用我们自己再去写。但可能代码复杂度要高点,不如复合控件来得快。有时依项目要求要重写 onMeasure onLayout()方法来控制布局大小。
  2. 利用Button 的 android:drawableLeft 来实现图文混排。实际测试发现,无法实现图文居中显示,图与文字的距离无法控制,系统默认为图片在控件的最左边。可能需要我们自己复写 相应drawableLeft属性对应的方法。

需求:圆形按钮的实现加点击效果的实现。

实现:实现圆形按钮就是为此建立一个drawable文件即可。同理,点击效果使用selector即可。

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <!-- 填充的颜色 --> <solid android:color="#23cdde" /> <!-- 设置按钮的四个角为弧形 --> <!-- android:radius 弧形的半径 --> <corners android:radius="5dip" />
</shape>

需求:主页面需要在底部添加4个水平排列且均匀分布的选项按钮,选项按钮样式为图片在上,文字在下,同时单击选项按钮时,主页面的界面改变成相应的页面,按钮的图片颜色与文字都变化成指定的颜色。很常见的导航按钮。

实现:选项按钮的样式实现仍然采用复合型控件的方式,名OptionView,其xml文件包括一个表示指示器的TextView控件,一个显示图片的ImageView,一个显示文字的TextView,无难度。图片颜色的变化利用ColorMatrix颜色矩阵。文字的颜色变化系统可以控制。 指示器的显示与否我选择控制其透明度来实现。在OptionView类中,暴露一个change()方法,使得可以同时改变指示器,图片,文字。图片颜色的变化用一个自定义方法handleImage(Bitmap bm, int value)来处理。OptionView中定义一个私有变量isChange(),并暴露其get/setter方法。由于在此需求该控件只在xml引用,故只重写了public OptionView(Context context, AttributeSet attrs)方法,并自己自定义所需的xml属性,来获得文字,变化的颜色,文字大小,需设置的图片源等。在主页面加载布局文件时,获得4个OptionView的实例,为其添加单击事件监听。维护一个OptionView实例的的全局变量mSelected,表示该控件为当前选择控件,在主页面的onCreate方法中将某一个OptionView实例赋值给它同时调用它的change()方法。而在单击事件中,只要判断当前选择的OptionView控件是否为当前选择的控件,如果是,无作为,如果不是,则调用两者的change()方法并改变mSelected的值,接下来,就是Fragment的切换的问题了。需求实现。

单击事件的思路:最初实现按钮的单击事件时使用了复杂的观察者模式,让OptionView实现一个接口A,接口B的实现类保存所有A接口的实例并暴露添加,移除,通知观察这变化的办法。虽然结果也能实现,但是代码复杂,组织混乱。尤其是其实这里并不适用这个模式,让所有的按钮对单击事件感兴趣,如果某个按钮的单击事件会使得多个组件,多个页面,多个所谓的“观察者”感兴趣的话,才比较适合。一个主题通知所有观察者去变化。而这里,组件的单击事件存在互斥关系,且唯有且仅有此optionView的控件感兴趣。所以还不如用 维护一个变量来得实在。

指示器的变化思路:可以通过改变控件的View.setVisibility(visibility);方法来显示和隐藏控件。


需求:在单击optionView的事件中,要将 主页面 替换成 相应的页面。

实现:Fragment 实现。4个optionView分别对应4个Fragment的子类。在主界面维护显示的Fragment的变量mMain,单击事件中去判断mMain的是否为空,空实例化相应的Fragment出来,不为空直接调用FragmentTransaction.replace(R.id.main, mMain, "main")方法替换掉。需求实现。

值得注意的是:处理好Fragment 与 Activity 之间的生命周期问题。调用replace方法,会调用remove方法,所以要在Fragment的生命周期里恰当的保存好所需的信息。同时要处理好Activity的重建,例如设备转换屏幕时。


需求:第一个optionView所对应的Fragment需实现一个上部图片轮滑的效果来显示广告,同时需要显示4个系列的入口。整体效果应如下: 

实现:上部利用ViewPager 加 自定义的 IndicatorView 来实现圆点效果。中间显示的利用GridView来实现。主要是适配器Mainshow如何适配的问题。实现GridView的OnItemClickListener事件实现跳转需求。同时解决Fragment生命周期的问题,避免重复加载布局。该需求最大的难点为适配器。所以说说适配器是如何实现的。适配器的关键是Item的设置。在该需求中,选择自定义控件ListImage来填充Item。ListImage为左图,标题,分割线,图片,分别对应TextView,TextView,ImageView的复合型控件,实现起来不难。但是要控制ImageView图片的适配问题。同时解决如何不同分割线的绘制。需求实现。

实现分割线效果:我实现的思路将分割线分割成一个小图片,然后平铺。而Android实现平铺效果的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"android:src="@drawable/line1"android:tileMode="repeat" />

需求实现。

实现图片轮滑效果:这个实现了ViewPager.PageAdapter,问题解决,指示器的样式只要传给指示器一个ViewPage的实例即可。这指示器基本采用网上源码来实现。所以没什么好说的。传好参数就行了。

解决布局问题:这里我使用了Lin为了但是我们要让其显示在Item的最下面,但是实际效果为


需求:在通过主界面点击ListImage后进入列表显示商品介绍。每一个Item显示图片,显示手表名称,手表简介,手表获得的赞数,手表获得的评论。单击Item触发单击事件,进入该手表的详情信息页。

在这个需求里,我遇到的问题为:这些信息都是通过网络来的,所以我必须跟服务器进行交互。这里我直接封装了常用的网络访问库 NetHelp,使用基本的HttpURLConnection与服务器进行交互,暴露sendRequestWithHttpConnect(String request,int Method, IDate i)方法,接受请求命令,注意不是完整的url地址,有关于url的地址会在方法内进行拼装,因为我提供了一个合同类Contract定义了与服务端的数据交互的url常量。在NetHelp类中我可以维护一个保存当前请求的参数mparmasHashMap类型,如果服务端的请求url发生变化时,不必更改所有使用的url,同时保证拼接url不会出现拼接不完全的问题。因为一个完整的url我分成了三部分,指向服务端的域名的基本url,向服务端请求的具体方法,携带的参数 key - value 值。尤其是在拼接参数时同时对参数进行中文编码。当然,在NetHelp类中不处理返回的response,由调用者来自行决定如何处理。我提供一个IDate接口,里面只有一个方法HandlerDate(HttpURLConnection c),可以让调用者回调利用返回的HttpURLConnection自行处理返回的结果。

回到这个需求,首次进入我们肯定没有数据,所以我们要向服务端请求数据,服务端返回的一大段json,正常来讲为服务器返回的为 该数据集合的实体类的list集合的json。这里就产生了两个问题:1、要不要使用实体类封装数据。2、数据量庞大时,内存不足怎么解决。我自己思考的答案是:要用实体类,封装简单,在adapter适配器里适配数据时也更容易,数据量庞大时,使用化整体为部分的思想,要么向服务器请求部分数据,类似网页的分页。要么将数据存储在本地进行处理。在这个请求里,往极限了想,如果服务端返回10000条数据需要我们显示,存储在本地没必要,我们显示的也就那么点,所以第一让服务器返回显示的数据总数,我们根据数据总数,将数据分割成单次显示的数量,或者传给服务器两个参数,页数page,每页显示的数量pagesize,让服务器自己返回数据集合,我们再添加一个“加载更多”的控件,让page变化就可以了。解析json,网上一大堆成熟的框架,也是分分钟的事。剩下的就是发起请求的问题。值得注意的是,Android并不允许我们在UI线程中去访问网络,所以使用异步的 AsyncTask就是板上钉钉的事了。传好参数,数据成功通过回调函数获得。

解决了获取数据的问题,接下来就是如何填充数据的问题了,即ListViewListAdapter如何写。首先,在 字符串类型的填充很容易,但麻烦的是填充图片。我们需要解决图片下载,缓存,oom问题,自适应问题,乱序问题,滑动闪烁问题。问题一个一个来。

ListAdapter最重要的方法getView()重写过程中,很容易获得传过来的数据源的实体类对象。值得注意的是,在数据源的json中,图片并没有在实体类中完全解析成相应的Bitmap对象或drawable对象,当然如果项目需求需要,我们也可以实现,但是对于不知道什么时候使用实体类,让实体类去保存维护一堆bitmap对象,这个代码就不是那么优雅了。我的做法是保存的是路径或图片的名称,使用时根据其路径或名称再通过网络或本地文件或数据库解析成Bitmap对象。在加载的Adapter的布局文件中,控件的实例能找到并通过实体类进行封装,但是到ImageView这里就有点特殊了。因为填充网络图片就会遇到上面所说的问题。

首先,解决乱序问题。为ImageView.setTag(url)设置独有的Tag属性。在Adapter里维护一个当前适配的ListView引用,每次填充图片时,调用ListView.findViewWithTag(TagName)找到填充指定的ImageView.问题解决。

缓存问题。缓存问题是为了辅助oom问题引入的。这个需求采用LruCache来管理图片缓存。最大缓存设为最大可用内存的1/8

自适应问题。在这个需求中,要求图片的宽刚好能放满整个手机设备的屏幕宽,高度自定。而我们向服务器请求的图片url可能宽度无法填满或溢出,所以我们要根据屏幕的宽进行缩放。为此定义了HelpUntil.zoom(Bitmap mBitmap, int width, int height)将指定的Bitmap按指定的寛高进行缩放。问题解决。这里其实也可以把这个过程放到服务端处理,给服务端发送所需图片的寛高,让服务端为我们处理好,也可以。

滑动闪烁问题:滑动闪烁的问题是出在了ListView的滑动事件里。当ListView里滑动时,后台图片仍然在下载,导致各种跳跃,闪烁。所以在滑动时我们应该控制其ListView的滑动事件,当滑动时,停止下载,仅去下载当前可见范围的ImageView.即下载图片的调用放置在ListView的滑动事件上。所以在Adpater里暴露了cancelAllTasks()取消所有下载任务的方法与读取可见图片源的方法loadBitmaps(int firstVisibleItem, int visibleItemCount)。问题解决。

图片获取:图片获取的地方有两个:一个为本地缓存,即LruCache,另一个为网络请求了。总是先在缓存查询是否有已经下载好的图,有则显示,没有再去下载。这里的下载是典型的多线程下载。故使用了异步类BitmapWorkerTask继承AsyncTask解决单个图片下载问题。private Set<BitmapWorkerTask> taskCollection维护所有的下载任务。重要的是BitmapWorkerTask里如何下载。很好,这里就运用到了之前封装的NetHelp的方法了。在BitmapWorkerTask内部中调用复写doInBackground,封装好请求,BitmapWorkerTask实现IDate接口,将自身传给NetHelp的sendRequestWithHttpConnect(String request,int Method, IDate i)doInBackground就完成了。无论是对将数据流解析成Bitmap对象,还是将Bitmap放入缓存,缩放等等都在HandlerDate()方法里解决了。当然处理完下载图片的问题,还要在UI线程更新数据。那么就在onPostExecute(Bitmap bitmap)通过Tag找到相应的ImageView控件,将下载好的图片显示出来。在taskCollection移除任务就可以了。到这里,需求就完整实现了。

最后一个问题oom问题:避免加载大对象,不要将高清大图直接加载到内存中去,只保存图片尺寸大小,不保存图片到内存。同时记得调用Bitmap 的recycle()方法通知清理图片资源。

另外一种思路:使用Volley框架的 ImageLoader 和 NetworkImageView也能实现需求。


在项目中偶然得知的知识点

  1. xml属性设置时 背景色设为透明的值为 @null
  2. paint.setAntiAlias(true); // 设置抗锯齿,也即是边缘做平滑处理
  3. cMatrix.setScale (rScale, gScale, bScale, aScale);通过设置颜色矩阵的3原色的比例来实现颜色的变化。>>>>>这里引申出改变图像颜色还有哪些方法?
  4. 代码设置颜色值的有效性问题。
  5. 理解了构建Fragment的参数containerViewId 的具体意思。
  6. 图片平铺
  7. setCompoundDrawablesWithIntrinsicBounds的应用
  8. HttpClient 与 Android HttpURLconnect 的区别。
  9. url 传参时的中文乱码的解决
  10. 使用post传参时不能在获得状态吗之后再对request写入参数
  11. BitmapFactory.Options 的具体应用环境

Android手表商场项目总结相关推荐

  1. Android Studio创建项目

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u010046908/article/details/47000873 创建项目 首先,先指出Andr ...

  2. 140款Android开源优秀项目源码

    140款Android开源优秀项目源码 BeautifulRefreshLayout-漂亮的美食下拉刷新 https://github.com/android-cjj/BeautifulRefresh ...

  3. 2015年十大热门Android开源新项目

    2015即将结束,又到了大家喜闻乐见的年终盘点时刻啦,今天给大家盘点一下2015年Android开发领域新出现的10大热门开源项目.数据来自于GitHub搜索,创建时间自2015年1月1日开始的新项目 ...

  4. Android 金融类项目模块化架构

    一.前言 在以往的开发中,我们通常会使用MVC的模式进行开发,这样导致了Activity处理的逻辑非常的复杂,而且耦合度非常高,代码结构混乱.层次不清,各业务技术方案不统一,冗余代码充斥项目的各个角落 ...

  5. 2018.11月Android优质开源项目

    2019独角兽企业重金招聘Python工程师标准>>> 2018.11月Android优质开源项目 转载于:https://my.oschina.net/coderminer/blo ...

  6. 安卓(android)建立项目时失败,出现Android Manifest.xml file missing几种解决方法?...

    安卓(android)建立项目时失败,出现AndroidManifest.xml file missing几种解决方法? Eclipse新建项目,遇到这样的问题,注意如下: 1.文件名最好不要用中文. ...

  7. android 实训的背景,Android实训项目作业.doc

    Android实训项目作业 2-1用整型数计算两个数的和2 2-7排列任意4个数的顺序,按从小到大顺序输出2 2.1编写显示下列图形的程序.2 3.1编写程序,当点击按钮命令后,页面标题及文本组件的文 ...

  8. Android Studio下项目构建的Gradle配置及打包应用变体

    Gradle简介   Gradle是一个自动化构建工具,采用Groovy的Domain Specific Language(领域特定语言)来描述和控制构建逻辑.具有语法简洁.可读性强.配置灵活等特点. ...

  9. android umeng,GitHub - umeng/umeng_community_android: 友盟微社区Android SDK开源项目

    友盟微社区 Android SDK 该项目是友盟微社区的开源部分代码,根目录下的工程为集成友盟微社区SDK的demo,umeng_comm_android_ui为友盟微社区开源UI代码,里面包含了友盟 ...

  10. Android开源工具项目集合

    最近因为要去外派了,工欲善其事,必先利其器!所以又回顾了一下自己github上所收藏的项目,也算是温故而知新吧. 最流行的Android组件大全  http://www.open-open.com/l ...

最新文章

  1. springboot学习笔记一(从maven项目到springboot)
  2. boost::mpl模块实现partition相关的测试程序
  3. 【后缀数组】【poj2774】【 Long Long Message】
  4. 字段 新增hive_Hive分区表 | 每日五分钟学大数据
  5. 开局崩盘!IDEA 2020 无法启动的解决办法|赠送 IDEA 2020 新功能
  6. 通俗易懂的随机森林模型讲解
  7. 广告公司管理软件介绍
  8. TVDI中线性拟合干湿边的步骤
  9. 《疯狂java讲义》学习(19):枚举类
  10. swoole开发多人在线游戏新手教程
  11. 浪潮服务器键盘自动输空格,浪潮推出自主车载加固1U服务器填补国内该领域空白...
  12. centos 安装python36 pip19.1 python虚拟环境
  13. django+vue+nginx+frp搭建漫画网站之接入谷歌统计和百度统计(三)
  14. 【偶爱宋词】章良能·小重山
  15. 计算机与网络科学在化学信息学中的作用,化学信息学之科技文献检索.doc
  16. 教你用代码实现一个网页老虎机游戏
  17. 初识Python之刨根问底
  18. 2017.1.12——寒假集训第一天
  19. instagram搜索_如何使用jQuery和PHP构建自己的Instagram搜索引擎
  20. 全网最全python爬虫+数据分析资源整理

热门文章

  1. LIME-AI可解释模型:《“Why Should I Trust You?” Explaining the Predictions of Any Classifier》论文笔记
  2. 《雍正皇帝·九王夺嫡》生态文化专有词泰译研究(第一章)
  3. siri 语义识别_如何查看使用Siri识别的歌曲列表
  4. P2P模式文件传输网络应用的开发
  5. 多个分析视角的数据多维分析图表该如何制作?
  6. Html中 发光字体 的CSS属性
  7. NES模拟器源码阅读
  8. php ios表情包,[iOS] 自定义表情包
  9. 喇叭POP爆破音产生的原因与解决办法
  10. 网络神采 网站数据采集软件