2020.1-开发记录
这段时间一直在写项目,现在来整理一下这段时间开发中遇到的一些坑吧
Okhttp客户端保持session
很多时候我们使用http客户端都需要保持session,起初我以为okhttp应该会自动保存session,但是在实际使用过程中发现它并不会自动保存session,我们需要使用一个库来解决这个问题
在gradle的依赖中加入如下依赖1
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.2.0'
像这样使用它
1 | val cookieManager = CookieManager() |
这样编写代码就可以获得一个保存session的OkhttpClient了
补充
虽然这样可以保持session,但是在实际使用中依然存在不少问题,例如无法持久化
可以使用下面的方案来解决该问题
先要加入以下源1
maven { url "https://jitpack.io" }
1 | implementation 'com.github.franmontiel:PersistentCookieJar:v1.0.1' |
这个库可以自动持久化cookie,只需要一个context参数即可
1 | var cookieJar: ClearableCookieJar = |
解析json返回格式
1 | implementation group: 'com.squareup.retrofit2', name: 'converter-gson', version: '2.4.0' |
在创建retrofit的时候使用.addConverterFactory(GsonConverterFactory.create())
即可
使状态栏透明
方法很简单,只需在onCreate中加入以下代码
1 | window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) |
或是在对应的style中加入
1 | <item name="android:windowTranslucentStatus">true</item> |
在style中更改theme属性之后,在Androidmanifest中为activity设置主题即可
其中
- 第一行代码可以让状态栏透明
- 第二行让虚拟导航栏透明(有返回 home 和最近任务按钮的那一栏)
- 第三行是5.0之前让状态栏透明的方法
- 如果出现显示错误可以尝试添加代码
1
<item name="android:fitsSystemWindows">true</item>
- 或手动更改布局文件来解决
隐藏ActionBar的另一种方法
现在很多方法都是直接将style
中的parent
改成NoActionBar,但是这样一来会有个问题,你重新创建一个style之后,如果你的主题颜色发生更改,则你必须要更改两个主题的颜色
可以通过继承原style解决这个问题
1 | <style name="AppTheme" parent="Theme.MaterialComponents.Light.DarkActionBar"> |
AppThemeNoActionBar
的parent为AppTheme,他的主题颜色与AppTheme的相同,所不同的是这个主题可以隐藏ActionBar
同样的,你也可以用这样的方法创建一个style来实现状态栏透明
实现一个提示内容会自动上移的EditText
效果
要实现这个效果很简单,只需要使用md库内的Text Fields
切换到某个Fragment里才在ActionBar显示菜单按钮
首先你需要在onCreateView里加入以下代码
1 | setHasOptionsMenu(true) // 调用这个才会显示菜单 |
然后重写方法
1 | override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { |
这里注意一下,这个方法与activity的有点不同,除了这个地方以外其他的都和activity的一样
使用VierPager和TabLayout快速实现侧滑切换fragment
或许有更简单的方法
首先写一个Adapter,继承androidx.fragment.app.FragmentPagerAdapter
并实现抽象方法
1 |
|
只需要创建一个Adapter实例并使用setupWithViewPager即可
1 |
|
其中fragment_community_viewPager
是用于显示fragment的ViewPager对象,fragment是一个存储Fragment实例的类
activity!!.supportFragmentManager
是一个supportFragmentManager
对象,这里是在fragment内使用,使用时需要灵活替换
一个好用的http客户端-Retrofit
不解释了,翻文档吧
贴个官方示例给大家看看这库有多好用
1 | public interface GitHubService { |
之后你就可以发送http请求了
1 | Retrofit retrofit = new Retrofit.Builder() |
如果返回内容是json格式,你甚至可以直接让库帮你解析为对象,只需要在Retrofit.Builder()时加入以下代码
1 | .addConverterFactory(GsonConverterFactory.create()) |
不过你需要一个依赖
1 | implementation group: 'com.squareup.retrofit2', name: 'converter-gson', version: '2.4.0' |
快速将tensorflow lite导入到你的项目中
获取相机图像信息
参考文章的方法大致还是没有什么问题的,只是使用camerax库的时候使用的是旧版,新版的创建Analysis方法
1 | def camerax_version = '1.0.0-alpha06' |
1 | val executor = Executors.newSingleThreadExecutor() |
不过说不定哪一天可能又改了呢
导入并运行模型
可以使用最新的稳定版tflite
1 | implementation group: 'org.tensorflow', name: 'tensorflow-lite', version: '2.1.0' |
在构建Interpreter的时候有细微不同
1 | val options = Interpreter.Options() |
快速使用深度学习实现移动端图片分类
keras内置了很多常用的模型,你可以使用这些模型快速构建你的应用
要训练自己的模型也很简单
所需依赖
1 | import os |
加载数据
以下是一个快速加载数据的代码段
1 | def generate(batch, shape, ptrain, pval): |
这段代码可以让你从文件夹加载图片并自动生成经过旋转,缩放的图片
数据集的文件夹格式应该是这样的
1 | -train |
构建模型
模型就使用mobilenetv2
1 | model = MobileNetV2(input_shape=shape, , classes=n_class) |
n_class
为分类的类别数量,weights=None
可以让你从头开始训练你自己的模型,shape
一般为(224,224,3),三个参数分别是图片长,宽,通道数(如果你的图片是黑白的就填入1)
优化器
1 | opt = Adam(lr=0.001) |
lr为学习速度,注意并不是越快越好,0.001即可
提前结束训练和可视化
1 | earlystop = EarlyStopping(monitor='val_acc', patience=5, verbose=0, mode='auto') |
编译模型
1 | model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy']) |
加载数据1
train_generator, validation_generator, count1, count2 = generate(batch, shape[:2], train_dir,eval_dir)
batch
是批次尺寸,具体请看链接
在获取了数据生成器之后我们还需要获取label列表,使用下面的函数来获取
1 | def save_labels(generator): |
将刚刚获取的生成器传入即可
训练模型
使用下面的代码来打印模型信息并开始训练
1 | model.summary() |
epochs
是训练次数,一次训练会把数据全部过一遍
保存模型
一句话,就这么简单
1 | model.save("model.h5") |
转换模型
使用tensorflow的转换工具来转换
1 | tflite_convert --output_file=litemodel.tflite --keras_model_file=model.h5 |
常见的模型都可以用这个方法来转换,但是部分模型似乎不行,本人也没找到好的方案