Android鎖屏黑屏後連續定位問題解決方案

南方吳彥祖_藍斯發表於2021-09-23

LocationServiceDemo

該示例主要展示App切換到後臺熄滅螢幕後如何持續獲得裝置位置。

前述

掃一掃安裝

Android鎖屏黑屏後連續定位問題解決方案

問題說明

小米可以在WLAN高階設定中,設定在息屏情況下關閉wifi,(如果裝置手機流量關閉)導致在亮屏時可以定位,息屏後不能定位的情況。針對此種情況,我們在定位服務中,如果檢測到上述邏輯,則去點亮螢幕。 小米息屏後,WIFI大概在5分鐘之後會斷開,所以我們建議點亮螢幕的時間間隔為5分鐘。

核心難點

  1. 在定位服務中檢測是否是由息屏造成的網路中斷,如果是,則嘗試進行點亮螢幕。同時,為了避免頻繁點亮,對最小時間間隔進行了設定(可以按需求修改).如果息屏沒有斷網,則無需點亮螢幕.

  2. 需要保證定位服務的優先順序,以免被殺死。

  3. 定位服務包含了點亮螢幕的功能,需要有拉活機制,保證此服務一直是alive的。部分機型會殺死嘗試多次點亮螢幕的Service(經不完全測試,華為允許的嘗試次數為2次,小米為1次).

實現原理

1.在本地服務裡啟動連續定位:

//在activity中啟動自定義本地服務LocationServicegetApplicationContext().startService(new Intent(this, LocationService.class));//在LocationService中啟動定位mLocationClient = new AMapLocationClient(this.getApplicationContext());
mLocationOption = new AMapLocationClientOption();// 使用連續定位mLocationOption.setOnceLocation(false);// 每10秒定位一次mLocationOption.setInterval(10 * 1000);
mLocationClient.setLocationOption(mLocationOption);
mLocationClient.setLocationListener(locationListener);
mLocationClient.startLocation();
複製程式碼

2.在locationListener中對結果進行判斷,如果是息屏造成的斷網,則嘗試點亮螢幕:

  AMapLocationListener locationListener = new AMapLocationListener() {        @Override
        public void onLocationChanged(AMapLocation aMapLocation) {            //傳送結果的通知
            sendLocationBroadcast(aMapLocation);        //判斷是否需要對息屏斷wifi的情況進行處理
            if (!mIsWifiCloseable) {                return;
            }        //將定位結果和裝置狀態一起交給mWifiAutoCloseDelegate
            if (aMapLocation.getErrorCode() == AMapLocation.LOCATION_SUCCESS) {                //...
            } else {               //...
            }
        }        private void sendLocationBroadcast(AMapLocation aMapLocation) {            //記錄資訊併傳送廣播...
        }
    };/** 處理息屏後wifi斷開的邏輯*/public class WifiAutoCloseDelegate implements IWifiAutoCloseDelegate {    /**
     * 請根據後臺資料自行新增。此處只針對小米手機
     * @param context
     * @return
     */
    @Override
    public boolean isUseful(Context context) {       //...
    }    /** 由於服務可能被殺掉,所以在服務初始化時,初始相關引數*/
    @Override
    public void initOnServiceStarted(Context context) {        //...
    }    /** 處理定位成功的資訊*/s    @Override
    public void onLocateSuccess(Context context, boolean isScreenOn, boolean isMobileable) {        //...
    }    /** 處理定位失敗的資訊。如果需要喚醒螢幕,則嘗試喚醒*/
    @Override
    public void onLocateFail(Context context, int errorCode, boolean isScreenOn, boolean isWifiable) {        //...
    }
}
複製程式碼

3.點亮螢幕時,會利用最小間隔時間加以限制:

     /**
     * 喚醒螢幕
     */
    public void wakeUpScreen(final Context context) {        try {
            acquirePowerLock(context, PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_DIM_WAKE_LOCK);
        } catch (Exception e) {            throw e;
        }
    }    /**
     * 根據levelAndFlags,獲得PowerManager的WaveLock
     * 利用worker thread去獲得鎖,以免阻塞主執行緒,並且增加了最小間隔,防止頻繁喚醒
     * @param context
     * @param levelAndFlags
     */
    private void acquirePowerLock(final Context context, final int levelAndFlags) {        //...
    }
複製程式碼

4.採用雙service繫結Notification,提高程式優先順序

    /**
     * LocationService.java
     * 觸發利用notification增加程式優先順序
     */
    protected void applyNotiKeepMech() {        //...
    }    /* LocationHelperService
     * binder中的回撥用於繫結和LocatioService一樣的NotificationId,並stopForeground使通知隱藏
     */
   private class HelperBinder extends ILocationHelperServiceAIDL.Stub{        @Override
        public void onFinishBind(int notiId) throws RemoteException {            //...
        }
    }
複製程式碼

5.採用了LocationHelperService做為守護程式,在檢測到LocationService被殺掉後,重啟定位服務。

        private void startBind() {
        mInnerConnection = new ServiceConnection() {        /** 檢測到定位服務被kill掉時,重啟定位服務*/
            @Override
            public void onServiceDisconnected(ComponentName name) {                //...
            }
        };    //...
    }
複製程式碼

專案地址

作者:小Fuคิดถึง
連結:
來源:掘金
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69983917/viewspace-2793323/,如需轉載,請註明出處,否則將追究法律責任。

相關文章