一些代码经验分享
代码编写
1.用kotlin写事件回调时,可以采用Lambda表达式简化,如:
view.bt_apply.setOnClickListener { viewModel.onApplyClick() }
2.打印项目依赖
/gradlew :项目名称:dependencies > 要保存的文件.txt
举例 : ./gradlew :biz-aer:dependencies > 1depen.txt
3.使用fastJson解析kotlin对象,容易失败,建议转化为Java对象
4.软件版本区分
● alpha版:内部测试版。α是希腊字母的第一个,表示最早的版本,一般用户不要下载这个版本,这个版本包含很多BUG,功能也不全,主要是给开发人员和 测试人员测试和找BUG用的。
● beta版:公开测试版。β是希腊字母的第二个,顾名思义,这个版本比alpha版发布得晚一些,主要是给“部落”用户和忠实用户测试用的,该版本任然存 在很多BUG,但是相对alpha版要稳定一些。这个阶段版本的软件还会不断增加新功能。如果你是发烧友,可以下载这个版本。
● rc版:Release Candidate(候选版本),该版本又较beta版更进一步了,该版本功能不再增加,和最终发布版功能一样。这个版本有点像最终发行版之前的一个类似 预览版,这个的发布就标明离最终发行版不远了。作为普通用户,如果你很急着用这个软件的话,也可以下载这个版本。
● stable版:稳定版。在开源软件中,都有stable版,这个就是开源软件的最终发行版,用户可以放心大胆的用了。
5.触摸点位置计算
event.getX():表示的是触摸的点距离自身左边界的距离
event.getRawX:表示的是触摸点距离屏幕左边界的距离
6.AdapterView中 setTag,getTag是为了方便 ViewHolder 复用。
ItemView的 setTag不能用作状态的保持,比如是否 textView展开,应该修改 List数据,以数据驱动UI。因为 AdapterView复用 会导致状态混乱。
7.Fragment不能通过构造函数增加字段传参,需要通过getArguments 取参数。否则在系统恢复Fragment时容易crash
8.编译期间在 class -> dex之间 可以添加Transform监听,来自定义插件修改字节码。
原来我们自定义的Transform,添加到了extension中,然后在打包阶段编译java->class之后,class->dex之前,遍历extension中的Transform(包括我们自定义的)然后添加到TransformManager 注册为 TransformTask,当执行Task时候,在调用Transform的transform方法,这样就达到了在dex之前修改字节码的目的
链接:https://juejin.cn/post/6974962797973078046
9.使用debug包开发完功能后,必须用release包重新验证功能。
举例: 猜价答题,题目未出现的bug
10.使用Handler要注意判空,同理,使用对象前要判空;尤其是在对象有可能被赋值为null时。
11.反编译
-
安装
brew install jadx -
启动方法:jadx-gui
-
选择打开指定的 apk
-
根据包名找到对应的源代码
12.PermissionX
现在,业内普遍比较认可使用另外一种小技巧来进行实现。是什么小技巧呢?回想一下,之前所有申请运行时权限的操作都是在 Activity 中进行的,事实上,Android 在 Fragment 中也提供了一份相同的 API,使得我们在 Fragment 中也能申请运行时权限。
但不同的是,Fragment 并不像 Activity 那样必须有界面,我们完全可以向 Activity 中添加一个隐藏的 Fragment,然后在这个隐藏的 Fragment 中对运行时权限的 API 进行封装。这是一种非常轻量级的做法,不用担心隐藏 Fragment 会对 Activity 的性能造成什么影响。
https://juejin.cn/post/6903709311906938893
https://github.com/guolindev/PermissionX
Bug Fix 总结
add view 时报错:java.lang.IllegalArgumentException: Cannot add a null child view to a ViewGroup
问题原因: 在执行addHighLightView时,未判断要添加的view是否为空。
解决方案: 在add view之前需要判断是否为空,不为空才可以添加。
总结:遇到报错可以查看源代码,找到问题所在
“Cannot add a null child view to a ViewGroup”
(http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/view/ViewGroup.java)
2.网络请求解析的Data数据,一定要序列化,不然被混淆后,导致解析失败问题。
3.新增接口请求,javaben映射时一定要注意 在混淆文件中查看,是否已防止混淆。
4.EditText setSelection方法调用注意保护,避免crash
5.AndroidStudio debug时可以设置变量值,模拟出现NullpointerException场景。
6.基类里定义了public String TAG实例变量,子类(Kotlin代码)用同名的静态常量companion object {
const val TAG = “xxx”
} ,会crash
异常信息: java.lang.IncompatibleClassChangeError: Expected ‘xx’ to be a instance field rather than a static field
注意:子类(Kotlin)代码,点击变量TAG,会跟踪进入到父类代码中
子类为 Java代码时,暂未发现有该异常。
Kotlin代码转Java后查看:
问题分析:
If a field that is not declared private was not declared static and is changed to be declared static, or vice versa, then a linkage error, specifically an IncompatibleClassChangeError, will result if the field is used by a pre-existing binary which expected a field of the other kind. Such changes are not recommended in code that has been widely distributed.
翻译:
如果一个未被声明为私有的字段没有被声明为静态的,并且被改变为被声明为静态的,或者反之亦然,那么如果该字段被一个预先存在的二进制文件使用,而该二进制文件期待的是另一种类型的字段,则会导致一个链接错误,特别是IncompatibleClassChangeError。在广泛分发的代码中不建议进行此类更改。
UI 特性积累
1.Dialog:
自定义Dialog,继承Dialog, https://www.jianshu.com/p/809623bbc3b6
自定义DialogFragment, https://blog.csdn.net/u011272795/article/details/102822028
2.FrameLayout,RelativeLayout,LinearLayout都可以实现view的层叠效果
RelativeLayout: 通过 alignBottom, alignTop, alignParentLeft等
LinearLayout:通过marginTop="-12dp"等
3.RemoteImageView设置圆角:
方式一:
RemoteImageView imageView = (RemoteImageView) view.findViewById(R.id.iv_photo);
// 设置banner图片的边缘为圆角, radius 为 8 imageView.setPainterImageShapeType(PainterShapeType.ROUND_CORNER);
imageView.cornerRadius(AndroidUtil.dp2px(viewGroup.getContext(), 8));
imageView.load(banner.imageUrl);
方式二:
<androidx.cardview.widget.CardView
android:id=“@+id/cv_img_container”
android:layout_width=“@dimen/space_80dp”
android:layout_height=“@dimen/space_80dp”
app:cardCornerRadius=“@dimen/space_8dp”
android:layout_below=“@id/view_divide”
android:layout_marginEnd=“@dimen/space_6dp”
app:cardElevation=“@dimen/space_0dp”>
<com.ugc.aaf.widget.widget.imageview.ForeExtendedRemoteImageView
android:id=“@+id/riv_product”
android:layout_width=“@dimen/space_80dp”
android:layout_height=“@dimen/space_80dp”
app:imageScaleType=“centerCrop”
app:imgRadioH=“1”
app:imgRadioW=“1” />
</androidx.cardview.widget.CardView>
4.TextView字体大小自适应
android:autoSizeMaxTextSize=“12sp”
android:autoSizeMinTextSize=“4sp”
android:autoSizeTextType=“uniform”
5.SpannableStringBuilder连续调用setSpan时参数Object what不能使用同一个引用
否则只有最后一个设置有效
https://blog.csdn.net/BigBoySunshine/article/details/48706451
6.新建iconFont图标库
- 去iconFont网站下载需要使用的icon ttf文件。https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=3494273&keyword=&project_type=&page=
- ugc_iconfont.ttf文件放在 res/font 文件夹下
- 在 style.xml 文件下
增加 style
4.使用
<androidx.appcompat.widget.AppCompatTextView
style=“@style/UGCIconFont”
android:text=“@string/icAdd”
android:textColor=“@color/gray_cccccc”
android:textSize=“20sp”
android:layout_width=“@dimen/space_24dp”
android:layout_height=“@dimen/space_24dp”
android:layout_gravity=“center”
/>
7.设置状态栏为白色,Toolbar字体黑色背景色为白色
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar_actionbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:theme="@style/MMyorderLeaveFeedBackTitleTheme"
android:background="@color/white"
/>
<style name="MMyorderLeaveFeedBackTitleTheme" parent="@style/ThemeOverlay.AppCompat.Light">
<item name="colorPrimary">#FFFFFF</item>
<item name="colorPrimaryDark">#FFFFFF</item>
<item name="textColorPrimary">#000000</item>
<item name="colorControlNormal">#000000</item> <!-- 重要,控制左侧箭头为黑色>
</style>
<!-- navigation icon color -->
<item name="colorControlNormal">@color/my_color</item>
<!-- color of the menu overflow icon -->
<item name="android:textColorSecondary">@color/my_color</item
状态栏设置为白色:
Activity onCreate setContentView后面执行
try {
StatusBarUtil.setTranslucentForImageView(this, 0, findViewById(R.id.ll_content));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
StatusBarUtil.setColor(this, getColor(R.color.white), 0);
}
StatusBarUtil.setLightMode(this);
} catch (Throwable e) {
}