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
参考文档:
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();
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);
}
}