安卓项目开发总结

安卓项目开发总结

1、网络请求

  1. 线程+Handlerjava

    • 使用线程池提升应用性能。
  • AsyncTask
  • xUtilsandroid

    • 接口回调。封装网络请求,在子线程中执行,根据响应码判断结果,经过Handler调用接口的方法,完成对不一样状态的不一样操做。
  • 使用GSON,将JSON字符串转换为JavaBean对象。数据库

备注:HttpClient在Android 6.0中已被移除,可是HttpUrlConnection仍然可使用。canvas

2、数据缓存

  1. 普通数据的缓存缓存

    • 首先判断本地是否有缓存数据,若是有,先显示本地数据,若是没有直接访问网络获取最新数据并保存时间戳。
    • 本地有缓存数据并显示完毕后,携带本地数据对应的时间戳访问服务器,判断当前数据是否为最新数据。
    • 若是是最新数据,再也不执行任何操做。
    • 若是不是最新数据,请求服务器返回最新数据和对应的时间戳,缓存到本地文件或者数据库中,并进行显示。
  • 图片的缓存

3、断点下载/上传

  1. 断点下载性能优化

    • 经过设置range请求头,请求服务器要获取文件的字节范围,去下载指定数据段的文件。
    • 经过DownloadTask执行下载任务,在下载过程当中,每写一段文件数据就将已写文件数据大小保存至文件或数据库,以便下次开始下载的时候用于指定range的范围。
    • 经过Handler去更新UI界面,若是有多个任务同时进行下载,分别为每个DownloadTask设置DownloadListener。
    • 为了不ListView不一样item显示错误的下载进度,使用ViewHolder对ListView进行优化处理。
  • 断点上传服务器

    • 该功能须要服务器支持才能够进行。

4、业务逻辑

  1. 封装JavaBean,页面展现,友盟SDK,百度地图,支付集成等
  2. 数据存储(sp存储,文件存储,数据库和网络存储)
  3. Service:开启线程,和服务器保持链接,接收服务器推送消息
  4. BroadcaseReceiver:网络

    • 注册经常使用广播事件,判断本身服务是否在运行,若是服务没有运行,开启服务,能够作到服务长时间在后台保持运行。
    • 广播也能够做为四大组件间通讯的工具

5、页面层

  1. Activity框架

    • 抽取BaseActivity,重写onCreate方法,依次执行initView,initData,initEvent,封装访问网络的操做,在回调结果里执行子类Activity的操做,须要子类提供的数据可使用抽象方法让子类去实现或者暴露方法给子类,让子类去覆写该方法。
    • 用集合记录已经打开/关闭的Activity,方便在任何Activity中执行退出应用的操做,退出后还须要调用killProcess(pid),杀死进程。
    • 封装startAnActivity方法,在BaseActivity中使用一个静态变量记录当前应用的Activity是否在栈中的最顶层,若是在,直接开启Activity,若是不在,新建一个任务栈开启Activity。
  • Fragment异步

    • show/hide:执行效率高,可是会占用内存
    • replace:执行效率低,可是内存占用少
  • 经常使用控件

  • ListView:优化,局部刷新的重点是,找到要更新的那项的View,而后再根据业务逻辑更新数据便可。重写updateItem方法,更新界面后,对应的数据也要更新,不然下次再滚动到该View的时候可能又还原了。
private void updateItem(int index) {
    int visiblePosition = listView.getFirstVisiblePosition();
    if (index - visiblePosition >= 0) {
        //获得要更新的item的view
        View view = listView.getChildAt(index - visiblePosition);
 
        // 更新界面(示例参考)
        // TextView nameView = ViewLess.$(view, R.id.name);
        // nameView.setText("update " + index);
        // 更新列表数据(示例参考)
        // list.get(index).setName("Update " + index);
    }
}
  • ViewPager:使用动画就使用JazzyViewPager
  • LinearLayout
  • RelativeLayout
  • FrameLayout
  • PercentLayout
  1. 自定义控件:能够拖动的GrideView
  2. 屏幕适配:dp和px的相互转换,使用百分比布局
  3. 动画
    1. 属性动画(会改变控件的真实位置,功能强大,代码复杂)
    2. 补间动画(不会改变控件的真实位置,包含4种)
      1. 位移动画
      2. 旋转动画
      3. 透明度
      4. 缩放动画
      5. 组合动画(以上4中动画能够组合为一个动画)
    3. 帧动画(图片的切换)

6、优化

  1. 布局优化
    1. include:布局重用
    2. merge:减小视图层级,例如你的主布局文件是垂直布局,引入了一个垂直布局的include,这是若是include布局使用的LinearLayout就没意义了,使用的话反而减慢你的UI表现。这时可使用 标签优化。
    3. ViewStub:须要时记载,使用该标签并不会影响UI初始化时的性能。当调用inflate()函数的时候,ViewStub被引用的资源替代,而且返回引用的view。
    4. 注:ViewStub目前有个缺陷就是还不支持 标签。
    5. 经过代码增长或删除View(addView/removeView)
  2. 代码优化
    1. 使用注解框架,ButterKnife,Dagger2,xUtils3,lint代码分析
  3. 内存/性能优化
    1. oom内存溢出,多是由内存泄露致使,经过mat插件进行分析
  4. 电量优化
  5. WebView,HTML5,Android新特性

