android采坑记录

这篇博客记录了Android开发过程中的各种坑,包括ScrollView匹配高度问题、ViewPager高度自适应、WebView与ScrollView配合滚动、权限申请、文件上传错误、时间戳转换、Activity启动模式等,并给出了相应的解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ScrollView控件中的match_parent无效

添加android:fillViewport=“true”属性

轮播banner,数据源更新界面无法更新

其实也不是无法更新,内部有viewPager首页刷新无效,会在之后的pager里显示新的数据源中的东西。内部已经调用了adapter.notifyDataSetChanged()。这是viewPager的机制可以参考viewPager刷新问题详解

ScrollView嵌套横向滑动控件时冲突

ScrollView嵌套横向滑动控件时冲突问题

ViewPager高度自适应,获取高度为0

使用viewpager高度自适应时 MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)拿到的高度都是0,我使用的是databing,后来发现是pager.setObjectForPosition(binding.getRoot(),position);这样拿到整个界面的第一层布局,高度似乎无法撑开。后来使用 pager.setObjectForPosition(binding.recycler,position);对recycler的高度设置,它的外层是ScrollerView,可以将界面撑开,这样得到的高度才是fragment中全部控件的高度。viewPager高度自适应

WebView内嵌在Scrollerview中,一起上下滚动

webview内嵌在Scrollerview中,上下滚动,只能滚动webview,要webview与scrollerview一起滚动,可以在ScrollerView中加 android:descendantFocusability="blocksDescendants"抢占焦点即可实现。

使用@Nullable PersistableBundle persistentState界面空白

在activity中使用

public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);

这是5.0以上新出的方法,给予界面持久化的能力,但需要在AndroidManifest.xml的activity标签下添加android:persistableMode="persistAcrossReboots"属性,不然界面会无法加载处理,显示一片空白。

ViewPager+Fragment更新fragment无效

根据业务需要每次刷新都是重新创建fragment,但除了第一次,每次获取的fragment中的值是空。后来发现是因为使用了FragmentPagerAdapter,FragmentPagerAdapter中的instantiateItem方法会去判断是否有fragment的缓存,如果有就使用那个,所以每次都拿到的是另一个对象。FragmentPagerAdapter中Fragment不能刷新问题。这是通过 ShopListFrag shopListFrag = (ShopListFrag) viewPagerVM.items.get(binding.tabs.getSelectedTabPosition());获取的方式,fragment更新从而items更新。但是如果不使用上面的方式,通过ShopListFrag shopListFrag = (ShopListFrag) childFragmentManager.getFragments().get(binding.tabs.getSelectedTabPosition());这样获取,也可以得到fragmnet对象。

使用DataBinding控件有时显示不全

  • 在使用databinding的时候界面需要model值动态刷新,但有时整个控件会加载不全,字符空白,这可能是因为控件已经加载,但因为长度的限制无法显示,可以在model中对数据赋初值,先将控件的长度拉开在刷新。
  • 又遇到一个bug,databinding数据获取更改后,界面无法刷新,控件gone后占着位置,其他控件没有重新布局,部分机型锁屏后,再展示又可以了。网上说的先清除动画,再通知或者直接强制刷新调用requestLayout也无效。我们用的是下拉刷新控件SwipeToLoadLayout,将swipe_target的 id设置在linearLayout上,去掉ScrollerView这样又可以了。最后摸索中发现不是ScrollerView的锅,是我们在BindingAdapter中调用了SwipeToLoadLayout.post(new Runnable())方法,将其改为postDelay延时调用就可以了。估计是占用了UI线程,导致界面无法刷新。

radioButton设置默认选中,切换tab后无法显示

使用android:chenk属性可以设置默认初始化。我的应用场景是根据返回的值显示哪个被选中了,第一次请求显示是可以的,但切换tab之后,界面更新,然后再切换回来,发现不显示选中,但值已经设置。解决方法:使用radioGroup的android:checkButton属性设置选中方式。

时间戳转换为日期,存在时区问题

导入的包有问题:应该导入java.text.SimpleDateFormat;而不是android.icu.text.SimpleDateFormat;,出现的问题场景是差8个小时,存在时区问题,忽略了系统的时区

Android Studio的坑

  • android studio 升级一直卡在refleshing xx/Gradle test这是没有最新gradle所致,因为网络问题所以下载不了导致,可以在网上直接下相应的gradle版本放在C:\Users\Administrator.gradle\wrapper\dists\gradle-4.1-all目录下,项目结构为
    目录结构
  • 将android studio 从2.3升级到3.0 ,导致as在新建项目时,报模板错误,这是应为as升级是文件损坏。网上说直接将出错的文件替换就好了。但我这里没有具体文件。后来发现,as创建时的模板都在安装目录/plugins/android/lib/templates比如我的地址是D:\android\android_location\plugins\android\lib\templates,可以将这个文件夹整体替换掉,就ok了。

logcat不输出日志

酷派:拨号盘输入20121220#
华为:
#* #2846579# *# *

Activity设置singelTask,ARouter跳转回首页,fragment重叠

有时候界面过深,想回到首页,比较麻烦,所以设置singleTask,跳转回首页,其余页面自动关闭。在onNewIntent中接收参数,设置想要显示的tab,但出现了重叠现象。原来首页显示会默认显示第0号tab,然后你又设置了其余tab,tab监听会关闭第0号tab,显示你设置的tab,但如果你是从其余的tab回来的,将会出现重叠,所以手动关闭最后离开的tab页,可以设置变量存储最后离开的是哪一个position,手动关闭。

