Android 开发笔记2.0

本文主要记录一些在开发过程中可能要用到的知识点,持续更新哦!2.0正式上线

目录:

  1. git clone URL之后想切换远程分支只需要git checkout 分支就行,不用再-b了。

  2. 个别手机在锁屏页点击三个功能入口无效,原因:非Activity启动Activity需要加上标记为NEW_TASK。

3.ViewPager 中的 Fragment 可见性问题的埋点解决方案:

4.常用的APP下载地方,可以免登陆下载Google Play的应用:apkpure(需翻墙) apkmirror

5.监听home键广播启动Activity会延迟5s,通过PendingIntent.send()方法启动Activity也不可以立即启动。
6.flutter中的inheritedwidget做到的数据共享只是实现了他和他子树的数据共享而已,但是provider可以做到跨组件数据共享。

7.git 删除分支、重命名分支

8.释放动画资源是(一般是controller?.dispose)需要调用在super.dispose方法之前的,不然会报错。

9.用handler做延时操作时要注意内存泄漏的问题,以免快速退出activity时造成程序崩溃。

10.recyclerview中第一个,最后一个,和中间的item样式不同时可以在onBindViewHolder中根据position来对应设置。

11.fragment的replace, add, show, hide方法区别:replace会替换掉之前的fragment,并且走完其生命周期;hide和show的话之前的fragment并不会走完其生命周期。

12.在replaceFragment出现Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState错误。

13.版本适配的沉浸式状态栏

14.recyclerview同时点击多个item或者同时多次点击单个item引起crash

15.TextView中文英文数字混排导致的自动换行问题

16.SmartRefreshLayout的一些注意事项

17.Fresco设置圆角时的注意事项

18.点击不同tab请求数据时,为防止 List 改变的不够及时,可以将 LIst 的类型换成线程安全的 CopyOnWriteArrayList ,再加上一定时间的防触摸操作即可解决数据出现混乱的问题。

19.RecyclerView的缓存机制(参考链接:https://www.jianshu.com/p/3e9aa4bdaefd

20.在MainActivity按下返回键不能完全退出应用

21.Android 10 授权读取媒体文件后还是报permission denied 错误。(Android 10 存储适配)

22.快手全屏视频广告播放黑屏

23.Android 不推荐使用枚举

24.打开系统页面

25.查看当前页面布局的具体情况

26.获取签名文件的SHA1值

27.android 与 h5 交互方式:

28.快速截屏模拟器的屏幕

29.AS Build窗口出现乱码

30.ViewPager禁止左右滑动

31.TabLayout 隐藏下划线

32.Android Studio 自动导包

33.TabLayout 实现部分自定义样式(自定义选中时的文字大小,样式,颜色)

34.打正式包时报下面的错误

35.git push免登录提交

36.敏感词校验

37.webview 白屏

38.每次刷新Recyclerview时,记录上次浏览的位置,并滑动到指定位置

39.Android 文件存储

40.实现录音功能

41.去除按钮阴影效果

42.自定义的对话框的背景、宽度、高度不生效

43.PopupWindow 出现在控件上方

44.实现 TextView 部分文字的点击监听(用户服务及隐私协议对话框)

45.Glide设置圆角图片

46.上传到OSS的录音文件无法播放

47.LAME 实现 mp3音频 的录制

48.获取 UTC 字符串的时间戳

49.获取当前的 UTC 时间戳

50.自定义转盘跳动动画

51.自定义 view 圆中心写文字

52.出现at android.view.ViewGroup.jumpDrawablesToCurrentState错误

53.获取当前进程名

54.MAT 打不开 .hprof 文件

55.APK 构建过程

56.CPU架构及so库兼容问题总结

57.高版本手机无法在后台开启震动

58.Git stash命令使用

59.图片文件与Bitmap之间的相互转换

60.安装完APK后点打开,然后回到桌面,再点图标打开时出现APP重建,重走启动页

61.ViewPager嵌套ViewPager中多层Fragment子ViewPager中加载不出来Fragment

62.禁止EditText自动弹出键盘

63.recyclerview 嵌套 scrollview 没有滑到顶部

64.输入法上移布局(不只是移到edittext下方)

65.EditText 的 hint 居中,光标居左

66.接口回调不执行

67.smoothScrollToPosition和scrollToPosition的区别

68.RecyclerView的置顶,上移和下移的动画效果及逻辑实现

69.关闭最近的程序列表中的任务

70.Glide加载大量图片导致数据错乱和OOM

71.自适应高度的 viewpager

72.EventBus 收不到消息

73.gradient中的angle属性

74.国际化语言失效

75.项目报红,却可以运行

76.textview文字颜色渐变

77.等边距的GridLayoutManager

2022-6-30

1. git clone URL之后想切换远程分支只需要git checkout 分支就行,不用再-b了。

虽然本地没有显示有其他分支,但其实是有的,所以只需要git checkout 就行。

2. 个别手机在锁屏页点击三个功能入口无效,原因:非Activity启动Activity需要加上标记为NEW_TASK。

但我是在Activity启动的其他activity,这也不行,可能这个activity是在service里面吧。所以为了各平台手机的
兼容性,最好还是加上标记为NEW_TASK吧。
总结:非Activity的context启动Activity需要加上NEW_TASK标记位。

3.ViewPager 中的 Fragment 可见性问题的埋点解决方案:

当 setUserVisibleHint 方法还没被废弃时:
(1)使用setUserVisibleHint 监听fragment是否可见,
(2)然后监听系统息屏和亮屏广播,利用onResume解决已经在指定fragment时进入后台再回到前台的问题,
(3)最后用一个int变量解决一开始指定fragment会被setUserVisibleHint设为false的问题。

private int userVisibleHintShowTimes = 0;
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        if (isVisibleToUser) {
            //到达fragment埋点
        } else {
            if (userVisibleHintShowTimes != 0){
                //离开fragment埋点
            }else {
                userVisibleHintShowTimes++;
            }
        }
        super.setUserVisibleHint(isVisibleToUser);
    }

