Фонова служба з прослуховувачем місцезнаходження в android


76

Я створюю фонову службу, яка працюватиме у своєму власному процесі. Це повинно дозволити мені слухати, якщо місце розташування пристрою змінилося. Я мав би змогу змінити критерії, такі як відстань, яку пройшов перед тим, як повідомити інтерфейс.

Як я можу зробити те саме? Я трохи знаю про обслуговування та LocationListenerвпровадження. Будемо вдячні за будь-які підручники в мережі.

Я отримав одне зворотне посилання із переповнення стека, але я не розумів його багато.


2
Перегляньте цю публікацію в блозі: android-developers.blogspot.ro/2011/06/…
Фелікс

Дивіться останній метод GoogleApiClient stackoverflow.com/a/41981246/3496570
AndroidGeek

Відповіді:


116

Спочатку потрібно створити Service. У цьому Serviceстворіть клас, що розширюється LocationListener. Для цього використовуйте такий фрагмент коду Service:

public class LocationService extends Service {
public static final String BROADCAST_ACTION = "Hello World";
private static final int TWO_MINUTES = 1000 * 60 * 2;
public LocationManager locationManager;
public MyLocationListener listener;
public Location previousBestLocation = null;

Intent intent;
int counter = 0;

@Override
public void onCreate() {
    super.onCreate();
    intent = new Intent(BROADCAST_ACTION);
}

@Override
public void onStart(Intent intent, int startId) {
    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    listener = new MyLocationListener();
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 4000, 0, (LocationListener) listener);
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 4000, 0, listener);
}

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

protected boolean isBetterLocation(Location location, Location currentBestLocation) {
    if (currentBestLocation == null) {
        // A new location is always better than no location
        return true;
    }

    // Check whether the new location fix is newer or older
    long timeDelta = location.getTime() - currentBestLocation.getTime();
    boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
    boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
    boolean isNewer = timeDelta > 0;

    // If it's been more than two minutes since the current location, use the new location
    // because the user has likely moved
    if (isSignificantlyNewer) {
        return true;
        // If the new location is more than two minutes older, it must be worse
    } else if (isSignificantlyOlder) {
        return false;
    }

    // Check whether the new location fix is more or less accurate
    int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
    boolean isLessAccurate = accuracyDelta > 0;
    boolean isMoreAccurate = accuracyDelta < 0;
    boolean isSignificantlyLessAccurate = accuracyDelta > 200;

    // Check if the old and new location are from the same provider
    boolean isFromSameProvider = isSameProvider(location.getProvider(),
            currentBestLocation.getProvider());

    // Determine location quality using a combination of timeliness and accuracy
    if (isMoreAccurate) {
        return true;
    } else if (isNewer && !isLessAccurate) {
        return true;
    } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
        return true;
    }
    return false;
}



/** Checks whether two providers are the same */
private boolean isSameProvider(String provider1, String provider2) {
    if (provider1 == null) {
        return provider2 == null;
    }
    return provider1.equals(provider2);
}



@Override
public void onDestroy() {
    // handler.removeCallbacks(sendUpdatesToUI);     
    super.onDestroy();
    Log.v("STOP_SERVICE", "DONE");
    locationManager.removeUpdates(listener);
}

public static Thread performOnBackgroundThread(final Runnable runnable) {
    final Thread t = new Thread() {
        @Override
        public void run() {
            try {
                runnable.run();
            } finally {

            }
        }
    };
    t.start();
    return t;
}
public class MyLocationListener implements LocationListener
{

    public void onLocationChanged(final Location loc)
    {
        Log.i("*****", "Location changed");
        if(isBetterLocation(loc, previousBestLocation)) {
            loc.getLatitude();
            loc.getLongitude();
            intent.putExtra("Latitude", loc.getLatitude());
            intent.putExtra("Longitude", loc.getLongitude());
            intent.putExtra("Provider", loc.getProvider());
            sendBroadcast(intent);

        }
    }

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

    }

    public void onProviderDisabled(String provider)
    {
        Toast.makeText( getApplicationContext(), "Gps Disabled", Toast.LENGTH_SHORT ).show();
    }


    public void onProviderEnabled(String provider)
    {
        Toast.makeText( getApplicationContext(), "Gps Enabled", Toast.LENGTH_SHORT).show();
    }
}

Додайте це Serviceде завгодно у свій проект, як завгодно! :)


