Android开发常见问题总结(持续更新)

滑动

  1. 滑动嵌套

滑动组件的嵌套可能会产生以下一些问题:

  • 滑动冲突

解决方法:使用NestedScrollView替代ScrollViewRecyclerView可以设置属性android:nestedScrollingEnabled="false"或代码里setNestedScrollingEnabled(false);来禁用组件自身的滑动

注意:如果RecyclerView只能显示一个Item的话,需要设置NestedScrollView的属性android:fillViewport="true"

  • 滑动失效

ScrollView设置fillViewport="true"的情况下,如果对ScrollView的直接子view设置上下margin,在超出内容的高度小于设置的margin的情况下,可能会导致整个ScrollView滑动失效

  1. 焦点抢占

ScrollViewRecyclerView等滑动组件可能会抢占焦点,导致界面显示时直接滑动到对应组件的位置,而不是顶部

解决方法:在顶部View(或者其他你所期望的初始位置)加上属性android:focusable="true"android:focusableInTouchMode="true"

新解决方法:在顶部View上加android:descendantFocusability属性,该属性是用来定义父布局与子布局之间的关系的,它有三种值:

  • beforeDescendants:父布局会优先其子类控件而获取到焦点
  • afterDescendants:父布局只有当其子类控件不需要获取焦点时才获取焦点
  • blocksDescendants:父布局会覆盖子类控件而直接获得焦点

使用blocksDescendants覆盖子布局焦点以解决焦点抢占问题


RecyclerView

Adapter

  1. onBindViewHolder中设置子View回调时需要注意

如果回调的参数包括position时,需要注意有没有地方会调用notifyItemRemovednotifyItemRangeRemoved,如果有,需要使用holder.getAdapterPosition()来代替onBindViewHolder方法的position参数

原因:notifyItemRemoved不会对其他的Item重新调用onBindViewHolder,这样可能会导致position错位。holder.getAdapterPosition()方法会返回数据在 Adapter 中的位置(即使位置的变化还未刷新到布局中)

  1. 如何在更新数据后重新定位到顶部
//重写父类方法,获得绑定的RecyclerView
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);
    mRecyclerView = recyclerView;
}

//当数据更新后调用
if (mRecyclerView != null && mRecyclerView.getChildCount() > 0) {
    mRecyclerView.scrollToPosition(0);
}

之前尝试过mRecyclerView.scrollTo(0, 0);但没有起效,不清楚为什么

  1. 动态部分更新数据时