@Override
    public void onResume() {
        Alog.i("NewsTab", "NewsTabFragment---onResume");

        //isLighted表示是否收到亮屏广播
        if (isLighted && getUserVisibleHint()) {
            //在指定fragment页面回到后台再回到前台时埋点
        }

        super.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();

        if (getUserVisibleHint()){
            //离开fragment埋点
        }
    }

    private class LockerReceiver extends BroadcastReceiver {
        private long showHomeAdLastTime=0;
        private long showLockAdLastTime=0;
        public LockerReceiver() {
        }

        @Override
        public void onReceive(final Context context, Intent intent) {
            if (!TextUtils.isEmpty(action)) {
                if (action.equals(Intent.ACTION_SCREEN_ON)) {
                   isLighted = true;
                } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                    isLighted = false;
                }
            }
        }
    }

当 setUserVisibleHint 方法已经被废弃时:
(1)在构建 adapter 的构造函数时,调用 super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); 方法。
(2)然后在 fragment 的相应 onResume 和 onPause 方法中直接埋点即可。

4.常用的APP下载地方,可以免登陆下载Google Play的应用:apkpure(需翻墙) apkmirror
5.监听home键广播启动Activity会延迟5s,通过PendingIntent.send()方法启动Activity也不可以立即启动。
6.flutter中的inheritedwidget做到的数据共享只是实现了他和他子树的数据共享而已,但是provider可以做到跨组件数据共享。
7.git 删除分支、重命名分支

删除本地分支
命令行 : $ git branch -d $ git branch -D

删除远程分支
命令行 : $ git push origin --delete

重命名本地分支
命令行 : $ git branch -m

重命名远程分支
(1)将远程分支删除掉 git push origin --delete
(2)将本地分支重命名 git branch -m
(3)将本地分支推到远程 git push origin

8.释放动画资源是(一般是controller?.dispose)需要调用在super.dispose方法之前的,不然会报错。
9.用handler做延时操作时要注意内存泄漏的问题,以免快速退出activity时造成程序崩溃。
10.recyclerview中第一个,最后一个,和中间的item样式不同时可以在onBindViewHolder中根据position来对应设置。
11.fragment的replace, add, show, hide方法区别:replace会替换掉之前的fragment,并且走完其生命周期;hide和show的话之前的fragment并不会走完其生命周期。

总结:用法上add配合hide或是remove使用,replace一般单独出现。

12.在replaceFragment出现Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState错误。

