滑動
- 滑動嵌套
滑動組件的嵌套可能會產(chǎn)生以下一些問題:
- 滑動沖突
解決方法:使用NestedScrollView
替代ScrollView
誊垢,RecyclerView
可以設(shè)置屬性android:nestedScrollingEnabled="false"
或代碼里setNestedScrollingEnabled(false);
來禁用組件自身的滑動
注意:如果RecyclerView
只能顯示一個Item的話酵紫,需要設(shè)置NestedScrollView
的屬性android:fillViewport="true"
- 滑動失效
ScrollView
設(shè)置fillViewport="true"
的情況下席楚,如果對ScrollView
的直接子view設(shè)置上下margin醇疼,在超出內(nèi)容的高度小于設(shè)置的margin的情況下,可能會導(dǎo)致整個ScrollView
滑動失效
- 焦點(diǎn)搶占
ScrollView
听想、RecyclerView
等滑動組件可能會搶占焦點(diǎn)眼虱,導(dǎo)致界面顯示時直接滑動到對應(yīng)組件的位置,而不是頂部
解決方法:在頂部View(或者其他你所期望的初始位置)加上屬性android:focusable="true"
和android:focusableInTouchMode="true"
新解決方法:在頂部View上加android:descendantFocusability
屬性僵朗,該屬性是用來定義父布局與子布局之間的關(guān)系的赖欣,它有三種值:
-
beforeDescendants
:父布局會優(yōu)先其子類控件而獲取到焦點(diǎn) -
afterDescendants
:父布局只有當(dāng)其子類控件不需要獲取焦點(diǎn)時才獲取焦點(diǎn) -
blocksDescendants
:父布局會覆蓋子類控件而直接獲得焦點(diǎn)
使用blocksDescendants
覆蓋子布局焦點(diǎn)以解決焦點(diǎn)搶占問題
RecyclerView
Adapter
- 在
onBindViewHolder
中設(shè)置子View回調(diào)時需要注意
如果回調(diào)的參數(shù)包括position時歌径,需要注意有沒有地方會調(diào)用notifyItemRemoved
或notifyItemRangeRemoved
戈毒,如果有,需要使用holder.getAdapterPosition()
來代替onBindViewHolder
方法的position參數(shù)
原因:notifyItemRemoved
不會對其他的Item重新調(diào)用onBindViewHolder
甥厦,這樣可能會導(dǎo)致position錯位粪薛。holder.getAdapterPosition()
方法會返回數(shù)據(jù)在 Adapter 中的位置(即使位置的變化還未刷新到布局中)
- 如何在更新數(shù)據(jù)后重新定位到頂部
//重寫父類方法云矫,獲得綁定的RecyclerView
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
mRecyclerView = recyclerView;
}
//當(dāng)數(shù)據(jù)更新后調(diào)用
if (mRecyclerView != null && mRecyclerView.getChildCount() > 0) {
mRecyclerView.scrollToPosition(0);
}
之前嘗試過mRecyclerView.scrollTo(0, 0);
但沒有起效,不清楚為什么
- 動態(tài)部分更新數(shù)據(jù)時
如果RecyclerView
需要動態(tài)更新部分數(shù)據(jù),并且在onBindViewHolder
時對某些view設(shè)置了事件或者回調(diào)等让禀,如果此時使用到了position參數(shù)需要注意挑社,如果你只notify了部分?jǐn)?shù)據(jù)更新,可能會導(dǎo)致更新后部分ViewHolder中的回調(diào)里的position不正確巡揍,建議:
- 使用
notifyDataSetChanged()
- 使用
notifyItem
痛阻,但是在onBindViewHolder
中設(shè)置回調(diào)時不要使用position參數(shù),而是使用holder.getAdapterPosition()
替代(注意這個方法在ViewHolder
沒有和RecyclerView
綁定時會返回-1NO_POSITION
)
Dialog
- 生命周期
- 初始化時需要注意
Dialog在第一次調(diào)用show()
方法后才會執(zhí)行onCreate(Bundle savedInstanceState)
方法腮敌,因此建議自定義Dialog時將findViewById
等初始化操作放在構(gòu)造函數(shù)中進(jìn)行阱当,避免外部使用時因在show()
之前設(shè)置視圖數(shù)據(jù)導(dǎo)致NPE
PopupWindow
- 點(diǎn)擊沒反應(yīng)
PopupWindow
如果不設(shè)置背景的話,在某些5.x以下系統(tǒng)機(jī)型上會出現(xiàn)點(diǎn)擊沒反應(yīng)的問題
解決方法:給PopupWindow設(shè)置一個空背景popupWindow.setBackgroundDrawable(new BitmapDrawable(mContext.getResources(), (Bitmap) null));
廣播
- 隱式廣播
在Android8.0以上的系統(tǒng)糜工,大部分的隱式廣播都被限制不可使用弊添。
解決方法:
- 使用動態(tài)廣播
- 使用顯示廣播
// 方式一: 設(shè)置Component
Intent intent = new Intent(SOME_ACTION);
intent.setComponent(new ComponentName(context, SomeReceiver.class));
context.sendBroadcast(intent);
// 方式二: 設(shè)置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);
}
實(shí)體鍵盤
-
EditText
有焦點(diǎn)時會攔截鍵盤的數(shù)字鍵
解決方法:使用TextWatcher
等監(jiān)聽EditText
輸入
內(nèi)存泄漏
- 動畫
在Activity銷毀之前如果沒有cancel掉,會導(dǎo)致這個Activity內(nèi)存泄漏
ClickableSpan
使用SpannableString.setSpan
方法設(shè)置ClickableSpan
可能導(dǎo)致內(nèi)存泄漏
原因:TextView
在onSaveInstanceState
時會將ClickableSpan
復(fù)制一份捌木,由于某些原因油坝,SpannableString
不會刪除這個ClickableSpan
,從而導(dǎo)致內(nèi)存泄漏刨裆,詳見: StackOverflow
解決方法:自定義一個抽象類同時繼承ClickableSpan
和實(shí)現(xiàn)NoCopySpan
接口澈圈,外部setSpan
時使用這個抽象類
Fragment
-
Fragment
盡量不要使用帶參構(gòu)造函數(shù),一定要保證有一個不含參的構(gòu)造函數(shù)帆啃,否則在Activity
重建時嘗試反射newInstance
恢復(fù)Fragment
時會拋出Could not find Fragment constructor
異常
混淆
- 反射
如果使用到了反射瞬女,需要特別注意需不需要在proguard-rules
中加入keep規(guī)則
- module混淆
如果是多module項(xiàng)目,想要在module中增加混淆規(guī)則努潘,proguardFiles
屬性是無效的诽偷,應(yīng)該使用consumerProguardFiles
屬性
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 21
targetSdkVersion 28
versionName repo.version
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'proguard-rules.pro' //這里
}
...
}
相機(jī)開發(fā)
- 拍照角度
相機(jī)的方向一般是以手機(jī)橫向作為正方向,這樣如果我們以豎屏的方式拍照疯坤,拍出來的照片可能會出現(xiàn)旋轉(zhuǎn)了90度的情況报慕,這時候就需要在拍照完后處理一下圖片,旋轉(zhuǎn)到正確位置贴膘。
具體介紹與算法在Android SDK中CaptureRequest.JPEG_ORIENTATION
的注釋中
private int getJpegOrientation(CameraCharacteristics c, int deviceOrientation) {
if (deviceOrientation == android.view.OrientationEventListener.ORIENTATION_UNKNOWN)
return 0;
//獲得相機(jī)方向與設(shè)備方向間的夾角
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;
}
計算好角度后就可以對圖片做旋轉(zhuǎn)了,網(wǎng)上有很多文章都說使用這種方式做旋轉(zhuǎn)
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getJpegOrientation(deviceRotation));
但實(shí)際上在某些系統(tǒng)上 (MIUI)略号,設(shè)置的這個參數(shù)并不會生效刑峡,所以我的方案是,獲得拍攝好的照片Bitmap后玄柠,再對其進(jìn)行旋轉(zhuǎn)
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);
}
相關(guān)推薦
【Android面試題】2022最新Android中高級大廠高頻面試題匯總助力金三銀四高薪必備_嗶哩嗶哩_bilibili
Android開發(fā)進(jìn)階學(xué)習(xí)—設(shè)計思想解讀開源框架 · 已更新至104集(持續(xù)更新中~)_嗶哩嗶哩_bilibili
Android音視頻開發(fā):音視頻基礎(chǔ)知識到直播推流實(shí)戰(zhàn)系列教程_嗶哩嗶哩_bilibili
Android項(xiàng)目實(shí)戰(zhàn)-從0開始手把手實(shí)現(xiàn)組件化路由SDK項(xiàng)目實(shí)戰(zhàn)_嗶哩嗶哩_bilibili