定位服务 GPS 强制关闭

Posted

技术标签:

【中文标题】定位服务 GPS 强制关闭【英文标题】:Location service GPS Force closed 【发布时间】:2013-10-22 07:14:46 【问题描述】:

您好,我开发了一个应用程序来定位最佳位置并将其发送到一个号码。它在网络位置上工作正常,但是当我想用 GPS 或 Criteria 类定位时,它会强制关闭! 真好,你帮我 tnx。

package ir.M410.toolkit;

import android.app.Service;
import android.content.Intent;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.telephony.SmsManager;
import android.util.Log;



public class LocationFinder extends Service implements LocationListener

double lat ,lon ;
@Override
public IBinder onBind(Intent arg0) 
    return null;
       

@Override
public int onStartCommand(Intent intent, int flags, int startId) 
    // We want this service to continue running until it is explicitly
    // stopped, so return sticky.


    LocationManager mlocationManager = (LocationManager)        getSystemService(LOCATION_SERVICE);
    Criteria criteria = new Criteria();
    criteria.setAccuracy(Criteria.ACCURACY_FINE);
    criteria.setPowerRequirement(Criteria.POWER_MEDIUM);
    String locationprovider = mlocationManager.getBestProvider(criteria, true);
    Location mlocation = mlocationManager.getLastKnownLocation(locationprovider);


      lat = mlocation.getLatitude ();
      lon = mlocation.getLongitude ();

      Log.i("Geo_Location", "Latitude: " + lat + ", Longitude: " + lon);

      SmsManager sms = SmsManager.getDefault();
        sms.sendTextMessage("+11231233213", null,"https://maps.google.com/maps?q="+lat+","+lon, null, null);



        //  SmsManager sms = SmsManager.getDefault();
    //sms.sendTextMessage(MainActivity.senderNum, null,"  "+"lat:"+lat+"  "+"lon:"+lon, null, null);
 //stopSelf();
          return START_NOT_STICKY;


@Override
public void onLocationChanged(Location location) 
    // TODO Auto-generated method stub

     lat= location.getLatitude();
    lon =location.getLongitude();

    Log.i("Geo_Location", "Latitude: " + lat + ", Longitude: " + lon);
  //  stopSelf();


@Override
public void onProviderDisabled(String provider) 
    // TODO Auto-generated method stub



@Override
public void onProviderEnabled(String provider) 
    // TODO Auto-generated method stub



@Override
public void onStatusChanged(String provider, int status, Bundle extras) 
    // TODO Auto-generated method stub




@Override
public void onDestroy() 
    super.onDestroy();



这是我的清单:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ir.M410.toolkit"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="17" />

<uses-permission android:name="android.permission.RECEIVE_SMS" >
</uses-permission>
<uses-permission android:name="android.permission.READ_SMS" >
</uses-permission>
<uses-permission android:name="android.permission.SEND_SMS" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" >
</uses-permission>
<uses-permission android:name="android.permission.CALL_PHONE" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <receiver android:name="ir.M410.toolkit.Broadcast_Receiver" >
        <intent-filter android:priority="2147483647" >
            <action android:name="android.intent.action.PHONE_STATE" />
            <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            <action android:name="ir.M410.toolkit.android.action.broadcast" />
        </intent-filter>
    </receiver>

    <service android:name="ir.M410.toolkit.LocationFinder" />

    <activity
        android:name="ir.M410.toolkit.PasswordCheck"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity
        android:name="ir.M410.toolkit.MainActivity"
        android:label="@string/title_activity_main"
        android:screenOrientation="portrait" >
    </activity>
    <activity
        android:name="ir.M410.toolkit.Teturial"
        android:label="@string/title_activity_teturial" >
    </activity>
    <activity
        android:name="ir.M410.toolkit.CallDivertActivity"
        android:label="@string/title_activity_call_divert" >
    </activity>
</application>

</manifest>

[已编辑]这里是 LogCat 定义:

