获取服务中的位置

时间:2015-08-10 16:28:30

标签: java android gps geolocation location

修改:我已将代码添加到最近尝试的底部。

我正在尝试按照示例代码here。我在检索最后一个已知位置时遇到困难。我尝试了几种方法。

  1. 在上面的链接示例中,他们使用“GPSTracker”。它给出了错误“无法解析符号'GPSTracker'”。是否有我缺少的导入?
  2. 我尝试使用LocationManager获取位置,如this example所示,但我收到错误“无法解析方法'requestLocationUpdates(java.lang.String,long,long,anonymous java.util.TimerTask)'” 。我也尝试将第三个参数更改为浮点数并得到类似的错误。
  3. 我尝试使用FusedLocationProviderApi获取位置。我将新的GoogleApiClient.Builder添加到我的onCreate()方法,导入了com.google.android.gms.location.FusedLocationProviderApi,并更新了build.gradle文件。但是当我将“this”添加到.addConnectionCallbacks(this)和.addOnConnectionFailedListener(this)时,它会在新的GoogleApiClient.Builder方法中出错。根据我的阅读,这是最佳选择,因为它针对最少的电池使用进行了优化?
  4. 我对如何获得位置感到茫然。我的目标与第一个链接的示例类似。我想构建一个在后台运行的服务,并将在指定的时间间隔内将其位置的更新发送到服务器。到目前为止,我已经创建了两个按钮,允许服务启动和停止。服务启动后,它会检查设备是否有移动数据。然后,我想要检查位置是否已打开并且有GPS信号。我只想要GPS信号而不是网络位置。最后,如果数据和位置/ GPS信号都为真,那么它会在指定的时间间隔内将其位置发送到服务器。到目前为止,这是我的代码。

    MainActivity.java

    package com.testtracker;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    
    public class MainActivity extends Activity
    {
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MyService.setUp(this);
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
    
        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings)
        {
            return true;
        }
    
        return super.onOptionsItemSelected(item);
    }
    
    public void startService(View view)
    {
        startService(new Intent(getBaseContext(), MyService.class));
    }
    
    public void stopService(View view)
    {
        stopService(new Intent(getBaseContext(), MyService.class));
    }
    }
    

    MyService.java

    package com.testtracker;
    
    import android.app.Activity;
    import android.app.Service;
    import android.content.Context;
    import android.content.Intent;
    import android.net.ConnectivityManager;
    import android.os.IBinder;
    import android.os.PowerManager;
    import android.widget.Button;
    import android.widget.Toast;
    
    import java.lang.reflect.Method;
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class MyService extends Service
    {
    PowerManager powerManager;
    PowerManager.WakeLock wakeLock;
    static Button startButton;
    static Button stopButton;
    
    public static void setUp(Activity act)
    {
        startButton = (Button)act.findViewById(R.id.button2);
        stopButton = (Button)act.findViewById(R.id.button);
    }
    
    @Override
    public IBinder onBind(Intent intent)
    {
        return null;
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
        wakeLock.acquire();
    
        startButton.setEnabled(false);
        stopButton.setEnabled(true);
    
        final ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
    
        Timer timer = new Timer();
        final int TIME_INTERVAL = 10000;
    
        Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
    
        timer.schedule(new TimerTask()
        {
            boolean mobileDataEnabled = false;
    
            public void run() {
                try {
                    //Check if phone has data
                    Class cmClass = Class.forName(connectivityManager.getClass().getName());
                    Method method = cmClass.getDeclaredMethod("getMobileDataEnabled");
                    method.setAccessible(true);
                    mobileDataEnabled = (Boolean) method.invoke(connectivityManager);
    
                    if (mobileDataEnabled)
                    {
                        //Has data. Check if phone has location and GPS signal. If it does, get location and send to server.
                    }
                    else
                    {
                        //No data. Check again during the next timer interval.
                    }
    
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, 0, TIME_INTERVAL);
    
        return START_STICKY;
    }
    
    @Override
    public void onDestroy()
    {
        super.onDestroy();
        wakeLock.release();
        startButton.setEnabled(true);
        stopButton.setEnabled(false);
        Toast.makeText(this, "Service Stopped", Toast.LENGTH_SHORT).show();
    }
    }
    

    编辑:

    通过我一直在进行的尝试(记录在我的下面的评论中),我想我会发布更新后的代码。我将使用当前的尝试更新以下代码,并将上述代码保留为原始代码。我最好使用FusedLocationProviderApi或Little Fluffy Location Library,因为它们似乎已针对在后台运行进行了优化。

    MainActivity.java

    package com.testtracker;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.location.LocationManager;
    import android.os.Bundle;
    import android.provider.Settings;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.widget.Button;
    
    public class MainActivity extends Activity implements Button.OnClickListener
    {
    Button startButton;
    Button stopButton;
    
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        startButton = (Button)findViewById(R.id.button2);
        stopButton = (Button)findViewById(R.id.button);
    
        startButton.setEnabled(true);
        stopButton.setEnabled(false);
    
        LocationManager service = (LocationManager)getSystemService(LOCATION_SERVICE);
        boolean locationEnabled = service.isProviderEnabled(LocationManager.GPS_PROVIDER);
    
        if(!locationEnabled)
        {
            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            startActivity(intent);
        }
    
        startButton.setOnClickListener(this);
        stopButton.setOnClickListener(this);
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
    
        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings)
        {
            return true;
        }
    
        return super.onOptionsItemSelected(item);
    }
    
    @Override
    public void onClick(View v)
    {
        switch(v.getId())
        {
            case R.id.button2:
                startButton.setEnabled(false);
                stopButton.setEnabled(true);
    
                Intent intentStart = new Intent(this, MyService.class);
                startService(intentStart);
                break;
    
            case R.id.button:
                startButton.setEnabled(true);
                stopButton.setEnabled(false);
    
                Intent intentStop = new Intent(this, MyService.class);
                stopService(intentStop);
                break;
        }
    
    }
    }
    

    MyService.java

    package com.testtracker;
    
    import android.app.Activity;
    import android.app.Service;
    import android.content.Context;
    import android.content.Intent;
    import android.location.Criteria;
    import android.location.Location;
    import android.location.LocationListener;
    import android.location.LocationManager;
    import android.net.ConnectivityManager;
    import android.os.Bundle;
    import android.os.IBinder;
    import android.os.Looper;
    import android.os.PowerManager;
    import android.widget.Toast;
    
    import java.lang.reflect.Method;
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class MyService extends Service implements LocationListener
    {
    protected LocationManager locationManager;
    protected LocationListener locationListener;
    
    PowerManager powerManager;
    PowerManager.WakeLock wakeLock;
    
    public void onCreate()
    {
        Toast.makeText(this, "in on create", Toast.LENGTH_SHORT).show();
    }
    
    @Override
    public IBinder onBind(Intent intent)
    {
        return null;
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
        wakeLock.acquire();
    
        final ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
    
        Timer timer = new Timer();
        final int TIME_INTERVAL = 10000;
    
        Looper.prepare(); //Fatal error said this must be added?
    
        Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
    
        timer.schedule(new TimerTask()
        {
            boolean mobileDataEnabled = false;
    
            public void run() {
                try {
                    //Check if phone has data
                    Class cmClass = Class.forName(connectivityManager.getClass().getName());
                    Method method = cmClass.getDeclaredMethod("getMobileDataEnabled");
                    method.setAccessible(true);
                    mobileDataEnabled = (Boolean) method.invoke(connectivityManager);
    
                    if (mobileDataEnabled)
                    {
                        //Has data. Check if phone has location and GPS signal. If it does, get location and send to server.
                        locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
                        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
    
                        final Criteria cri = new Criteria();
    
                        String bestProvider = locationManager.getBestProvider(cri, true);
    
                        Location loc = locationManager.getLastKnownLocation(bestProvider);
                        double lat = loc.getLatitude();
                        double lng = loc.getLongitude();
    
                        Toast.makeText(getBaseContext(), lat + " - " + lng, Toast.LENGTH_SHORT).show();
                    }
    
                } catch (Exception e) {
                    e.printStackTrace();
                    onDestroy();
                }
            }
        }, 0, TIME_INTERVAL);
    
        return START_STICKY;
    }
    
    @Override
    public void onDestroy()
    {
        super.onDestroy();
        wakeLock.release();
    
        Toast.makeText(this, "Service Stopped", Toast.LENGTH_SHORT).show();
    }
    
    @Override
    public void onLocationChanged(Location location) {
    
    }
    
    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
    
    }
    
    @Override
    public void onProviderEnabled(String provider) {
    
    }
    
    @Override
    public void onProviderDisabled(String provider) {
    
    }
    }
    

    logcat的 错误看起来像是由Looper.prepare()引起的。如果我不添加,那么我得到致命错误“无法在未调用Looper.prepare()的线程内创建处理程序”。不能赢这个吗?

    2263-2263/com.testtracker E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.testtracker, PID: 2263
    java.lang.RuntimeException: Unable to start service com.testtracker.MyService@18edb4e4 with Intent { cmp=com.testtracker/.MyService }: java.lang.RuntimeException: Only one Looper may be created per thread
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2914)
    at android.app.ActivityThread.access$2100(ActivityThread.java:151)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1401)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5257)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
    Caused by: java.lang.RuntimeException: Only one Looper may be created per thread
    at android.os.Looper.prepare(Looper.java:76)
    at android.os.Looper.prepare(Looper.java:71)
    at com.testtracker.MyService.onStartCommand(MyService.java:53)
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2897)
    at android.app.ActivityThread.access$2100(ActivityThread.java:151)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1401)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5257)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
    

0 个答案:

没有答案