Android 小問題匯總(2)

<持續(xù)更新中>:更新目錄

    1. 聲網(wǎng)后臺保活策略和IntentService使用回調(diào)監(jiān)聽,解決Android 臨時后臺任務(wù)問題
    1. 解決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;
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容