10-14 19:58:37.823: E/AndroidRuntime(2685): FATAL EXCEPTION: main
10-14 19:58:37.823: E/AndroidRuntime(2685): java.lang.RuntimeException: Unable to start service ir.M410.toolkit.LocationFinder@4482e4a8 with Intent  cmp=ir.M410.toolkit/.LocationFinder : java.lang.NullPointerException
10-14 19:58:37.823: E/AndroidRuntime(2685):     at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3260)
10-14 19:58:37.823: E/AndroidRuntime(2685):     at android.app.ActivityThread.access$3600(ActivityThread.java:135)
10-14 19:58:37.823: E/AndroidRuntime(2685):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2205)
10-14 19:58:37.823: E/AndroidRuntime(2685):     at android.os.Handler.dispatchMessage(Handler.java:99)
10-14 19:58:37.823: E/AndroidRuntime(2685):     at android.os.Looper.loop(Looper.java:143)
10-14 19:58:37.823: E/AndroidRuntime(2685):     at android.app.ActivityThread.main(ActivityThread.java:4914)
10-14 19:58:37.823: E/AndroidRuntime(2685):     at java.lang.reflect.Method.invokeNative(Native Method)
10-14 19:58:37.823: E/AndroidRuntime(2685):     at java.lang.reflect.Method.invoke(Method.java:521)
10-14 19:58:37.823: E/AndroidRuntime(2685):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
10-14 19:58:37.823: E/AndroidRuntime(2685):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
10-14 19:58:37.823: E/AndroidRuntime(2685):     at dalvik.system.NativeStart.main(Native Method)
10-14 19:58:37.823: E/AndroidRuntime(2685): Caused by: java.lang.NullPointerException
10-14 19:58:37.823: E/AndroidRuntime(2685):     at ir.M410.toolkit.LocationFinder.onStartCommand(LocationFinder.java:38)
10-14 19:58:37.823: E/AndroidRuntime(2685):     at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3246)
10-14 19:58:37.823: E/AndroidRuntime(2685):     ... 10 more

[编辑] 代码检查不为空:

@Override
public int onStartCommand(Intent intent, int flags, int startId) 
    // We want this service to continue running until it is explicitly
    // stopped, so return sticky.


    LocationManager mlocationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
    Criteria criteria = new Criteria();
    criteria.setAccuracy(Criteria.ACCURACY_FINE);
    criteria.setPowerRequirement(Criteria.POWER_MEDIUM);
    String locationprovider = mlocationManager.getBestProvider(criteria, true);
    if(mlocationManager.getLastKnownLocation(locationprovider)!=null)
    Location mlocation = mlocationManager.getLastKnownLocation(locationprovider);


      lat = mlocation.getLatitude ();
      lon = mlocation.getLongitude ();

      Log.i("Geo_Location", "Latitude: " + lat + ", Longitude: " + lon);

      SmsManager sms = SmsManager.getDefault();
        sms.sendTextMessage("+11231233213", null,"https://maps.google.com/maps?q="+lat+","+lon, null, null);

    

它没问题,没有强制关闭,但没有收到数据,它总是为空!!

【问题讨论】:

堆栈跟踪说明了什么 在 onSTartCommand() 使用最后一个已知位置之前,检查它是否为空。还要在 Logcat 中提供输出/堆栈跟踪 mlocation 在调用 getLatitude()getLongitude() 方法之前进行空检查 正如前面两个 cmets 所指出的,在 GPS 定位之前,最后一个已知位置将为空,因此是空指针。 为了您当前的目的,您可以通过 onLocationChange() 函数发送短信。在这种情况下,只要该位置可用。要在位置可用时仅发送一次,请使用标志来跟踪您是否已经发送了 SMS。我的建议是您应该使用提供的新位置 API 而不是框架位置 API。新的位置 API 使用 Fused 位置提供程序提供快速访问并消耗更少的电量。检查这个:youtube.com/watch?v=Bte_GHuxUGc 【参考方案1】:

我已经从http://www.androidhive.info/2012/07/android-gps-location-manager-tutorial/实现了我自己版本的 GPSTracker 类

使用此功能,您可以打开 GPS 并在有效位置可用时立即接收回叫。这可能需要一点时间,具体取决于设备的位置,但会提供更精确和可靠的位置。

通过我的实现,您可以执行以下操作:

private GPSTracker gps;
private FirstFixListener firstFixListener;
private LocationUpdateListener locationUpdateListener;

private void sendGPStoSMS() 
    gps = GPSTracker.getInstance(context);
    firstFixListener = new MyFirstFixListener();
    locationUpdateListener = new MyLocationUpdateListener();
    gps.startUsingGPS(firstFixListener, locationUpdateListener);