原因:如果activity的状态被保存了,这里再提交就会检查这个状态,符合条件就抛出一个异常来终止应用进程。也就是说在activity调用了onSaveInstanceState()之后,再commit一个事务就会出现该异常。那如果不想抛出异常,也可以很简单调用commitAllowingStateLoss()方法来略过这个检查就可以了。

13.版本适配的沉浸式状态栏

(1)简单版

/**
   * 设置沉浸式状态栏
   */
  private void setTransparentStatusBar() {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
          View decorView = getWindow().getDecorView();
          decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
          getWindow().setStatusBarColor(Color.TRANSPARENT);
      }
  }

(2)第三方库版
https://github.com/LongSh1z/ImmersionBar

14.recyclerview同时点击多个item或者同时多次点击单个item引起crash

解决方案:

public abstract class StaticListener implements View.OnClickListener {
    private static long lastClickTime;
    private static final long MIN_TIME_INTERVAL = 1500;

    protected boolean isTimeEnabled(){
        long currentClickTime = System.currentTimeMillis();
        if ((currentClickTime - lastClickTime) > MIN_TIME_INTERVAL){
            lastClickTime = currentClickTime;
            return true;
        }else {
            return false;
        }
    }
}
使用时:
btn1.setOnClickListener(new StaticListener() {
            @Override
            public void onClick(View v) {
                if (isTimeEnabled()) {
                    Log.d("CCC", "onClick");
                }
            }
        });
15.TextView中文英文数字混排导致的自动换行问题

解决方案:重写TextView

16.SmartRefreshLayout的一些注意事项

默认情况下会启用列表惯性滑动到底部时自动加载更多,解决方法如下:

//是否启用列表惯性滑动到底部时自动加载更多
mSmartRefreshLayout.setEnableAutoLoadMore(false);

默认情况下会在加载完成时滚动列表显示新的内容,解决方法如下:

//是否在加载完成时滚动列表显示新的内容
mSmartRefreshLayout.setEnableScrollContentWhenLoaded(false);

其他的默认情况如下:

//下面示例中的值等于默认值
RefreshLayout refreshLayout = (RefreshLayout)findViewById(R.id.refreshLayout);
refreshLayout.setPrimaryColorsId(R.color.colorPrimary, android.R.color.white);
refreshLayout.setDragRate(0.5f);//显示下拉高度/手指真实下拉高度=阻尼效果
refreshLayout.setReboundDuration(300);//回弹动画时长(毫秒)

refreshLayout.setHeaderHeight(100);//Header标准高度(显示下拉高度>=标准高度 触发刷新)
refreshLayout.setHeaderHeightPx(100);//同上-像素为单位 (V1.1.0删除)
refreshLayout.setFooterHeight(100);//Footer标准高度(显示上拉高度>=标准高度 触发加载)
refreshLayout.setFooterHeightPx(100);//同上-像素为单位 (V1.1.0删除)

refreshLayout.setFooterHeaderInsetStart(0);//设置 Header 起始位置偏移量 1.0.5
refreshLayout.setFooterHeaderInsetStartPx(0);//同上-像素为单位 1.0.5 (V1.1.0删除)
refreshLayout.setFooterFooterInsetStart(0);//设置 Footer 起始位置偏移量 1.0.5
refreshLayout.setFooterFooterInsetStartPx(0);//同上-像素为单位 1.0.5 (V1.1.0删除)

refreshLayout.setHeaderMaxDragRate(2);//最大显示下拉高度/Header标准高度
refreshLayout.setFooterMaxDragRate(2);//最大显示下拉高度/Footer标准高度
refreshLayout.setHeaderTriggerRate(1);//触发刷新距离 与 HeaderHeight 的比率1.0.4
refreshLayout.setFooterTriggerRate(1);//触发加载距离 与 FooterHeight 的比率1.0.4

