android 開發-定位

在手機中最經常使用的定位技術是GPS。
可是國內的應用並不能直接獲取真實的地理信息。
火星座標系統
各個座標系的介紹html

知識點

  1. service
  2. listener
  3. location

高德SDK

直接使用高德的SDK能夠省去很多麻煩。可是在使用SDK的時候須要key storejava

文檔很清楚高德SDK文檔,經過簡單的設置便可獲取須要的GPS信息。
可是要作到長時間監聽,還須要AlarmManager來保持CPU的工做。android

監聽位置信息

主要有4個步驟:git

  1. 配置AndroidManifest.xml
  2. 初始化定位
  3. 配置參數並啓動定位
  4. 獲取定位結果
class GpsService : Service() {
    private var mLocationClient: AMapLocationClient? = null
    //聲明定位回調監聽器
    private var mLocationListener: AMapLocationListener = AMapLocationListener { amapLocation ->
        if (amapLocation != null) {
            if (amapLocation.errorCode == 0) {
                //解析定位結果
                val latitude = amapLocation.latitude;//獲取緯度
                val longitude = amapLocation.longitude;//獲取經度
                PostDataTask().execute(Pair(latitude,longitude))
                Log.i("location","acc : ${amapLocation.accuracy}")
                Log.i("location", "altitude : ${amapLocation.altitude}")
            } else
                Log.w("location","error code: ${amapLocation.errorInfo}")
        }
    }

    override fun onCreate() {
        mLocationClient = AMapLocationClient(applicationContext)
        //設置定位回調監聽
        mLocationClient!!.setLocationListener(mLocationListener)
        val option = AMapLocationClientOption()
        /**
         * 設置定位場景,目前支持三種場景(簽到、出行、運動,默認無場景)
         */
        option.locationPurpose = AMapLocationClientOption.AMapLocationPurpose.Transport
        option.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
        //啓動定位
        mLocationClient!!.startLocation()
    }
}

位置存儲

安卓不能直接使用MySQL。既然用了高德的服務,乾脆存儲也使用雲存儲。它提供了幾個十分方便的API。api

在安卓中不能再主線程中調用Http請求。須要TaskAync來輔助完成一次請求。微信

private class PostDataTask : AsyncTask<Pair<Double, Double>, Int, Boolean>() {
        override fun doInBackground(vararg args: Pair<Double, Double>): Boolean {
            for (arg in args) {
                val longitude = arg.first;//獲取緯度
                val  latitude= arg.second;//獲取經度
                val now = System.currentTimeMillis() / 1000
                val params =getDataString(mapOf(
                        "key" to "2ad3b7f65c549d9155b7325c2d2c13b4",
                        "tableid" to "5a80175d2376c17f0129f54c",
                        "data" to " {\"_name\":\"$now\",\"_location\":\"$latitude,$longitude\"  }"))

                Log.d("location",params)
                var url = URL("http://yuntuapi.amap.com/datamanage/data/create")
                val urlConnection = url.openConnection() as HttpURLConnection
                urlConnection.instanceFollowRedirects = false;
                urlConnection.doOutput = true
                urlConnection.requestMethod = "POST";

                urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                urlConnection.setRequestProperty("charset", "utf-8");
                urlConnection.setRequestProperty("Content-Length", Integer.toString(params.length));
                urlConnection.useCaches = false;

                try {
                    DataOutputStream(urlConnection.outputStream).write((params).toByteArray())
                    urlConnection.connect()
                    if (urlConnection.responseCode in 200..299) {
                        val br = (InputStreamReader(urlConnection.inputStream).readText())
                        Log.i("response", br)
                    }

                } catch (e: java.io.IOException) {
                    e.printStackTrace()
                }

                urlConnection.disconnect()
            }
            return true;
        }

        private fun getDataString(params: Map<String, String>): String {
            val result = StringBuilder()
            var first = true
            for (entry in params.keys) {
                if (first)
                    first = false;
                else
                    result.append("&");
                result.append(URLEncoder.encode(entry, "UTF-8"));
                result.append("=");
                result.append(URLEncoder.encode(params[entry], "UTF-8"));
            }
            return result.toString();
        }
    }

在使用該接口的時候,出現一個錯誤:app

{
    "info": "參數缺失或格式非法",
    "infocode": "30001",
    "status": 0
}

開始還覺得是urlencode的不對,後來各類尋找也沒發現問題。最終發現是因爲經緯度的順序寫錯了,不支持地區就算了,返回這麼一個信息很頭疼啊。ide

AlarmManager

其實這段代碼很是簡單,在啓動service的時候建立一個alarm,而後在alarm的接收器裏再次啓動service。從而達到不被關閉的效果。ui

//service 類中
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        Log.i(TAG, "onStartCommand() executed")
        //Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show();
        val manager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val alarmTime = 20 * 1000 // 定時10s
        val triggerAtTime = SystemClock.elapsedRealtime() + alarmTime
        val i = Intent(this, AlarmReceiver::class.java)
        val pi = PendingIntent.getBroadcast(this, 0, i, 0)
        manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi)
        return super.onStartCommand(intent, Service.START_FLAG_REDELIVERY, startId)
    }

Reciverthis

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("alarm","trigger alarm");
        Intent i = new Intent(context, GpsService.class);
        context.startService(i);
    }
}

開機啓動

BootBroadcastReceiver

public class BootBroadcastReceiver extends BroadcastReceiver {
    static final String ACTION = "android.intent.action.BOOT_COMPLETED";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(ACTION)) {
            Intent mainActivityIntent = new Intent(context, GpsService.class);  // 要啓動的Activity
            mainActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(mainActivityIntent);
        }
    }
}

進程仍是被幹掉了怎麼辦?

流氓軟件的必備技能。但仍是有時候須要這麼一個東西。好比個人應用是一個定製化的軟件。這個時候整個系統都應該圍繞個人APP去工做。好比一個基於安卓的機器人系統。在空閒的時候容許用戶打開別的應用玩玩遊戲什麼的,可是個人後臺系統必需要時刻保持工做狀態。

service 進程保護機制

試了裏面的幾種辦法,最後仍是沒有在個人魅藍2,yunOS 3.1.6上達到開機啓動加後臺常駐。果真仍是大廠技術高。我手機裏的高德、微信、金山詞霸、cortana都作到了。囧。可是除了cortana其他的都是2個進程在跑。微信和高德的是能夠被殺掉,並不會重啓。而金山詞霸、cortana能夠作到重啓服務。二者有一個共同點,就是都能修改鎖屏內容。可能要作到流氓就必須抱大腿,跟特權的系統服務綁定在一塊兒。

相關文章
相關標籤/搜索