程序员自我救赎

记录程序员救赎之道

每周三晚的技术分享和每周末每人一篇的技术博客

产品层面

  1. 特效的运用要考虑用户的心理趋向和感受,炫的效果很酷,可能会让人产生某种心理导向。
  2. 特效的运用要考虑将来功能的扩展,一味的渲染也不一定很好,可能会为后续功能带来难度。
  3. 一个产品能帮助用户解决至少一个问题,那解决问题会有主流程,引导要强化,比如按钮大,颜色显眼,字体稍大,放置位置移动少。
  4. 产品不能为照顾运营而偏离主题,或者严重影响美观和主要功能,聚划算妹纸儿们说广告banner曝光度不够,设计变为由轮转变为平铺,但是广告良莠不齐,视觉效果不好,并且主页list仅能显示1、2个商品,影响了主题功能。

 

代码方面

代码需要审核,程序的代码需要共同学习,完善代码  

项目方面

  1. 计划进度,前紧后慢,提前实施。
  2. 不拘泥与细节,不干扰整体进度。
  3. 个人有担当,能者多劳,最大程度保证进度。
  4. 有问题不能包着,有些项目问题不是一个人的问题,不是一人能担得住的。
  5. 宝不能压在责任无关人身上,别人的资源、承诺要充分利用,但是最终还是靠自己突破。
  6. 干一样活的人放在一起,沟通迅速,快速解决问题。
  7. 早上碰一下,清晰任务;晚上碰一下一下,检查进度。
  8. bug先把基础性、功能性问题解决,适配、显示、兼容问题靠后。
  9. 不同网络机型下的跑测,不同网络环境下的测试提前入测。
  10. 写完一天代码,尽量坚持用findbugs查找潜在危险。
  11. 同一版本多次发布,或多个版本发布后,记录下的crash问题如果没有版本属性就很难定位,混淆map也对应不上。发板后立即封代码,保证bug日志中的bug发生行数和源码一致。
  12. 开发新功能、打包、发布过程规范化,规范减少问题发生概率。
  13. 日志规范:
            1). 冗长、惯例日志打到Verbose级别,例如网络返回信息,经常携带大量的信息,会严                                    重干扰视觉;
            2). 细粒度信息打到Debug级别,对出问题时调试有帮助作用,比如某个参数的值,我并    不总想知道是多少,但某些情况我就得看一下;
            3). 粗粒度级别信息打到Info级别,比如应用业务主逻辑,运行中重要的过程或关键点;
            4). 会出现 潜在错误的信息 或者 可以接受的错误 打到Warn级别,比如某个地方我想警告一下说这里是有问题的,或者可能引出其他什么问题;
            5). 错误或者致命信息,理应放到Error级别,血红的颜色很显眼~

 

管理方面

  1. 会议总结问题,就一定要着手解决,不解决会议时间就白浪费了。
  2. 对于人的期望,快速的给予回馈,帮助其向希望的方向发展。