加载so库是报错UnsatisfiedLinkError

参考
还要注意你的so文件是存放在jniLibs文件下的还是在lib文件下的。sourceSets.main {jniLibs.srcDirs = [‘libs’] }是将lib文件当作了jniLibs,所以存放在jniLibs下时又加了这一句,会加载不到so库。

scheme跳转始终再同一个app

第三方唤醒APP以及四种启动模式的思考
使用了singleTask,需要再newIntent中获值。

scrollerView抢占子控件的滑动事件

 @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
    	//父控件不拦截子控件的任何事件
        getParent().requestDisallowInterceptTouchEvent(true);
        return super.dispatchTouchEvent(ev);
    }

权限申请一直在提示是否允许

这一般在android 6.0出现,只看到在申请WRITE_SETTINGS和CHANGE_NETWORK_STATE权限时,google在7.0已改。
参考

private void permissionSetting() {
        if (Build.VERSION.SDK_INT >= 23) {
            if (Build.VERSION.SDK_INT == 23) {
                if (Settings.System.canWrite(this)){
                    Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, 1);
                }else{
                    Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);
                    intent.setData(Uri.parse("package:" + getPackageName()));
                    startActivity(intent);
                }
            } else {
                if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_SETTINGS) != PackageManager.PERMISSION_GRANTED||
                        ContextCompat.checkSelfPermission(this, Manifest.permission.CHANGE_NETWORK_STATE) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_SETTINGS, Manifest.permission.CHANGE_NETWORK_STATE,}, BaseParam.PERMISSIONS_REQUEST);
                }
            }
        }
    }

上传文件时出错:java.net.ProtocolException: expected 6137 bytes but received 7081

这个原因可能是因为在上传时把文件写入请求体这是一个异步操作,上传也是一个异步开发,导致一边写一边发送,文件一大就会出现这个问题。解决方案1.延迟,2.压缩文件大小,3.把这两个异步之间改成同步,先写完再发送。

Only the original thread that created a view hierarchy can touch its views

这个问题的本质原因是控件模块等等创建时所在线程和处理时所在的线程不是同一个。大部分情况是非UI线程更改UI,但我遇到一个比较少的情况,比如说dialog,我们封装了dialog的create和dismiss,有时不注意会在某个回调里创建了dialog,而我们第二次又在主线程show了之前创建的dialog,这两个不是同一个线程,所以报了这个错误。解决方法,要么自己第一次就在主线程创建dialog,要么将dialog置为null,重新创建,而不是把原先的show

file2.exists()一直返回false,但文件是存在的

使用了DownloadManager,他的下载地址是request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);但是在判断的时候用的是File path = new File(Environment.DIRECTORY_DOWNLOADS),这两个目录其实是不一样的,setDestinationInExternalPublicDir的路径其实是storage/emulate/0/然后再后面添加所设置的路径即storage/emulate/0/download,可以使用File path = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString());

Context.startForegroundService() did not then call Service.startForeground()

android 8.0之后的错误,后台每启动一个服务需要一个通知,不然5s后报错。参考

使用adapter的notifyDataSetChanged,列表数据没有刷新

出问题的赋值方式list=allList。这种赋值方式无法更新,因为系统调用notifyDataSetChanged方法是检测List的内存数据块有没有更新,从而引发界面刷新。但是上面的赋值方式是把list引用到了另一块内存块,这样系统检测是没有变化的。正确的方式是list.clear();list.addAll(allList);

HorizontalScrollView自动滑动到焦点位置

项目里做了个左滑删除的控件,用到了HorizontalScrollView,即强行将HorizontalScrollView的第一个控件的宽设为屏幕宽度,从而实现左滑删除的效果。但这个item里包含了一个EditText控件,每次进入,自动获取了焦点,并且HorizontalScrollView左滑了部分,滑到到焦点位置,导致显示出删除按钮。不自动获取焦点方法:将焦点赋给其他控件android:focusable=“true” android:focusableInTouchMode=“true”,默认滑动的解决方法:重写HorizontalScrollView的computeScroll和scrollBy方法,将super方法注释掉。

h5使用input选择file的方式无法调取android的原生相机相册文件夹

解决方法参考

多个SurfaceView重叠问题

surfaceView是纵深排序(Z-ordered)的,它总在自己所在窗口的后面。所以,显示在前面的surfaceView要写在前面。也可以代码设置setZOrderOnTop(true)设置在最顶层。

<RelativeLayout
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <SurfaceView
           android:id="@+id/RlVedio1"
           android:layout_width="@dimen/x180"
           android:layout_height="@dimen/y300" />
      <SurfaceView
          android:id="@+id/RlVedio2"
          android:layout_width="@dimen/x180"
          android:layout_height="@dimen/y300" />
  </RelativeLayout>

与常规RelativeLayout不同,RlVedio1在RlVedio2上面。

多个fragment,切换时,fragment里的recyclerView不显示,其他控件正常

这个是因为切换时listView的数据在第一次fragment创建时已经加载过了,所以没有再次加载。将adapter重新重新赋值设置一下就行。

自动安装时报解析包失败

这主要是7.0,8.0兼容问题 使用以上方法,可以解决应用内部更新升级无误。但是如果使用手机原始的浏览器扫码下载(比如vivo的浏览器)无法自动安装升级,只能下载下来手动点击安装。这是因为浏览器不允许安装未知应用,我也没找到地方设置,因为这个这是手机初始应用,使用第三方浏览器应该可以在设置里设置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值