refreshLayout.setEnableRefresh(true);//是否启用下拉刷新功能
refreshLayout.setEnableLoadMore(false);//是否启用上拉加载功能
refreshLayout.setEnableAutoLoadMore(true);//是否启用列表惯性滑动到底部时自动加载更多
refreshLayout.setEnablePureScrollMode(false);//是否启用纯滚动模式
refreshLayout.setEnableNestedScroll(false);//是否启用嵌套滚动
refreshLayout.setEnableOverScrollBounce(true);//是否启用越界回弹
refreshLayout.setEnableScrollContentWhenLoaded(true);//是否在加载完成时滚动列表显示新的内容
refreshLayout.setEnableHeaderTranslationContent(true);//是否下拉Header的时候向下平移列表或者内容
refreshLayout.setEnableFooterTranslationContent(true);//是否上拉Footer的时候向上平移列表或者内容
refreshLayout.setEnableLoadMoreWhenContentNotFull(true);//是否在列表不满一页时候开启上拉加载功能
refreshLayout.setEnableFooterFollowWhenLoadFinished(false);//是否在全部加载结束之后Footer跟随内容1.0.4
refreshLayout.setEnableOverScrollDrag(false);//是否启用越界拖动(仿苹果效果)1.0.4

refreshLayout.setEnableScrollContentWhenRefreshed(true);//是否在刷新完成时滚动列表显示新的内容 1.0.5
refreshLayout.srlEnableClipHeaderWhenFixedBehind(true);//是否剪裁Header当时样式为FixedBehind时1.0.5
refreshLayout.srlEnableClipFooterWhenFixedBehind(true);//是否剪裁Footer当时样式为FixedBehind时1.0.5

refreshLayout.setDisableContentWhenRefresh(false);//是否在刷新的时候禁止列表的操作
refreshLayout.setDisableContentWhenLoading(false);//是否在加载的时候禁止列表的操作

refreshLayout.setOnMultiPurposeListener(new SimpleMultiPurposeListener());//设置多功能监听器
refreshLayout.setScrollBoundaryDecider(new ScrollBoundaryDecider());//设置滚动边界判断
refreshLayout.setScrollBoundaryDecider(new ScrollBoundaryDeciderAdapter());//自定义滚动边界

refreshLayout.setRefreshHeader(new ClassicsHeader(context));//设置Header
refreshLayout.setRefreshFooter(new ClassicsFooter(context));//设置Footer
refreshLayout.setRefreshContent(new View(context));//设置刷新Content(用于非xml布局代替addView)1.0.4

refreshLayout.autoRefresh();//自动刷新
refreshLayout.autoLoadMore();//自动加载
refreshLayout.autoRefreshAnimationOnly();//自动刷新,只显示动画不执行刷新
refreshLayout.autoLoadMoreAnimationOnly();//自动加载,只显示动画不执行加载
refreshLayout.autoRefresh(400);//延迟400毫秒后自动刷新
refreshLayout.autoLoadMore(400);//延迟400毫秒后自动加载
refreshLayout.finishRefresh();//结束刷新
refreshLayout.finishLoadMore();//结束加载
refreshLayout.finishRefresh(3000);//延迟3000毫秒后结束刷新
refreshLayout.finishLoadMore(3000);//延迟3000毫秒后结束加载
refreshLayout.finishRefresh(false);//结束刷新(刷新失败)
refreshLayout.finishLoadMore(false);//结束加载(加载失败)
refreshLayout.finishLoadMoreWithNoMoreData();//完成加载并标记没有更多数据 1.0.4
refreshLayout.closeHeaderOrFooter();//关闭正在打开状态的 Header 或者 Footer(1.1.0)
refreshLayout.resetNoMoreData();//恢复没有更多数据的原始状态 1.0.4(1.1.0删除)
refreshLayout.setNoMoreData(false);//恢复没有更多数据的原始状态 1.0.5
17.Fresco设置圆角时的注意事项
18.点击不同tab请求数据时,为防止 List 改变的不够及时,可以将 LIst 的类型换成线程安全的 CopyOnWriteArrayList ,再加上一定时间的防触摸操作即可解决数据出现混乱的问题。
19.RecyclerView的缓存机制(参考链接:https://www.jianshu.com/p/3e9aa4bdaefd
20.在MainActivity按下返回键不能完全退出应用

如果确定要退出应用的话,可以调用 System.exit(0);

21.Android 10 授权读取媒体文件后还是报permission denied 错误。(Android 10 存储适配)

(1)创建文件适配(视频)

private String isExistDir(String saveDir, Context context) throws IOException {
        File downloadFile;
        // 下载位置
        if (Build.VERSION.SDK_INT >= 29){
            downloadFile = new File(String.valueOf(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES)));
        }else {
            downloadFile = new File(Environment.getExternalStorageDirectory(), saveDir);
        }
        String savePath = downloadFile.getAbsolutePath();
        Log.d("savePath:",savePath);
        PreferenceUtils.putString(context, Constant.SAVE_PATH,savePath);
        return savePath;
}