1
2
3
4
5
6
7
8
9
android{
...
defaultConfig {
...
ndk {
abiFilters 'armeabi', 'x86'//, 'armeabi-v7a', 'x86_64', 'arm64-v8a', mips, mips64...加入需要生成的文件夹
}

}

如果不添加此处ndk的选项描述,那么androidstudio默认打包会产生所有的平台so文件包,如果没有相应的so文件那么就会导致程序报错:找不到so文件在某个目录下。因此我们需要根据现有的什么类型的so文件进行配置ndk。

  • 通常我们都会有armeabi和x86平台的so文件,这两个都是为32位的平台提供。有这两个就满足的几乎全部的机型了
  • armeabi-v7a,arm64-v8a都是arm平台的更优化的平台,使用这个so文件效率更高,如果有这种的so文件那么就添加响应的配置。
  • 手机优先选择平台更好的处理平台的so文件,因此没有高版本的so文件就不要添加配置。

####如何把库发布到JCenter

1、首先去注册https://bintray.com
2、

1
2
3
4
5
6
7
8
9
10
11
12
13
 classpath 'com.novoda:bintray-release:0.3.4'

如果遇到错误添加
allprojects {
repositories {
jcenter()
}
tasks.withType(Javadoc) {
options.addStringOption('Xdoclint:none', '-quiet')
options.addStringOption('encoding', 'UTF-8')
}
}

3、库的build

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apply plugin: 'com.novoda.bintray-release'//添加
android {
lintOptions {
abortOnError false
}
}

publish {
userOrg = 'limxing'//bintray.com用户名
groupId = 'me.leefeng'//jcenter上的路径
artifactId = 'library'//项目名称
publishVersion = '1.0.2'//版本号
desc = '我的个人库,更改动画'//描述,不重要
website = 'https://github.com/limxing/app'//网站,不重要;尽量模拟github上的地址,例如我这样的;当然你有地址最好了
}

在最近的项目中,使用了ViewPager+ImageView进行图片的浏览,OOM的代码:

1
2
3
4
5
6
7
@Override
public Object instantiateItem(ViewGroup container, int position) {
Work.Att att = list.get(position);
PhotoView view = new PhotoView(container.getContext());
container.addView(view);
return view;
}

这样会重复的创建ImageView,可能没有被回收,所以解决的方案是创建一个全局的集合,让图片都放进去,在使用的时候根据位置进行设置不同的图片去展示

1
2
3
4
5
6
7
@Override
public Object instantiateItem(ViewGroup container, int position) {
Work.Att att = list.get(position);
PhotoView view = Application.getImageList().get(position);
container.addView(view);
return view;
}

####关键

但是这样同样会让Viewpager指针指向了这个集合中的ImageView,因此在onDestory中添加:viewpager.removeAllViews();

在使用RecyclerView过程中使用 notifyItemInserted notifyItemRangeRemoved等
方法时,还要调用notifyItemRangeChanged(position,list.size());

1
2
3
4
5
list.add(0, "leefeng.me" + "==onRefresh");
recycleview.stopRefresh(b);
adapter.notifyItemInserted(0);
adapter.notifyItemRangeChanged(0,list.size());

在使用RadioButton的时候在选择图片切换的时候出现的一个问题:

1
2
<item android:drawable="@drawable/my_on" android:state_checked="true" />
<item android:drawable="@drawable/my_off" />

不能添加state_pressed的状态,否则就出现了不能够正常切换DrawableTop图片

Android ViewPager左右滑动取消的方法是重写子View
实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (getScrollX()<0) {
LogUtils.w("WifiCustomWebView---> getScrollX <= 0");
getParent().requestDisallowInterceptTouchEvent(false);
return false;
} else if (getScrollX() >= computeHorizontalScrollRange()) { //- getWidth()
LogUtils.w("WifiCustomWebView---> getScrollX >= computeHorizontalScrollRange()");
return false;
} else {
LogUtils.w(computeHorizontalScrollRange()+"--"+getScrollX()+"=="+"WifiCustomWebView---> true");
getParent().requestDisallowInterceptTouchEvent(true); //子view中,可以中断pager获取到事件
return true;
}
// return super.onInterceptTouchEvent(ev);
}

一年多前就出现来这个技术,但是也没有怎么去了解和使用,一直以为EventBus和广播类似呢,后来才发现,EventBus更好用,类型更明确,发送的消息可以是任何自定义的对象,因此写个简单的使用,以免忘记

Github项目框架的地址:https://github.com/greenrobot/EventBus

使用步骤:

一、创建消息类(实体),用于存放消息的内容,例如:

1
2
3
4
5
6
7
8
9
10
class EventMessage{
String messge;
public void setMessge(String message){
this.message=message;
}
public String getMessage(){
return message;
}

}

二、注册消息:

EventBus.getDefault().register(this);

三、接受消息:

1
2
3
4
5
@Subscribe(threadMode = ThreadMode.MAIN)
public void showEventBuss(EventMessage event) {
String msg = "收到了消息:" + event.getMessage();
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
}

其中方法名无所谓,内部运用了反射的机制,获取到方法名,进行的调用,ThreadMode有四种:
/**

  • Subscriber will be called in the same thread, which is posting the event. This is the default. Event delivery
  • implies the least overhead because it avoids thread switching completely. Thus this is the recommended mode for
  • simple tasks that are known to complete is a very short time without requiring the main thread. Event handlers
  • using this mode must return quickly to avoid blocking the posting thread, which may be the main thread.
    */
    POSTING,

/**

  • Subscriber will be called in Android’s main thread (sometimes referred to as UI thread). If the posting thread is
  • the main thread, event handler methods will be called directly. Event handlers using this mode must return
  • quickly to avoid blocking the main thread.
    */
    MAIN,在主线程中调用执行

/**

  • Subscriber will be called in a background thread. If posting thread is not the main thread, event handler methods
  • will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single
  • background thread, that will deliver all its events sequentially. Event handlers using this mode should try to
  • return quickly to avoid blocking the background thread.
    */
    BACKGROUND,在子线程中执行

/**

  • Event handler methods are called in a separate thread. This is always independent from the posting thread and the
  • main thread. Posting events never wait for event handler methods using this mode. Event handler methods should
  • use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number
  • of long running asynchronous handler methods at the same time to limit the number of concurrent threads. EventBus
  • uses a thread pool to efficiently reuse threads from completed asynchronous event handler notifications.
    */
    ASYNC

四、注销消息:

EventBus.getDefalt().unregister(this);

0%