private class MyFirstFixListener implements FirstFixListener 

    @Override
    public void onFirsFixChanged(boolean hasGPSfix) 
        if (hasGPSfix == true) 
            Location position = gps.getLocation();
            // send SMS with position

            // stop the gps and unregister callbacks
            gps.stopUsingGPS(firstFixListener, locationUpdateListener);
        

    



private class MyLocationUpdateListener implements LocationUpdateListener 

    @Override
    public void onLocationChanged(Location location) 
        // hand you each new location from the GPS
        // you do not need this as you only want to send a single position

    


这是我的 GPSTracker 实现:

public class GPSTracker extends Service implements LocationListener 

private static final String TAG = "GPSTracker";

/**
 * Register to receive callback on first fix status
 * 
 * @author Morten
 * 
 */
public interface FirstFixListener 

    /**
     * Is called whenever gps register a change in first-fix availability
     * This is valuable to prevent sending invalid locations to the server.
     * 
     * @param hasGPSfix
     */
    public void onFirsFixChanged(boolean hasGPSfix);


/**
 * Register to receive all location updates
 * 
 * @author Morten
 * 
 */
public interface LocationUpdateListener 
    /**
     * Is called every single time the GPS unit register a new location
     * The location param will never be null, however, it can be outdated if hasGPSfix is not true.
     *  
     * @param location
     */
    public void onLocationChanged(Location location);


private Context mContext;

// flag for GPS status
private List<FirstFixListener> firstFixListeners;
private List<LocationUpdateListener> locationUpdateListeners;
boolean isGPSFix = false;
boolean isGPSEnabled = false;
private GPSFixListener gpsListener;

// flag for GPS status
boolean canGetLocation = false;

Location location; // location
double latitude; // latitude
double longitude; // longitude
long mLastLocationMillis;

private boolean logLocationChanges;

// Declaring a Location Manager
protected LocationManager locationManager;

/** removed again as we need multiple instances with different callbacks **/
private static GPSTracker instance;

public static GPSTracker getInstance(Context context) 
    if (instance != null) 
        return instance;
    
    return instance = new GPSTracker(context);


private GPSTracker(Context context) 
    this.mContext = context;
    gpsListener = new GPSFixListener();
    firstFixListeners = new ArrayList<GPSTracker.FirstFixListener>();
    locationUpdateListeners = new ArrayList<GPSTracker.LocationUpdateListener>();


public boolean hasGPSFirstFix() 
    return isGPSFix;


private void addFirstFixListener(FirstFixListener firstFixListener) 
    this.firstFixListeners.add(firstFixListener);


private void addLocationUpdateListener(
        LocationUpdateListener locationUpdateListener) 
    this.locationUpdateListeners.add(locationUpdateListener);


private void removeFirstFixListener(FirstFixListener firstFixListener) 
    this.firstFixListeners.remove(firstFixListener);


private void removeLocationUpdateListener(
        LocationUpdateListener locationUpdateListener) 
    this.locationUpdateListeners.remove(locationUpdateListener);


public void setLogLocationChanges(boolean logLocationChanges) 
    this.logLocationChanges = logLocationChanges;


public Location getLocation() 
    return location;


private Location startLocationListener() 
    canGetLocation = false;

    try 
        locationManager = (LocationManager) mContext
                .getSystemService(Service.LOCATION_SERVICE);

        // getting GPS status
        isGPSEnabled = locationManager
                .isProviderEnabled(LocationManager.GPS_PROVIDER);

        if (isGPSEnabled) 
            if (location == null) 
                locationManager.requestLocationUpdates(
                        LocationManager.GPS_PROVIDER, 0, 0, this);
                locationManager.addGpsStatusListener(gpsListener);
                if (locationManager != null) 
                    location = locationManager
                            .getLastKnownLocation(LocationManager.GPS_PROVIDER);
                    if (location != null) 
                        latitude = location.getLatitude();
                        longitude = location.getLongitude();
                    
                
            
         else 
            showSettingsAlert();
        

     catch (Exception e) 
        e.printStackTrace();
    

    return location;


public void stopUsingGPS(FirstFixListener firstFixListener,
        LocationUpdateListener locationUpdateListener) 
    if (firstFixListener != null)
        removeFirstFixListener(firstFixListener);
    if (locationUpdateListener != null)
        removeLocationUpdateListener(locationUpdateListener);

    stopUsingGPS();


