Android开发中遇到的问题记录
Ccixyj opened this issue · comments
1.Unresolved reference for synthetic view when layout is in library module (无效)
父模块使用子模块的布局,kotlin-android-extensions 是不能直接使用。
//配置文件添加如下:
androidExtensions {
experimental = true
}
参考stackoverflow的问题
Kotlin Android Extensions
的高级用法可以查阅官方文档
现在没有真正的解决办法
KT-22430
2. ConstraintLayout
(1.1.x) 在 RecyclerView
中高度不正确的问题
在 ConstraintLayout
修改属性如下:
android:layout_height="wrap_content"
app:layout_constraintHeight_default="wrap"
app:layout_constrainedHeight="true"
主要是 app:layout_constraintHeight_default="wrap"
这条属性
参考:
3. canvas
drawtext()
方法的注意点
drawtext()
参数的 y
是一 文字的 baseline
为基准的。所以需要画文字背景时需要考虑 计算 fontMetrics
的 descent / ascent
参数.
3. webview
无法加载图片的问题
对于大家来讲WebView肯定很熟悉,因为我们在日常开发中经常用到它。所以对于它的一些基本用法我就不在这啰嗦了,直接进入正题。
我遇到的问题就是在使用WebView加载网页的时候图片不显示(我手机系统是5.1.1),当时出现这个问题我就想当然的以为,是不是给WebView少设置的什么东西。然后百度一下:
mWebview.getSettings().setJavaScriptEnabled(true);//启用js
mWebview.getSettings().setBlockNetworkImage(false);//解决图片不显示
然后我检查了自己代码,这两句话也明明加了啊,这到底是什么鬼。后面我也加过其它的一些设置,依然没有用。难道是我的访问路径有问题吗,于是我随便找了带图片的网页,使用WebView加载了一下,哎呦我擦,图片显示没毛病啊。看来还真是我的访问路径有问题啊,但是别的都显示没问题,为什么就图片不显示呢。我跟踪断点把访问的路径复制了出来一看,我靠原来访问路径是https的呀。于是我就把矛头指向了https,简单来说,https就是http的安全版,它在http的基础上加入了ssl层。https协议在使用的时候需要申请一个安全证书,我就想是不是安全证书有问题,回头一想假如安全证书有问题,页面应该是直接显示空白才对。问题又出在哪,于是我把网页路径复制到了浏览器打开,然后查看了一下网页源码,发现图片的引用是http的,问题会不会就出在这呢。果然不出所料:
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP){
settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
于是在设置WebView的时候加上了这句话,果然问题解决了。在5.0以下的系统即使不加这句话,图片也可以正常显示,亲测有效。
4. CoordinatorLayout > CollapsingToolbarLayout
中 需要全屏的处理
- xml 中不要出现
android:fitsSystemWindows="true|false"
- 使用
ImmersionBar
,并且 设置immersionBar.titleBar(mToolbar).init()
注意: 父类如统一初始化了
immersionBar
的话,则要添加immersionBar.reset()
或者复写父类的实现使得immersionBar
不要初始化
5. Webview
与 JS
交互 方式
使用JsPrompt方式拦截时** 需要记得调用
result?.confirm
或result?.cancel()
6. 比较好的屏幕适配
现在可以用as插件了,真tm高级!
另外一种思路(今日头条)
相关文章
7. fragment 中 toolbar 的问题
一个 Activity 中含有多个fragment,且每个fragment有toolbar。那么每个fragment的toolbar是不同的实例,但是activity.setSupportActionBar()
后,activity 的 actionbar 只能持有最后设置的 toolbar 实例。
解决方案:
- 当前fragment 显示时再次设置
activity.setSupportActionBar()
,比如在viewerpager
中。 - 去掉 fragment 中的
activity.setSupportActionBar()
,在各自的 fragment 完成各自的初始化,脱离与activity
的联系。
相关问题:
8.SwipeRefreshLayout 与 CoordinatorLayout 嵌套刷新
Appbar相关 AppBarStateChangeListener
:
public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener {
public enum State {
EXPANDED,
COLLAPSED,
IDLE
}
private State mCurrentState = State.IDLE;
@Override
public final void onOffsetChanged(AppBarLayout appBarLayout, int i) {
if (i == 0) {
if (mCurrentState != State.EXPANDED) {
onStateChanged(appBarLayout, State.EXPANDED);
}
mCurrentState = State.EXPANDED;
} else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) {
if (mCurrentState != State.COLLAPSED) {
onStateChanged(appBarLayout, State.COLLAPSED);
}
mCurrentState = State.COLLAPSED;
} else {
if (mCurrentState != State.IDLE) {
onStateChanged(appBarLayout, State.IDLE);
}
mCurrentState = State.IDLE;
}
}
public abstract void onStateChanged(AppBarLayout appBarLayout, State state);
}
9. Toolbar 中 标题居中
确保添加了下面的属性:
<android.support.v7.widget.Toolbar
<TextView
android:layout_width="wrap_content"
android:layout_gravity="center"
android:gravity="center" />
</android.support.v7.widget.Toolbar>
10. ViewPager
嵌套 HorizontalScrollView
的滚动处理
自定义 ViewPager
,重写 canScroll()
override fun canScroll(v: View, checkV: Boolean, dx: Int, x: Int, y: Int): Boolean {
return if (v is HorizontalScrollView) {
val child = v.getChildAt(0) ?: return super.canScroll(v, checkV, dx, x, y)
if (child.measuredWidth == v.scrollX + v.width - v.paddingLeft - v.paddingRight) {
super.canScroll(v, checkV, dx, x, y)
} else true
} else super.canScroll(v, checkV, dx, x, y)
}
其中,要注意 child.measuredWidth == v.scrollX + v.width - v.paddingLeft - v.paddingRight
是处理
滚到底部后触摸事件交还给 ViewPager
处理
11. ConstraintLayout 中 Group 的注意点
group.setGone
没问题。 但是 group.setInvisible
需要手动调用group.updatePreLayout(constraintLayout)
。
推测原因为 setInvisible
不会调用 updateLayout
。
12. Glide
的 Transformation
注意点
Glide
中 FitCenter
和 CenterCrop
都属于 Transformation<T>
类型。如果要添加自定义的 Transformation
时,都需要放入 Transform(vararg transforms)
中。
示例:
//glide 3.x , 4.x 类似
Glide.with(this).load(img)
.bitmapTransform( CenterCrop(viewContext), RoundedCornersTransformation(viewContext, 8, 0))
.into(imageview)
13. Webview
(h5)中 video 全屏播放
在使用 webview
,如何让 video
支持全屏呢?
- 首先在对应的
activity
标签中条件旋转的支持。
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
android:hardwareAccelerated="true"
android:screenOrientation="portrait"
同时 在对应布局中添加一个占位 view container
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<WebView
android:id="@+id/base_webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ProgressBar
android:id="@+id/mp_web_progress"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="@dimen/material_3dp"
android:background="@color/transparent"
android:max="100"
android:padding="0dp" />
<!--全屏占位的view container-->
<FrameLayout
android:id="@+id/fl_video"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
</FrameLayout>
- 确认添加了
WebSetting
相关配置
webSettings.loadWithOverviewMode = true
- 自定义的
WebChromeClient
中复写onShowCustomView(view: View?, callback: CustomViewCallback?)
和onHideCustomView()
方法
private var nVideoView: View? = null
private var customViewCallback: CustomViewCallback? = null
override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
super.onShowCustomView(view, callback)
super.onShowCustomView(view, callback)
if (nVideoView != null) {
callback?.onCustomViewHidden()
return
}
nVideoView = view
nVideoView?.visibility = View.VISIBLE
customViewCallback = callback
// 占位view容器添加nVideoView
fl_video?.addView(nVideoView)
fl_video?.visibility = View.VISIBLE
fl_video?.bringToFront()
//设置横屏
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
mToolbar.visibility = View.GONE
immersionBar.fullScreen(true).transparentStatusBar().statusBarDarkFont(false).init()
}
// 退出全屏调用此函数
override fun onHideCustomView() {
if (nVideoView == null) {
return
}
try {
customViewCallback?.onCustomViewHidden()
} catch (e: Exception) {
}
nVideoView?.visibility = View.GONE
// 占位view容器移除nVideoView
fl_video?.removeView(nVideoView)
nVideoView = null
fl_video?.visibility = View.GONE
// 设置竖屏
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
// 取消全屏
val attrs = window.attributes
attrs.flags = attrs.flags and WindowManager.LayoutParams.FLAG_FULLSCREEN.inv()
window.attributes = attrs
mToolbar.visibility = View.VISIBLE
immersionBar.statusBarDarkFont(true, 0.12f).statusBarColor("#F7F7F7").init()
}
完成。查看效果!!!
14.查看 android gradle 源码的一种方式
在 dependencies 加入 testImplementation "com.android.tools.build:gradle:${versions.gradle}"
即可
16.记录一个奇怪的bug,可能是混淆文件写的不正确
kotlin package级别的一个常量导致了android 在打包混淆 时某个依赖包的asstes 文件丢失一部分
private const val UnitTrans = 666.67
导致
nim_keystore
nim_keystore2
丢失
...
17. NestedScrollView
键盘遮挡的一个解决方案(adjustpan
无效)
项目里可以获取到 keybord
的高度。而且 adjustpan
无效,且 EditText
在NestedScrollView
底部,所以解决方案如下:
- 键盘弹出时添加一个
keybord
高度的Space
,并滑动只底部
setOnKeyboardListener { isPopup, keyboardHeight ->
KLog.d("setOnKeyboardListener $isPopup $keyboardHeight")
if (isPopup){
if (fr is MeetDetailFragment){
if (space.parent != null){
return@setOnKeyboardListener
}
space.apply {
layoutParams = ViewGroup.MarginLayoutParams(0, keyboardHeight)
}
//post to queue
fr.ll_meet_body.addView(space)
fr.nsc_meet_parent?.post {
fr.nsc_meet_parent.fullScroll(View.FOCUS_DOWN)
}
}
}else{
if (fr is MeetDetailFragment){
fr.ll_meet_body.removeView(space)
}
}
- 键盘关闭时添加一个移除
Space
https://blog.csdn.net/HJF_HUANGJINFU/article/details/61199480
18. 一行代码帮你检测Android模拟器
强制刷新app的依赖
gradlew build --refresh-dependencies
阿里云推送的坑
Android集成阿里云推送时,如果使用IntentService
时,同时也要集成MessageReceiver
,否则在进程结束后再次打卡app收不到离线的信息!!!
Drawable 多次tint时的问题
DrawableCompat.wrap(drawable)
后tint 需要先 unwrap
DrawableCompat.unwrap<Drawable>(drawable)
Android O
1. Service 使用 ContextCompat.startForegroundService(this,serIntent)
ForegroundService 需要构造一个 notification 来确保为前台服务
startForeground( i > 0 , notification)
notification 至少需要 setContentTitle
和 setSmallIcon
ADB 操作
1 . adb shell am start -n "package/package+classname"
2. adb shell am force-stop "package"