【问题标题】:Android location updates in a Service服务中的 Android 位置更新
【发布时间】:2013-02-25 12:03:45
【问题描述】:

我想做这样的事情:

  • 当我的应用程序启动时,我想启动一个服务来检查我的位置

  • 当应用程序进入后台时,我想停止服务

我有两个主要问题:

  1. 如何检测我的应用程序进入后台?我有几个活动,我在 MainActivity 中尝试了覆盖 onPause,但是当我开始其他活动时也会调用 onPause。

  2. 这个问题更重要:我的服务应该如何检查我的位置?我尝试了几种方法,但都没有成功。

我的服务看起来像这样,但它不起作用。我应该改变什么才能让它工作?

package com.pivoscore.service;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;

public class LocationService extends Service {

    private LocationListener locationListener;

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

    @Override
    public int onStartCommand(final Intent intent, final int flags, final int startId) {
        super.onStartCommand(intent, flags, startId);
        return Service.START_STICKY;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        final LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
        this.locationListener = new MyLocationListener();
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 100, 0, this.locationListener);
    }

    private static class MyLocationListener implements LocationListener {

        @Override
        public void onLocationChanged(final Location location) {
        }

        @Override
        public void onProviderDisabled(final String provider) {
        }

        @Override
        public void onProviderEnabled(final String provider) {
        }

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

    }

}

【问题讨论】:

  • onResume() 方法,让服务搜索Location Information 和onPause() 方法移除Location。
  • 我想在几个活动中使用我的位置,而不仅仅是在主要活动中。所以在 onPause 中停止服务是不明智的,因为如果有其他活动出现在前面,onPause 将被调用,我将停止获取位置更新。
  • android.permission.ACCESS_COARSE_LOCATION android.permission.ACCESS_FINE_LOCATION android.permission.ACCESS_NETWORK_STATE 你有没有在你的清单文件中添加这些权限?

标签: android location android-service


【解决方案1】:

这将帮助您确定您的要求是什么 但不要忘记添加我在评论中添加的权限 并且不要忘记在清单文件中添加服务标签 代码片段正在关注

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();        
    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, listener);
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 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);          
            /*final Geocoder geocoder = new Geocoder(getApplicationContext(), Locale.getDefault());         
            String Text = "";
            try {
                List<Address> addresses = geocoder.getFromLocation(loc.getLatitude(), loc.getLongitude(), 1);                
                Text = "My current location is: "+addresses.get(0).getAddressLine(0); 

            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                Text = "My current location is: " +"Latitude = " + loc.getLatitude() + ", Longitude = " + loc.getLongitude();  
            }
            */
            //Toast.makeText( getApplicationContext(), "Location polled to server", Toast.LENGTH_SHORT).show();
        }                               
    }

    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();
    }


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

    }

}

【讨论】:

  • 感谢您的出色回答。我只需将以下代码添加到我的 AndroidManifest.xml 就可以从活动启动服务:&lt;service android:enabled="true" android:name=".LocationService"/&gt;
  • oreo 8.0 版自动销毁
【解决方案2】:
  1. 应用程序不是 Android 中的可视组件。它分为活动,每个活动在可见时运行,在其他情况下暂停和销毁。因此,没有整个 Application 进入后台的概念,Activity 根据其各自的可见性暂停和恢复,并且在此问题上完全独立于其他 Activity。

  2. 您的服务应在其onCreate() 中向位置管理器注册,并在其onDestroy() 中取消注册。在其onBind() 中,它应该返回一个Messenger 对象。而且,在onLocationChanged() 中,它应该通过其共享的Messenger 发送消息。无需使用START_STICKY,因为您不希望 Service 一直运行。

  3. Activity(可以是App中的任何Activity)只需要在它的onStart()中调用bindService(),如果还没有启动服务,Activity就会从服务中得到一个Messenger。此外,Activity 应该从其onStop() 调用unbindService()。当没有任何绑定时,服务将自动停止。

  4. 如果您需要在应用程序(任务)级别执行第 3 点中的内容,请实现 Application 类,并使用其 onCreate()onTerminate()。应用程序类不会像 Activity 那样暂停或停止。

【讨论】:

  • 如何检测到我的应用程序进入后台?我从来没有说过任何活动会进入后台。但这已经不重要了,因为我的第一个问题已经解决了。
  • Android 中没有 Visible Application 组件。如果您的任何 Activity 可见,则 App 正在运行,否则,App 将停止,甚至可能被销毁。不过,您可以使用第 4 点。
【解决方案3】:

建议你使用google提供的最新位置api(也兼容2.2版本)。

这里有一个例子展示了如何使用它: https://github.com/chenjishi/android_location_demo

当您的应用运行到后台时,您可以调用 disconnect 来停止位置更新。

【讨论】:

    【解决方案4】:

    试试这个代码.. 通过使用这个你可以找到你的应用程序是在前台还是后台。希望这会帮助你。

    try {
        foreground = new ForegroundCheckTask().execute(ctx).get();
    }
    
    ======================================
    
    
    class ForegroundCheckTask extends AsyncTask<Context, Void, Boolean> {
    
    @Override
    protected Boolean doInBackground(Context... params) {
        final Context context = params[0].getApplicationContext();
        return isAppOnForeground(context);
    }
    
    private boolean isAppOnForeground(Context context) {
        ActivityManager activityManager = (ActivityManager) context
                .getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningAppProcessInfo> appProcesses = activityManager
                .getRunningAppProcesses();
        if (appProcesses == null) {
            return false;
        }
        final String packageName = context.getPackageName();
    
    
        String activePackageName = activityManager.getRunningTasks(1).get(0).topActivity.getPackageName();
        if (activePackageName.equals(packageName)) {
            return true;
        }
        else{
            return false;
        }
    
    
    }
    
    }
    

    【讨论】:

    • ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION 用于以后的位置代码仅此而已,只需记住将每个服务添加到您的 AndroidManifest 中
    • 没有权限..只需使用上下文就可以了..前景是一个布尔值..ctx是上下文..使用它并让我知道你的cmets。
    • 好的。我的服务的问题是我不能在模拟器中使用 NETWORK_PROVIDER。所以这是我的错误。对不起。它适用于我的手机。
    • k...您也可以在您的模拟器中测试网络提供商。转到 DMS-> 选择特定的模拟器-> 转到模拟器控件-> 因为您将拥有位置控制。根据你改变坐标..然后发送它..现在你的模拟器将提供位置..
    猜你喜欢
    • 2017-01-24
    • 1970-01-01
    • 2011-10-03
    • 2015-08-23
    • 1970-01-01
    • 2018-05-08
    • 2012-11-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多