/**
 * Stop using GPS listener Calling this function will stop using GPS in your
 * app
 * */
public void stopUsingGPS() 
    Log.d("DEBUG", "GPS stop");
    if (locationManager != null) 
        locationManager.removeUpdates(GPSTracker.this);
        location = null;

        if (gpsListener != null) 
            locationManager.removeGpsStatusListener(gpsListener);
        

    
    isGPSFix = false;
    location = null;


public void startUsingGPS(FirstFixListener firstFixListener,
        LocationUpdateListener locationUpdateListener) 
    Log.d("DEBUG", "GPS start");
    if (firstFixListener != null)
        addFirstFixListener(firstFixListener);
    if (locationUpdateListener != null)
        addLocationUpdateListener(locationUpdateListener);

    startLocationListener();


/**
 * Function to get latitude
 * */
public double getLatitude() 
    if (location != null) 
        latitude = location.getLatitude();
     else 
        Log.e("GPSTracker", "getLatitude location is null");
    

    // return latitude
    return latitude;


/**
 * Function to get longitude
 * */
public double getLongitude() 
    if (location != null) 
        longitude = location.getLongitude();
     else 
        Log.e("GPSTracker", "getLongitude location is null");
    

    // return longitude
    return longitude;


/**
 * Function to check GPS/wifi enabled
 * 
 * @return boolean
 * */
public boolean canGetLocation() 
    return this.canGetLocation;


/**
 * Function to show settings alert dialog On pressing Settings button will
 * lauch Settings Options
 * */
public void showSettingsAlert() 
    AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);

    // Setting Dialog Title
    alertDialog.setTitle("GPS settings");

    // Setting Dialog Message
    alertDialog
            .setMessage("GPS is not enabled. Do you want to go to settings menu?");

    // On pressing Settings button
    alertDialog.setPositiveButton("Settings",
            new DialogInterface.OnClickListener() 
                public void onClick(DialogInterface dialog, int which) 
                    Intent intent = new Intent(
                            Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                    mContext.startActivity(intent);
                
            );

    // on pressing cancel button
    alertDialog.setNegativeButton("Cancel",
            new DialogInterface.OnClickListener() 
                public void onClick(DialogInterface dialog, int which) 
                    dialog.cancel();
                
            );

    // Showing Alert Message
    alertDialog.show();


@Override
public void onLocationChanged(Location location) 
    if ( location == null)
        return;

    this.location = location;



    mLastLocationMillis = SystemClock.elapsedRealtime();
    canGetLocation = true;
    if (isGPSFix) 


        if (locationUpdateListeners != null) 
            for (LocationUpdateListener listener : locationUpdateListeners) 
                listener.onLocationChanged(location);
            
        
    



@Override
public void onProviderDisabled(String provider) 
    canGetLocation = false;


@Override
public void onProviderEnabled(String provider) 



@Override
public void onStatusChanged(String provider, int status, Bundle extras) 


@Override
public IBinder onBind(Intent arg0) 
    return null;


private boolean wasGPSFix = false;

// http://***.com/questions/2021176/how-can-i-check-the-current-status-of-the-gps-receiver
// answer from soundmaven
private class GPSFixListener implements GpsStatus.Listener 
    public void onGpsStatusChanged(int event) 
        switch (event) 
        case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
            isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;

            if (isGPSFix != wasGPSFix)  // only notify on changes
                wasGPSFix = isGPSFix;
                for (FirstFixListener listener : firstFixListeners) 
                    listener.onFirsFixChanged(isGPSFix);
                
            

            break;
        case GpsStatus.GPS_EVENT_FIRST_FIX:
            // Do something.



            break;
        
    


【讨论】:

嗨@NoumanCh。这个答案有点过时了,今天我建议使用诸如github.com/mcharmas/Android-ReactiveLocation 之类的库来利用融合位置更新

以上是关于定位服务 GPS 强制关闭的主要内容,如果未能解决你的问题,请参考以下文章

强制关闭 Android 位置权限

GPS/LOCATION 关闭时如何获取位置? [复制]

地理定位在 GPS 关闭的情况下不起作用

无法强制打开 GPS

如何不断地将 GPS 数据从 android 发送到服务器,直到应用程序关闭

Android 6.0 默认关闭定位和GPS,开启后默认选省电