<持續(xù)更新中>:更新目錄
- 聲網(wǎng)后臺保活策略和IntentService使用回調(diào)監(jiān)聽,解決Android 臨時后臺任務(wù)問題
- 解決ViewPager + Fragment 數(shù)據(jù)刷新問題, 刷新無效, notifyDataSetChanged()無效
1.聲網(wǎng)類似問題,就是直播中關(guān)于聲網(wǎng)退到后臺無法發(fā)出聲音,類似聲網(wǎng)?;顔栴}。從而引發(fā)創(chuàng)建后臺,startForegroundService的問題如下:
Android 8.0以上如果使用service就會報“ Context.startForegroundService() did not then call Service.startForeground()”這個錯,是因為Google限制了在調(diào)用了startForegroundService方法以后,5s內(nèi)一定要調(diào)用startForeground方法,但是這個其實很難杜絕,因為每臺設(shè)備情況不一樣,如果手機(jī)卡一點,很可能就卡過這5s了,所以我們只能盡量減少。
1.不要在fragment里啟動service,建議在mainActivity里啟動,并且要成對的start和stop,在onDestroy()里stop。
2.在onCreate和onStartCommand都startForeground(),并且id不要用0。
網(wǎng)上的幾點意見都用了但是還是在華為手機(jī),出現(xiàn)偶發(fā)崩潰,因為華為強(qiáng)制殺死后臺的系統(tǒng)機(jī)制,讓人還是挺頭大的。給出我的方案,但是很多問題
1. 由于Serveice不穩(wěn)定,而且開啟后臺殺死困難,所以選擇用IntentService替代
/**
* 后臺服務(wù),用于保持語音房,在后臺服務(wù)不被回收
*/
class KeepAppLifeService : IntentService("KeepAppLifeService") {
override fun onHandleIntent(intent: Intent?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// 注意notification也要適配Android 8 哦
startForeground(1, getNotification())
}
// 靜音
FSAudioManager.getInstance()
.sound(SPUtils.getInstance().getBoolean(SPUtils.SwitchRef.IS_OPEN_SOUND, false))
//麥位靜音處理
val user = AudioRoomManager.getInstance().userStates
user.entries.forEach {
if (it.value.isShut) {
FSAudioManager.getInstance().soundOne(it.key.toInt(), true)
}
}
}
private var notificationManager: NotificationManager? = null
private val notificationId = "keep_app_live"
private val notificationName = "keep_app_live_channel"
override fun onCreate() {
super.onCreate()
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
//創(chuàng)建NotificationChannel
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
notificationId,
notificationName,
NotificationManager.IMPORTANCE_HIGH
)
//不震動
channel.enableVibration(false)
//靜音
channel.setSound(null, null)
notificationManager?.createNotificationChannel(channel)
startForeground(1, getNotification())
}
}
/**
* 獲取通知(Android8.0后需要)
*/
private fun getNotification(): Notification? {
val builder: Notification.Builder = Notification.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(getString(R.string.app_name))
.setContentIntent(getIntent())
.setContentText(getString(R.string.text_on_keep_live))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(notificationId)
}
return builder.build()
}
/**
* 點擊后,直接打開app(之前的頁面),不跳轉(zhuǎn)特定activity
*/
@SuppressLint("UnspecifiedImmutableFlag")
private fun getIntent(): PendingIntent? {
val msgIntent =
applicationContext.packageManager.getLaunchIntentForPackage(packageName) //獲取啟動Activity
return PendingIntent.getActivity(
applicationContext,
1,
msgIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
}
}
2. 啟動和關(guān)閉時機(jī)
通常我們需要一個這樣的Activity管理和Application回掉
/**
* -----------
* Activity生命周期監(jiān)聽管理
* 在Application進(jìn)行注冊
* 包括功能:Activity活動列表管理,退出App
*/
public class ActivityLifecycleCallback implements Application.ActivityLifecycleCallbacks
根據(jù)這個我們就可以做計數(shù),判斷在前臺還是后臺操作
/**
* 根據(jù)getAppStatus,判斷app狀態(tài)
*/
public void getAppStatus(Activity activity) {
if (isForget == 0) {
//App進(jìn)入后臺或者APP鎖屏了
//開啟服務(wù)
LogUtils.i("KeepAppLifeService:開啟服務(wù)");
//當(dāng)前房間id
long roomId = AudioRoomManager.getInstance().getRoomId();
//如果當(dāng)前在房間中 并且房間id != -1 開啟服務(wù)
if(roomId != -1 && AudioRoomManager.getInstance() != null && AudioRoomManager.getInstance().isInRoom()){
if(App.getInstance() != null) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O){
App.getInstance().startForegroundService(new Intent(activity, KeepAppLifeService.class));
}else{
App.getInstance().startService(new Intent(activity, KeepAppLifeService.class));
}
}
}
} else {
//App進(jìn)入前臺
//結(jié)束服務(wù)
//停止Service
try {
LogUtils.i("KeepAppLifeService:結(jié)束服務(wù)");
Intent intentFour = new Intent(activity, KeepAppLifeService.class);
activity.stopService(intentFour);
} catch (Exception e) {
e.printStackTrace();
}
}
}
2. 維護(hù)和重構(gòu)老項目的時候,我們會遇到viewpager的一些bug或者業(yè)務(wù)上的bug無法刷新清除之前的緩存。結(jié)局如下
首先,你需要升級,viewPager2. 如果業(yè)務(wù)不允許。那么這么解決
重寫兩個方法:getItemId() getItemPosition()
實例
public class ViewPagerAdapter extends FragmentPagerAdapter {
private final String TAG = ViewPagerAdapter.class.getSimpleName();
private List<Fragment> mList;
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
public void setData(List<Fragment> mList) {
this.mList = mList;
notifyDataSetChanged();
}
@Override
public Fragment getItem(int i) {
return mList == null ? null : mList.get(i);
}
@Override
public int getCount() {
return mList == null ? 0 : mList.size();
}
@Override
public long getItemId(int position) {
return mList.get(position).hashCode();
}
@Override
public int getItemPosition(@NonNull Object object) {
if (mList.contains(object)) {
// 如果當(dāng)前 item 未被 remove,則返回 item 的真實 position
Logger.d(TAG, "包含");
return mList.indexOf(object);
} else {
// 否則返回狀態(tài)值 POSITION_NONE
Logger.d(TAG, "不包含");
return POSITION_NONE;
}
}
}