如果RecyclerView需要动态更新部分数据,并且在onBindViewHolder时对某些view设置了事件或者回调等,如果此时使用到了position参数需要注意,如果你只notify了部分数据更新,可能会导致更新后部分ViewHolder中的回调里的position不正确,建议:

  • 使用notifyDataSetChanged()
  • 使用notifyItem,但是在onBindViewHolder中设置回调时不要使用position参数,而是使用holder.getAdapterPosition()替代(注意这个方法在ViewHolder没有和RecyclerView绑定时会返回-1 NO_POSITION

Dialog

  1. 生命周期
  • 初始化时需要注意

Dialog在第一次调用show()方法后才会执行onCreate(Bundle savedInstanceState)方法,因此建议自定义Dialog时将findViewById等初始化操作放在构造函数中进行,避免外部使用时因在show()之前设置视图数据导致NPE


PopupWindow

  1. 点击没反应

PopupWindow如果不设置背景的话,在某些5.x以下系统机型上会出现点击没反应的问题

解决方法:给PopupWindow设置一个空背景popupWindow.setBackgroundDrawable(new BitmapDrawable(mContext.getResources(), (Bitmap) null));

详见:juejin.cn/post/684490…


广播

  1. 隐式广播

在Android8.0以上的系统,大部分的隐式广播都被限制不可使用。

解决方法:

  1. 使用动态广播
  2. 使用显示广播
// 方式一: 设置Component
Intent intent = new Intent(SOME_ACTION);
intent.setComponent(new ComponentName(context, SomeReceiver.class));
context.sendBroadcast(intent);

// 方式二: 设置Package
Intent intent = new Intent(SOME_ACTION);
intent.setPackage("com.dreamgyf.xxx");
context.sendBroadcast(intent);

// 不知道包名的话可以通过PackageManager获取所有注册了指定action的广播的package
Intent actionIntent = new Intent(SOME_ACTION);
PackageManager pm = context.getPackageManager();
List<ResolveInfo> matches = pm.queryBroadcastReceivers(actionIntent, 0);
for (ResolveInfo resolveInfo : matches) {            
    Intent intent = new Intent(actionIntent);            
    intent.setPackage(resolveInfo.activityInfo.applicationInfo.packageName);            
    intent.setAction(SOME_ACTION);            
    context.sendBroadcast(intent);        
}


实体键盘

  1. EditText有焦点时会拦截键盘的数字键

解决方法:使用TextWatcher等监听EditText输入


内存泄漏

  1. 动画

在Activity销毁之前如果没有cancel掉,会导致这个Activity内存泄漏

  1. ClickableSpan

使用SpannableString.setSpan方法设置ClickableSpan可能导致内存泄漏

原因:TextViewonSaveInstanceState时会将ClickableSpan复制一份,由于某些原因,SpannableString不会删除这个ClickableSpan,从而导致内存泄漏,详见: StackOverflow

解决方法:自定义一个抽象类同时继承ClickableSpan和实现NoCopySpan接口,外部setSpan时使用这个抽象类


Fragment

  1. Fragment尽量不要使用带参构造函数,一定要保证有一个不含参的构造函数,否则在Activity重建时尝试反射newInstance恢复Fragment时会抛出Could not find Fragment constructor异常

混淆

  1. 反射

如果使用到了反射,需要特别注意需不需要在proguard-rules中加入keep规则

  1. module混淆

如果是多module项目,想要在module中增加混淆规则,proguardFiles属性是无效的,应该使用consumerProguardFiles属性

android {
    compileSdkVersion 28

    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 28
        versionName repo.version

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

        consumerProguardFiles 'proguard-rules.pro' //这里
    }
    ...
}


相机开发

  1. 拍照角度

相机的方向一般是以手机横向作为正方向,这样如果我们以竖屏的方式拍照,拍出来的照片可能会出现旋转了90度的情况,这时候就需要在拍照完后处理一下图片,旋转到正确位置。

具体介绍与算法在Android SDK中CaptureRequest.JPEG_ORIENTATION的注释中

private int getJpegOrientation(CameraCharacteristics c, int deviceOrientation) {
    if (deviceOrientation == android.view.OrientationEventListener.ORIENTATION_UNKNOWN)
        return 0;
    //获得相机方向与设备方向间的夹角
    int sensorOrientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION);

    // Round device orientation to a multiple of 90
    deviceOrientation = (deviceOrientation + 45) / 90 * 90;

    // Reverse device orientation for front-facing cameras
    boolean facingFront = c.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT;
    if (facingFront) deviceOrientation = -deviceOrientation;

    // Calculate desired JPEG orientation relative to camera orientation to make
    // the image upright relative to the device orientation
    int jpegOrientation = (sensorOrientation + deviceOrientation + 360) % 360;

    return jpegOrientation;
}

计算好角度后就可以对图片做旋转了,网上有很多文章都说使用这种方式做旋转

captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getJpegOrientation(deviceRotation));

但实际上在某些系统上 (MIUI),设置的这个参数并不会生效,所以我的方案是,获得拍摄好的照片Bitmap后,再对其进行旋转

public Bitmap rotateBitmap(Bitmap bitmap, int angle) {
   Matrix matrix = new Matrix();
   matrix.setRotate(angle);
   return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}

相关推荐

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容