踢开Android 开发中的绊脚石

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xiaomai949804781/article/details/78326450

在开发过程中,许多并算不上高级技能甚至连基础知识都不算的东西经常被忽略,但这些东西还经常是开发过程中的绊脚石,很长时间都解决不了,一旦找到了解决办法,就茅塞顿开了“原来是这样啊,这不是小菜一碟吗?下次我注意就是了”。但是时间长了真的发现“好记性不如烂笔头”,当再次遇到同样的问题,发现还是一脸懵逼,但可以肯定之前遇到过这个问题。为了避免重走冤枉路,所以将它们记录下来。

  1. 虚线
  2. ScrollView 嵌套 ListView 或 RecyclerView

1. 虚线

在 drawable 目录下新建 dash_line.xml

<?xml version="1.0" encoding="utf-8"?>  
<shape xmlns:android="http://schemas.android.com/apk/res/android"  
    android:shape="line">  
    <stroke  
        android:width="3px"  
        android:color="#000000"  
        android:dashWidth="20px"  
        android:dashGap="5px" />  
</shape>  
  • width:线条的粗细
  • dashWidth:破折线的长度
  • dashGap:破折线之间的空隙的长度,当dashGap = 0时,就是实线。

注意
- 如果在标签中设置了android:width,则在标签中android:layout_height的值必须大于android:width的值,否则虚线不会显示。如果不设置,默认android:width = 0。
- 默认情况下,在 Android 4.0 以上设备虚线会变成实线,有下面两种方法解决:

  1. 代码中可以添加:

    ```
    line.setLayerType(View.LAYER_TYPE_SOFTWARE, null);  
    ```
    
    1. XML中可以添加:

      android:layerType="software"  

      下面是完整示例:

      <View
         android:layout_width="match_parent"
         android:layout_height="4px"
         android:layerType="software"
         android:background="@drawable/dash_line"/>

2. ScrollView 嵌套 ListView 或 RecyclerView

如果 ScrollView 中除了 ListView 或 RecyclerView 还包含其他如 RelativeLayout、LinearLayout 之类的布局,当 ListView 或 RecyclerView 不在顶部时,ScrollView 会自动滚动到它们所在的位置。解决办法:

recyclerView.setFocusable(false);
recyclerView.setFocusableInTouchMode(false);

此外,由于 ScrollView 和 ListView (RecyclerView)会产生滑动冲突,当触摸到 ListView(RecyclerView)的布局时,会感觉很不流畅,解决办法:

recyclerView.setNestedScrollingEnabled(false);

ListView的解决办法同上。

3. 换行转译符

一个TextView中的文本内容如果使用\r\n换行,在部分手机上会出现空白的一行,方法是使用字符串替换方法,将\r去掉。

4. Activity 与 Fragment 创建顺序

  1. 第一次创建时,先创建Activity 再 创建 Fragment。
  2. 当开启不保留活动后,页面恢复创建时,先创建 Fragment ,再创建 Activity,这时在 Activity 中,使用 (Support)FragmentManager.findFragmentById() 或 findFragmentByTag() 就可以获取到恢复的 Fragment。

5. MediaPlayer 的一些小技巧

  1. MediaPlayer 播放网络音频时, 边下边播过程中,若缓存未完成且已缓存的部分已经播放完时,不会触发onError() 回调,而是会触发onCompletion()回调。这时可以通过 mediaPlayer.getCurrentPosition() 和 mediaPlayer.getDuration() 进行比较,如果 currentPosition 小于 duration 说明播放未完成,可以认为是播放过程中出现异常。
    经测试发现,即使正常情况下音频全部缓冲完后,播放完毕时,mediaPlayer.getCurrentPosition() 的值也很可能小于 mediaPlayer.getDuration() 的值,所以上面的方法容易造成误判,改用新的方法。

调用 mediaPlayer.setOnBufferingUpdateListener(),这是缓冲进度的回调,percent 的值为 0 - 100,因此,可以根据 percent 的值判断是否缓冲完毕,当回调触发 onCompletion 时,如果 percent 的值是 100 认为正常播放完毕,否则认为没有缓冲完毕,播放错误。

扫描二维码关注公众号,回复: 2941739 查看本文章
// 播放出错的位置,记录下来,下次继续从这个点开始播放
private var errorPosition = 0
private var hasBuffered = false

fun setUrl(url: String) {
    if (mediaPlayer == null) {
        mediaPlayer = MediaPlayer()
    }
    mediaPlayer?.also {
        it.reset()
        try {
            it.setDataSource(url)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        it.setOnErrorListener { mp, what, extra ->
            if (mp.currentPosition > 0) {
                errorPosition = mp.currentPosition
            }
            callback?.onError()
            stop()
            setUrl(url)
            return@setOnErrorListener true
        }
        it.setOnCompletionListener {
            if (!hasBuffered) {
                errorPosition = it.currentPosition
                callback?.onError()
                setUrl(url)
                return@setOnCompletionListener
            }
            it.seekTo(0)
            val message = handler.obtainMessage(what, it.duration, it.duration)
            handler.sendMessage(message)
            callback?.onFinish()
        }
        it.setOnBufferingUpdateListener { mp, percent ->
            hasBuffered = percent >= 100
        }
        it.setOnPreparedListener {
            if (errorPosition > 0) {
                it.seekTo(errorPosition)
                errorPosition = 0
            }
            callback?.onPrepared(it.duration)
        }
        it.prepareAsync()
    }
}

fun stop() {
    handler.removeCallbacks(runnable)
    handler.removeMessages(what)
    mediaPlayer?.stop()
    mediaPlayer?.release()
    mediaPlayer = null
}

6. Retrofit Post 乱码问题

在请求头中指定编码格式:

@Headers("Content-Type:application/x-www-form-urlencoded; charset=utf-8")
@POST("/xxx/xxx")
@FormUrlEncoded
Observable<Result> send(@Field("id") int id, @Field("content") String content);

猜你喜欢

转载自blog.csdn.net/xiaomai949804781/article/details/78326450