【持续更新】Android 开发常见功能或BugFix

136 阅读2分钟

1. RecyclerView 最后一条下面留下一部分空白区域

布局文件实现

<androidx.recyclerview.widget.RecyclerView
    ...
    android:clipPadding="false"
    android:paddingBottom="100dp"
</androidx.recyclerview.widget.RecyclerView>

java 代码实现

recyclerView.setClipToPadding(false);
recyclerView.setPadding(0, 0, 0, paddingBottom);

2.【待验证】 Retrofit 向服务端传递集合或数组(List、Set、Array)类型的参数

@Field("toUids[]")

@FormUrlEncoded
@POST("/relative/url")
Observable<String> getServerData(@Field("uids[]") List<String> uids);

3. 【待验证】扩大View的可点击区域

    /**
     * 扩大指定View的可点击区域
     *
     * @param view 被扩大的view
     * @param expand 上下左右要扩大的像素值
     */
    public static void expandViewClickableArea(final View view, final int expand) {
        final View parentView = (View) view.getParent();
        if (parentView != null) {
            parentView.post(new Runnable() {
                @Override
                public void run() {
                    Rect delegateRect = new Rect();
                    // 获取View的可点击区域(上下左右四个点)距离父View左上角的距离
                    view.getHitRect(delegateRect);
                    delegateRect.left -= expand;
                    delegateRect.top -= expand;
                    delegateRect.right += expand;
                    delegateRect.bottom += expand;
                    if (parentView != null) {
                        parentView.setTouchDelegate(new TouchDelegate(delegateRect, view));
                    }
                }
            });
        }
    }

注意: 一个parent只能设置一个触摸委派。 设置多个时,只有最后设置的child有效。如果希望一个view能设置多个委派,需要再自定义parent

参考文档:

blog.csdn.net/leunging/ar…

4. 调整手机音量

    /**
     * 获取指定 声音类型的音量
     * @param streamType  {@link AudioManager#STREAM_MUSIC} {@link AudioManager#STREAM_VOICE_CALL} 等
     * @return 0 ~ 100
     */
    public static int getStreamVolume(Context context, int streamType) {
        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        int volume = 0;
        if (audioManager != null) {
            int maxVolume = audioManager.getStreamMaxVolume(streamType);
            volume = audioManager.getStreamVolume(streamType) * 100 / maxVolume;
        }
        return volume;
    }

    /**
     * 修改媒体音量,影响歌曲
     * @param streamType  {@link AudioManager#STREAM_MUSIC} {@link AudioManager#STREAM_VOICE_CALL} 等
     * @param volume 0 ~ 100
     */
    public static void updateMediaVolume(Context context, int streamType, int volume) {
        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        if (audioManager != null) {
            int maxVolume = audioManager.getStreamMaxVolume(streamType);
            // int currentVolume = audioManager.getStreamVolume(streamType);
            audioManager.setStreamVolume(streamType, Math.round(maxVolume / 100f * volume), 0);
       }
    }

5. RecyclerView 下标越界 IndexOutOfBoundsException

现象: 下拉刷新过程中,先清空了原数据源,然后再通过网络请求拉取最新数据,在新数据未回来之前,如果老数据超出一屏,滑动屏幕,会出现 IndexOutOfBoundsException

原因: 原数据源已被清空,此时触发滑动,会走到 onBindViewHolder 函数,通过下标取数据,此时数据源已经为空了,所以就会导致 IndexOutOfBoundsException

解决方法: 不要过早的清空原数据源,这种情况通常应该,在新数据返回后,再清空老数据,添加新数据。

6. Java 中如何移除集合中的某一段连续的元素?

通过 List#subList

// 移除前50条数据
list.subList(0, 50).clear();

// 移除后50条数据
list.subList(list.size() - 50, list.size()).clear();

// 移除特定范围内的数据
list.subList(20, 30).clear();

参考链接:www.kaelli.com/23.html

7. Fragment 出现 java.lang.IllegalStateException Fragment already added and state has been saved

主要原因: Fragment显示时,用户跳转到了其他页面,导致Fragment 执行了 onSaveInstance(),此时,收到一条新消息,需要将该Fragment重新加入页面,会导致该问题

// Fragment.java
public void setArguments(@Nullable Bundle args) {
        if (mFragmentManager != null && isStateSaved()) {
            throw new IllegalStateException("Fragment already added and state has been saved");
        }
        mArguments = args;
    }

解决方案: 保证 setArguments() 只调用一次,可以通过 getArgument() 获取并修改参数

8. FragmentDialog 透明背景和点击穿透

public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    if (getDialog() != null && getDialog().getWindow() != null) {
        Window window = getDialog().getWindow();
        // 点击穿透
        window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
        // 让 dialogFragment 背景透明
        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    }
}

9. Android Studio 实现方法自动导入 @org.jetbrains.annotations.Nullable 或者 org.jetbrains.annotations.NotNull 的问题

参考:zinyan.com/?p=74