7、自定义控件

  1. 建立自定义控件
    1. 继承View/ViewGroup/已有控件(包括布局控件)
    2. 在3个构造方法中,从参数少的到参数多的,依次调用,能够实现传入一个上下文,就能返回一个带有默认效果的控件,这也是第三个参数的做用。
  2. 自定义控件执行的流程
    1. onMeasure:测量,RatioFrameLayout可让图片按照比例显示的布局
      1. 两个参数:widthMeasureSpec/heightMeasureSpec
      2. 每一个参数分别表明宽度的测量规格和高度的测量规格,值为一个32位的二进制数,前两位表明测量模式,后三十位表明测量值。
      3. 能够经过MeasureSpec.getMode得到测量模式
      4. 能够经过MeasureSpec.getSize得到测量值
      5. 该方法是在当前View的measure方法中调用,因为不能重写measure方法,只能重写onMeasure方法对控件进行测量
    2. onLayout:布局,自定义流水布局FlowLayout
      1. 该方法是经过当前View的layout方法中调用,一样,须要重写onLayout完成对子控件的布局
      2. 因为View没有子控件,因此该方法只针对ViewGroup
    3. onDraw:绘制,快速索引控件
      1. 在该方法中能够完成对控件的绘制,须要用到canvas和paint
      2. 不要在该方法中new对象,不然可能形成GC回收不及时致使内存溢出或者GC时致使界面卡顿
  3. 自定义控件的事件处理
    1. onTouchEvent(返回值)
      1. 调用invalidate对控件进行重绘
      2. 返回true,消费事件
      3. 返回false,执行父View的
    2. dispatchTouchEvent:是否分发
      1. 返回true,不分发,事件直接返回不处理
      2. 返回false,分发,
        1. 若是子View是ViewGroup,执行onInterceptTouchEvent判断是否对事件进行拦截
        2. 若是子View是View,执行onTouchEvent判断是否对事件进行处理
    3. onInterceptTouchEvent(ViewGroup才有)
      1. 返回true,对事件进行拦截,直接返回不处理
      2. 返回false,不进行拦截,调用子View的dispatchTouchEvent
    4. requestDisallowInterceptTouchEvent
      1. 子View告诉父容器,不要拦截本身的事件
  4. 经过回调,返回自定义控件的当前状态
    1. 定义控件的全部状态
    2. 定义回调接口和回调方法(参数)
    3. 设置成员变量(setXXXListener)
    4. 在适当的位置调用回调方法
    5. 外部在回调方法中执行自定义的任务
  5. 自定义控件的动画
    1. 帧动画
    2. 补间动画
    3. 属性动画(性能比补间动画低)
      1. 插值器(Interpolator)
      2. 估值器(TypeEvaluator)
      3. ValueAnimator(是属性动画的核心类)
      4. 参考文档:Android动画学习
  6. ViewDragHelper,滑动删除控件,nineoldandroid.jar(在低版本2.3上执行属性动画仍然不会改变控件的真实位置,因此低版本的Android系统不支持属性动画)

8、图片缓存

连接:Android官方培训课程

  1. 不能致使应用崩溃(OOM),须要进行压缩处理
    1. 使用xUtils中的BitmapDisplayConfig中的optimizeMaxSizeByView方法对图片进行压缩
  2. 不能致使卡顿,须要进行异步加载(使用Thread或者AsyncTask)
  3. 不能显示错位,由于快速滑动的时候对图片进行异步加载,因为ListView中item的复用可能会致使图片的错位显示,对ListView/GridView中的item设置tag,异步记载完成后对tag进行判断,若是tag相同才进行显示。
  4. 加载要快,对已加载的图片进行缓存
    1. 内存缓存(LruCache),LruCache的本质是使用LinkedHashMap集合,该集合会根据使用的状况,按照使用频率进行排序,立即将超出内存大小时,将使用频率最低的图片进行移除。
    2. 磁盘缓存
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

// Use 1/8th of the available memory for this memory cache.
final int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
    @Override
    protected int sizeOf(String key, Bitmap bitmap) {
        // The cache size will be measured in kilobytes rather than
        // number of items.
        return bitmap.getByteCount() / 1024;
    }
};

9、Handler

  1. 为何要有Handler?
    1. 主线程不能作耗时操做,须要放在子线程中执行
    2. 子线程不能更新UI,只有主线程才能更新UI,因此须要使用Handler对子线程和主线程之间进行通讯
  2. 使用步骤
    1. new Handler(),该操做只能在主线程中执行
    2. 重写handleMessage方法
    3. 在子线程中发送消息sendMessage
    4. post能够延时发送消息
    5. 发送的消息可使用Message.obtain()方式获取
  3. 消息队列MessageQueue
    1. Looper.prepare
    2. Looper.loop
  4. 全部的界面操做都依赖于Handler机制
  5. 子线程只须要调用Looper.prepare和Looper.loop,就能够在这两行代码之间使用WindowManager修改UI
  6. 主线程也不能修改子线程建立的UI
  7. Handler是线程间通讯的工具
相关文章
相关标签/搜索