通过Android中的服务获取GPS位置

Get GPS location via a service in Android

我需要使用后台服务监控用户的位置,然后加载它们并显示用户的路径。

使用活动,获取GPS位置非常容易,但是当我通过服务完成它时,我遇到了一个问题,因为它似乎只适用于looper线程(或类似的东西)。

当我在互联网上寻找解决方案时,我发现许多人遇到了同样的问题,但我找不到可行的解决方案。 有人说你需要使用prepare-> loop-> quit,有些人说你必须使用handlerThread,但是,我仍然无法找到如何以正确的方式做这些事情。


我不明白在服务中实现位置监听功能究竟是什么问题。它看起来与您在Activity中所做的非常相似。
只需定义位置监听器并注册位置更新即可。
您可以参考以下代码作为示例:

清单文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name">
   
        <intent-filter >
           
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <service android:name=".MyService" android:process=":my_service" />
</application>

服务文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service {

    private static final String TAG ="BOOMBOOMTESTGPS";
    private LocationManager mLocationManager = null;
    private static final int LOCATION_INTERVAL = 1000;
    private static final float LOCATION_DISTANCE = 10f;

    private class LocationListener implements android.location.LocationListener {
        Location mLastLocation;

        public LocationListener(String provider) {
            Log.e(TAG,"LocationListener" + provider);
            mLastLocation = new Location(provider);
        }

        @Override
        public void onLocationChanged(Location location) {
            Log.e(TAG,"onLocationChanged:" + location);
            mLastLocation.set(location);
        }

        @Override
        public void onProviderDisabled(String provider) {
            Log.e(TAG,"onProviderDisabled:" + provider);
        }

        @Override
        public void onProviderEnabled(String provider) {
            Log.e(TAG,"onProviderEnabled:" + provider);
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
            Log.e(TAG,"onStatusChanged:" + provider);
        }
    }

    LocationListener[] mLocationListeners = new LocationListener[]{
            new LocationListener(LocationManager.GPS_PROVIDER),
            new LocationListener(LocationManager.NETWORK_PROVIDER)
    };

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG,"onStartCommand");
        super.onStartCommand(intent, flags, startId);
        return START_STICKY;
    }

    @Override
    public void onCreate() {
        Log.e(TAG,"onCreate");
        initializeLocationManager();
        try {
            mLocationManager.requestLocationUpdates(
                    LocationManager.NETWORK_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
                    mLocationListeners[1]);
        } catch (java.lang.SecurityException ex) {
            Log.i(TAG,"fail to request location update, ignore", ex);
        } catch (IllegalArgumentException ex) {
            Log.d(TAG,"network provider does not exist," + ex.getMessage());
        }
        try {
            mLocationManager.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
                    mLocationListeners[0]);
        } catch (java.lang.SecurityException ex) {
            Log.i(TAG,"fail to request location update, ignore", ex);
        } catch (IllegalArgumentException ex) {
            Log.d(TAG,"gps provider does not exist" + ex.getMessage());
        }
    }

    @Override
    public void onDestroy() {
        Log.e(TAG,"onDestroy");
        super.onDestroy();
        if (mLocationManager != null) {
            for (int i = 0; i < mLocationListeners.length; i++) {
                try {
                    mLocationManager.removeUpdates(mLocationListeners[i]);
                } catch (Exception ex) {
                    Log.i(TAG,"fail to remove location listners, ignore", ex);
                }
            }
        }
    }

    private void initializeLocationManager() {
        Log.e(TAG,"initializeLocationManager");
        if (mLocationManager == null) {
            mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
        }
    }
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
public class GPSService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener {
    private LocationRequest mLocationRequest;
    private GoogleApiClient mGoogleApiClient;
    private static final String LOGSERVICE ="#######";

    @Override
    public void onCreate() {
        super.onCreate();
        buildGoogleApiClient();
        Log.i(LOGSERVICE,"onCreate");

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(LOGSERVICE,"onStartCommand");

        if (!mGoogleApiClient.isConnected())
            mGoogleApiClient.connect();
        return START_STICKY;
    }


    @Override
    public void onConnected(Bundle bundle) {
        Log.i(LOGSERVICE,"onConnected" + bundle);

        Location l = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
        if (l != null) {
            Log.i(LOGSERVICE,"lat" + l.getLatitude());
            Log.i(LOGSERVICE,"lng" + l.getLongitude());

        }

        startLocationUpdate();
    }

    @Override
    public void onConnectionSuspended(int i) {
        Log.i(LOGSERVICE,"onConnectionSuspended" + i);

    }

    @Override
    public void onLocationChanged(Location location) {
        Log.i(LOGSERVICE,"lat" + location.getLatitude());
        Log.i(LOGSERVICE,"lng" + location.getLongitude());
        LatLng mLocation = (new LatLng(location.getLatitude(), location.getLongitude()));
        EventBus.getDefault().post(mLocation);

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(LOGSERVICE,"onDestroy - Estou sendo destruido");

    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.i(LOGSERVICE,"onConnectionFailed");

    }

    private void initLocationRequest() {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(5000);
        mLocationRequest.setFastestInterval(2000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

    }

    private void startLocationUpdate() {
        initLocationRequest();

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
    }

    private void stopLocationUpdate() {
        LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);

    }

    protected synchronized void buildGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addOnConnectionFailedListener(this)
                .addConnectionCallbacks(this)
                .addApi(LocationServices.API)
                .build();
    }

}


所有这些答案都不起作用从M到Android"O" - 8,由于Dozer模式限制了服务 - 无论什么服务或任何需要在后台进行离散事物的后台操作都将无法再运行。

