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能够作到重启服务。二者有一个共同点,就是都能修改锁屏内容。可能要作到流氓就必须抱大腿,跟特权的系统服务绑定在一块儿。

相关文章
相关标签/搜索