5
Зверніть увагу: цей код, схоже, може бути отриманий із проекту GPL’d (або, можливо, з цього ліцензованого проекту MIT. Хтось знає статус ліцензії вищезазначеного коду?
Інактивіст,

@Nilanchala, якщо це працює для вас, ніж позначте це правильно, щоб я міг допомогти іншим, хто має таку проблему
Usman Kurd

11
для чого потрібна функція "performOnBackgroundThread"? це десь використовується?
Martin Mlostek 05.03.14

2
Оскільки Служби Google Play включають служби локації, доцільно використовувати їх замість цього: github.com/nickfox/GpsTracker/blob/master/phoneClients/android/…
Нірмал,

3
Використовуйте onStartCommand () замість onStart () і поверніть START_STICKY. Наведений вище код також не запускатиметься в окремому процесі (для них існують різні рішення), тому всякий раз, коли додаток буде вбито (переважно після переходу у фоновий режим) системою Android, Служба зупинятиметься - хоча вона почнеться знову, якщо будуть доступні ресурси завдяки START_STICKY. Існують також різні рішення, щоб підтримати Службу живою, коли програма у фоновому режимі.
Darek Deoniziak

13

Я знаю, що публікую цю відповідь трохи пізно, але я відчув, що варто скористатися послугою постачальника розташування запобіжників Google, щоб отримати поточне місцезнаходження.

Основними особливостями цього API є:

1.Прості API: дозволяє вибрати рівень точності, а також енергоспоживання.

2.Одразу доступний: надає вашим програмам негайний доступ до найкращого, останнього місця.

3.Енергоефективність: він вибирає найефективніший спосіб отримати місце з меншим споживанням енергії

4.Універсальність: відповідає широкому колу потреб, від використання на передньому плані, яке потребує високоточного розташування, до фонового використання, яке потребує періодичного оновлення місцезнаходження з незначним впливом енергії.

Він гнучкий при оновленні в місці також. Якщо ви хочете, щоб поточне місцезнаходження було лише тоді, коли програма запускається, тоді ви можете використовувати getLastLocation(GoogleApiClient)метод.

Якщо ви хочете постійно оновлювати своє місцезнаходження, ви можете використовувати requestLocationUpdates(GoogleApiClient,LocationRequest, LocationListener)

Ви можете знайти дуже приємний блог про розташування запобіжників тут, а Google doc про розташування запобіжників - також тут .

Оновлення

Згідно з документами розробників, починаючи з Android O, вони додали нові обмеження щодо фонового розташування.

Якщо ваша програма працює у фоновому режимі, служба системи визначення місцезнаходження обчислює нове місце для вашої програми лише кілька разів на годину. Це має місце навіть тоді, коли ваш додаток вимагає частішого оновлення місцезнаходження. Однак якщо ваш додаток працює на передньому плані, частота дискретизації місцеположення не змінюється порівняно з Android 7.1.1 (рівень API 25).


1
Я думаю, ви маєте рацію, але якийсь користувацький Rom видалив службу Google Play, тому ви не можете використовувати постачальника розташування запобіжників.
Чень

2
Якщо ви просто хочете приблизно знати, де ви перебуваєте в певний час, або для менш точного відстеження, FusedLocationProviderце нормально, але для додатків, які вимагають відстеження з високою точністю, це просто недостатньо
StuStirling

2
Рішенням для цих користувацьких ромів є використання LOST від Mapzen. Пропонує ті самі функції, що й FusedLocationProviderAPI від Google, без необхідності реєструватися в сервісі Google Play
Адріан С.

1
Як я можу відстежувати маршрут користувача в запущеному додатку в android Oreo, якщо він може оновлювати місцезнаходження лише кілька разів щогодини?
Makalele

8

Служба фонового розташування. Він буде перезапущений навіть після вбивства програми.

MainActivity.java

public class MainActivity extends AppCompatActivity {
    AlarmManager alarmManager;
    Button stop;
    PendingIntent pendingIntent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (alarmManager == null) {
            alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
            Intent intent = new Intent(this, AlarmReceive.class);
            pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
            alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 30000,
                    pendingIntent);
        }
    }
}

BookingTrackingService.java

public class BookingTrackingService extends Service implements LocationListener {

    private static final String TAG = "BookingTrackingService";
    private Context context;
    boolean isGPSEnable = false;
    boolean isNetworkEnable = false;
    double latitude, longitude;
    LocationManager locationManager;
    Location location;
    private Handler mHandler = new Handler();
    private Timer mTimer = null;
    long notify_interval = 30000;

    public double track_lat = 0.0;
    public double track_lng = 0.0;
    public static String str_receiver = "servicetutorial.service.receiver";
    Intent intent;

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

    @Override
    public void onCreate() {
        super.onCreate();

        mTimer = new Timer();
        mTimer.schedule(new TimerTaskToGetLocation(), 5, notify_interval);
        intent = new Intent(str_receiver);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        this.context = this;


        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy <<");
        if (mTimer != null) {
            mTimer.cancel();
        }
    }

    private void trackLocation() {
        Log.e(TAG, "trackLocation");
        String TAG_TRACK_LOCATION = "trackLocation";
        Map<String, String> params = new HashMap<>();
        params.put("latitude", "" + track_lat);
        params.put("longitude", "" + track_lng);

        Log.e(TAG, "param_track_location >> " + params.toString());

        stopSelf();
        mTimer.cancel();

    }