因此,该方法将通过BroadCastReciever监听系统FusedLocationApiClient,该系统始终监听位置并且即使在打盹模式下也能工作。

发布链接将毫无意义,请使用广播接收器搜索FusedLocation。

谢谢


只是补充,我实现了这种方式,通常在我的Service类中工作

在我的服务中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Override
public void onCreate()
{
    mHandler = new Handler(Looper.getMainLooper());
    mHandler.post(this);
    super.onCreate();
}

@Override
public void onDestroy()
{
    mHandler.removeCallbacks(this);    
    super.onDestroy();
}

@Override
public void run()
{
    InciarGPSTracker();
}

这是我的解决方案

Step1在清单中注册Serice

1
2
3
4
5
6
7
<receiver
    android:name=".MySMSBroadcastReceiver"
    android:exported="true">
    <intent-filter>
       
    </intent-filter>
</receiver>

Step2服务代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
public class FusedLocationService extends Service {

    private String mLastUpdateTime = null;

    // bunch of location related apis
    private FusedLocationProviderClient mFusedLocationClient;
    private SettingsClient mSettingsClient;
    private LocationRequest mLocationRequest;
    private LocationSettingsRequest mLocationSettingsRequest;
    private LocationCallback mLocationCallback;
    private Location lastLocation;

    // location updates interval - 10sec
    private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 5000;

    // fastest updates interval - 5 sec
    // location updates will be received if another app is requesting the locations
    // than your app can handle
    private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 500;
    private DatabaseReference locationRef;
    private int notificationBuilder = 0;
    private boolean isInitRef;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.log("LOCATION GET DURATION","start in service");
        init();
        return START_STICKY;
    }

    /**
     * Initilize Location Apis
     * Create Builder if Share location true
     */
    private void init() {
        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
        mSettingsClient = LocationServices.getSettingsClient(this);
        mLocationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                super.onLocationResult(locationResult);
                receiveLocation(locationResult);
            }
        };

        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
        mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
        builder.addLocationRequest(mLocationRequest);
        mLocationSettingsRequest = builder.build();
        startLocationUpdates();
    }

    /**
     * Request Location Update
     */
    @SuppressLint("MissingPermission")
    private void startLocationUpdates() {
        mSettingsClient
                .checkLocationSettings(mLocationSettingsRequest)
                .addOnSuccessListener(locationSettingsResponse -> {
                    Log.log(TAG,"All location settings are satisfied. No MissingPermission");

                    //noinspection MissingPermission
                    mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
                })
                .addOnFailureListener(e -> {
                    int statusCode = ((ApiException) e).getStatusCode();
                    switch (statusCode) {
                        case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                            Log.loge("Location settings are not satisfied. Attempting to upgrade" +"location settings");
                            break;
                        case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                            Log.loge("Location settings are inadequate, and cannot be" +"fixed here. Fix in Settings.");
                    }
                });
    }

    /**
     * onLocationResult
     * on Receive Location  share to other activity and save if save true
     *
     * @param locationResult
     */
    private void receiveLocation(LocationResult locationResult) {
        lastLocation = locationResult.getLastLocation();

        LocationInstance.getInstance().changeState(lastLocation);

        saveLocation();
    }

    private void saveLocation() {
        String saveLocation = getsaveLocationStatus(this);

        if (saveLocation.equalsIgnoreCase("true") && notificationBuilder == 0) {
            notificationBuilder();
            notificationBuilder = 1;
        } else if (saveLocation.equalsIgnoreCase("false") && notificationBuilder == 1) {
            ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).cancel(1);
            notificationBuilder = 0;
        }

        Log.logd("receiveLocation : Share :-" + saveLocation +", [Lat" + lastLocation.getLatitude() +", Lng" + lastLocation.getLongitude() +"], Time :-" + mLastUpdateTime);

        if (saveLocation.equalsIgnoreCase("true") || getPreviousMin() < getCurrentMin()) {
            setLatLng(this, lastLocation);

            mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());

            if (isOnline(this) && !getUserId(this).equalsIgnoreCase("")) {
                if (!isInitRef) {
                    locationRef = getFirebaseInstance().child(getUserId(this)).child("location");
                    isInitRef = true;
                }
                if (isInitRef) {
                    locationRef.setValue(new LocationModel(lastLocation.getLatitude(), lastLocation.getLongitude(), mLastUpdateTime));
                }
            }
        }
    }

    private int getPreviousMin() {
        int previous_min = 0;
        if (mLastUpdateTime != null) {
            String[] pretime = mLastUpdateTime.split(":");
            previous_min = Integer.parseInt(pretime[1].trim()) + 1;

            if (previous_min > 59) {
                previous_min = 0;
            }
        }
        return previous_min;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopLocationUpdates();
    }

    /**
     * Remove Location Update
     */
    public void stopLocationUpdates() {
        mFusedLocationClient
                .removeLocationUpdates(mLocationCallback)
                .addOnCompleteListener(task -> Log.logd("stopLocationUpdates :"));
    }

    private void notificationBuilder() {
        if (Build.VERSION.SDK_INT >= 26) {
            String CHANNEL_ID ="my_channel_01";
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID,"Channel human readable title",
                    NotificationManager.IMPORTANCE_DEFAULT);

            ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);

            Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                    .setContentTitle("")
                    .setContentText("").build();

            startForeground(1, notification);
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

第3步

1
2
3
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

第4步

1
implementation 'com.google.android.gms:play-services-location:16.0.0'

好吧,我已经通过在服务的onCreate上创建一个处理程序并通过那里调用gps函数来解决它。

代码就像这样简单:

1
final handler=new Handler(Looper.getMainLooper());

然后强制在UI上运行东西,我在其上调用post