(2)获取文件适配(视频)

public static Uri getImageContentUri(Context context, java.io.File imageFile) {
        if (Build.VERSION.SDK_INT >= 29 || Build.VERSION.SDK_INT <= 23) {
            Log.d("Build.VERSION.SDK_INT:", String.valueOf(Build.VERSION.SDK_INT));
            String filePath = imageFile.getAbsolutePath();
            Cursor cursor = context.getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
                    new String[]{MediaStore.Video.Media._ID}, MediaStore.Video.Media.DATA + "=? ",
                    new String[]{filePath}, null);
            if (cursor != null && cursor.moveToFirst()) {
                String id = PreferenceUtils.getString(context, Constant.SAVE_PATH, "/storage/emulated/0/Android/data/" + context.getPackageName() + "/files/Movies");
                Uri uri = Uri.withAppendedPath(Uri.parse(id), "" + "live_video.mp4");
                Log.d(TAG, "getImageContentUri: uri:" + uri);
                if (uri == null && Build.VERSION.SDK_INT <= 23) {
                    int uriId = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
                    Uri baseUri = Uri.parse("content://media/external/images/media");
                    return Uri.withAppendedPath(baseUri, "" + uriId);
                }
                return uri;
            } else {
                if (imageFile.exists()) {
                    ContentValues values = new ContentValues();
                    values.put(MediaStore.Video.Media.DATA, filePath);
                    return context.getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
                } else {
                    return null;
                }
            }
        } else {
            Log.d("Build.VERSION.SDK_INT:", String.valueOf(Build.VERSION.SDK_INT));
            String filePath = imageFile.getAbsolutePath();
            Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    new String[]{MediaStore.Images.Media._ID}, MediaStore.Images.Media.DATA + "=? ",
                    new String[]{filePath}, null);
            if (cursor != null && cursor.moveToFirst()) {
                int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
                Uri baseUri = Uri.parse("content://media/external/images/media");
                return Uri.withAppendedPath(baseUri, "" + id);
            } else {
                if (imageFile.exists()) {
                    ContentValues values = new ContentValues();
                    values.put(MediaStore.Images.Media.DATA, filePath);
                    return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
                } else {
                    return null;
                }
            }
        }
    if(uri == null){
     
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为了满足广大Android开发爱好者与从业者的学习需求,我们精心整理并上传了一份全面而实用的Android项目资源包。这份资源包内容丰富,涵盖了从基础知识到实战应用的全方位内容,旨在为开发者们提供一个便捷、高效的学习平台。 一、文件手册 资源包中的文件手册部分,详细记录了Android开发的核心知识点和常用技术。无论是初学者还是有一定经验的开发者,都能从中找到所需的学习资料。手册采用了简洁明了的排版方式,使得查阅更加方便快捷。同时,手册内容深入浅出,既适合新手入门,也能为老手提供有价值的参考。 二、项目实战与练习 为了让学习者能够将理论知识与实践相结合,我们特别准备了项目实战与练习部分。这部分内容包含了多个精心设计的Android项目案例,从需求分析、设计思路到实现过程,都有详细的讲解和代码示例。学习者可以通过实际操作,深入了解Android开发的整个流程,提升自己的实战能力。 此外,我们还提供了一系列练习题,旨在巩固所学知识,检验学习成果。这些练习题既有基础题,也有难度较高的挑战题,适合不同层次的学习者进行练习。 三、Android开发工具集 在Android开发过程中,选择合适的工具能够大大提高开发效率。因此,我们整理了常用的Android开发工具集,包括开发工具、测试工具、性能优化工具等。这些工具都是经过我们精心筛选和测试的,能够帮助开发者们更加高效地进行Android开发工作。 总的来说,这份Android项目资源包是一份不可多得的学习资料,无论你是初学者还是有一定经验的开发者,都能从中受益匪浅。我们希望通过这份资源包,为广大Android开发爱好者与从业者提供一个更加便捷、高效的学习平台,共同推动Android开发领域的发展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值