    @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) {

    }

    /******************************/

    private void fn_getlocation() {
        locationManager = (LocationManager) getApplicationContext().getSystemService(LOCATION_SERVICE);
        isGPSEnable = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        isNetworkEnable = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

        if (!isGPSEnable && !isNetworkEnable) {
            Log.e(TAG, "CAN'T GET LOCATION");
            stopSelf();
        } else {
            if (isNetworkEnable) {
                location = null;
                locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 0, this);
                if (locationManager != null) {
                    location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                    if (location != null) {

                        Log.e(TAG, "isNetworkEnable latitude" + location.getLatitude() + "\nlongitude" + location.getLongitude() + "");
                        latitude = location.getLatitude();
                        longitude = location.getLongitude();
                        track_lat = latitude;
                        track_lng = longitude;
//                        fn_update(location);
                    }
                }
            }

            if (isGPSEnable) {
                location = null;
                locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, this);
                if (locationManager != null) {
                    location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                    if (location != null) {
                        Log.e(TAG, "isGPSEnable latitude" + location.getLatitude() + "\nlongitude" + location.getLongitude() + "");
                        latitude = location.getLatitude();
                        longitude = location.getLongitude();
                        track_lat = latitude;
                        track_lng = longitude;
//                        fn_update(location);
                    }
                }
            }

            Log.e(TAG, "START SERVICE");
            trackLocation();

        }
    }

    private class TimerTaskToGetLocation extends TimerTask {
        @Override
        public void run() {

            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    fn_getlocation();
                }
            });

        }
    }

//    private void fn_update(Location location) {
//
//        intent.putExtra("latutide", location.getLatitude() + "");
//        intent.putExtra("longitude", location.getLongitude() + "");
//        sendBroadcast(intent);
//    }
}

AlarmReceive.java (BroadcastReceiver)

public class AlarmReceive extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.e("Service_call_"  , "You are in AlarmReceive class.");
        Intent background = new Intent(context, BookingTrackingService.class);
//        Intent background = new Intent(context, GoogleService.class);
        Log.e("AlarmReceive ","testing called broadcast called");
        context.startService(background);
    }
}

AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

 <service
            android:name=".ServiceAndBroadcast.BookingTrackingService"
            android:enabled="true" />

        <receiver
            android:name=".ServiceAndBroadcast.AlarmReceive"
            android:exported="false">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

if (isNetworkEnable) {if (!isNetworkEnable) {в іншому випадку це може бути відсутнім НЕ. ;)
Шайлендра Мадда

1
Крім того, потрібно перевірити наявність дозволів. if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return;}
Шайлендра Мадда,

Мені вдалося отримати місцезнаходження, коли додаток працював за допомогою цього коду, але коли додаток було вбито, це не спрацювало, я намагаюся оновити місцезнаходження користувача в базі даних, навіть коли додаток вбито
Mandeep Kumar

1
У нових версіях Android для безперервної роботи служби визначення місцезнаходження потрібно безліч дозволів. Цей простий сервіс не працює, я впевнений у цьому
М. Усман Хан,

1
Погодьтеся з @ M.UsmanKhan, оскільки в останніх версіях Android startService ніколи не буде тримати програму у фоновому режимі. Всім матеріалам потрібно було використовувати службу на передньому плані та підтримувати роботу програми через це. Детальніше - developer.android.com/about/versions/oreo/background#services
Анудж Рагуванші

2

Дуже просто не потрібно створювати клас, розширює LocationListener 1- Змінна

private LocationManager mLocationManager;
private LocationListener mLocationListener;
private static double currentLat =0;
private static double currentLon =0;

2- onStartService ()

@Override public void onStartService() {
    addListenerLocation();
}

3- Метод addListenerLocation ()

 private void addListenerLocation() {
    mLocationManager = (LocationManager)
            getSystemService(Context.LOCATION_SERVICE);
    mLocationListener = new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            currentLat = location.getLatitude();
            currentLon = location.getLongitude();

            Toast.makeText(getBaseContext(),currentLat+"-"+currentLon, Toast.LENGTH_SHORT).show();

        }

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

        @Override
        public void onProviderEnabled(String provider) {
            Location lastKnownLocation = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
            if(lastKnownLocation!=null){
                currentLat = lastKnownLocation.getLatitude();
                currentLon = lastKnownLocation.getLongitude();
            }

        }

        @Override
        public void onProviderDisabled(String provider) {
        }
    };
    mLocationManager.requestLocationUpdates(
            LocationManager.GPS_PROVIDER, 500, 10, mLocationListener);
}

4- onDestroy ()

@Override
public void onDestroy() {
    super.onDestroy();
    mLocationManager.removeUpdates(mLocationListener);
}

Чомусь оновлення місцезнаходження відбувається лише тоді, коли переглядається програма ...
Девід Калланан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.