Android应用添加地理位置并在同一服务中接收意图

时间:2016-12-23 03:50:28

标签: android geofencing android-geofence

我正在尝试构建一个地理围栏应用程序,但它似乎只在主要活动开始时注册地理围栏,并且意图服务在应用程序关闭时停止接收它们。因此,我将添加地理围栏逻辑移动到意图服务(以及意图处理代码)并确保服务启动,但现在服务根本没有收到任何意图!

服务定义

public class GeofenceTransitionsIntentService extends IntentService implements ConnectionCallbacks, OnConnectionFailedListener, ResultCallback<Status>

服务中的所有内容(构建和连接谷歌api客户端)都在onCreate完成,目标处理程序和地理围栏注册内容onConnected注册地理围栏等。基本上,我已经尝试过了在旨在处理这些意图的同一服务中实施大量借用的地理围栏示例代码(来自文档)。

所有主要活动都是启动服务并绘制与服务中收到的地理围栏通知相关的内容。

如果您需要更多信息,请告诉我们。

修改

好的,好像我们需要更多信息 - 服务大纲:

public class GeofenceTransitionsIntentService extends IntentService implements ConnectionCallbacks, OnConnectionFailedListener, ResultCallback<Status> {

    protected static final String TAG = "GeofenceTransitionsIS";

    protected GoogleApiClient mGoogleApiClient;
    protected ArrayList<Geofence> mGeofenceList;
    private boolean mGeofencesAdded;
    private PendingIntent mGeofencePendingIntent;
    private SharedPreferences mSharedPreferences;

    public GeofenceTransitionsIntentService() {
        super(TAG);
    }

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

        buildGoogleApiClient();
        populateGeofenceList();
        mGoogleApiClient.connect();

    }

    ...

    @Override
    protected void onHandleIntent(Intent intent) {
        GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
        // handle the intent, send a notification
    }


    private void sendNotification(String notificationDetails) {
        // sends a notification
    }

    @Override
    public void onConnected(Bundle connectionHint)
    {
        LocationServices.GeofencingApi.addGeofences(
                mGoogleApiClient,
                getGeofencingRequest(),
                getGeofencePendingIntent()
        ).setResultCallback(this);
    }

    // straight out of the example
    private GeofencingRequest getGeofencingRequest()
    {
        ...
    }


    // from a branch of the example that reuses the pending intent
    private PendingIntent getGeofencePendingIntent()
    {
        if (mGeofencePendingIntent != null)
        {
            return mGeofencePendingIntent;
        }

        Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
        mGeofencePendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        return mGeofencePendingIntent;
    }

    public void populateGeofenceList() {
        for (thing place : listofplaces) {
            mGeofenceList.add(...)
        }
    }

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

    public void onResult(Status status)
    {
        // were fences added? usually yes
    }
}

我的研究一直令人沮丧 - 我看到人们声称能够通过广播接收器(参见第一条评论)而不是服务来做这样的事情吗?

我有一个非常糟糕的manifest.xml来自我一直在努力的所有修订:

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

<application
    android:allowBackup="true"
    android:label="@string/app_name"
    android:theme="@style/AppTheme">

    <activity
        android:name=".MainActivity"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>

    <service android:name=".GeofenceTransitionsIntentService"
             android:exported="true"
             android:enabled="true">
        <intent-filter >
            <action android:name="com.aol.android.geofence.ACTION_RECEIVE_GEOFENCE"/>
        </intent-filter>
    </service>

    ...

</application>

intent-filterandroid:exported="true"添加到服务定义中都没有帮助。

1 个答案:

答案 0 :(得分:3)

首先,请不要使用IntentService。它的唯一目的是获得单个意图,在后台线程中运行它,然后自行停止。您正在寻找的是Service,因为这会持续一段时间(直到操作系统开始在资源上运行不足)。

第二次,将代码移至服务后,请执行以下操作:

public class GeofenceTransitionsService extends Service implements ConnectionCallbacks, OnConnectionFailedListener, ResultCallback<Status> {
    //Whatever you need to declare
    ....
    GeofencingRequest mRequest;

    //This is only called once per instance of a Service, so use this to instantiate class variables
    @Override
    public void onCreate() {
        super.onCreate();
        buildGoogleApiClient();
        mGoogleApiClient.connect();
    }

    //Every time you call context.startService(Intent intent) after the service is created, 
    //this function gets called with the intent you have given it. You can use this to modify or change the geofence api,
    //passing GeofencingRequests in intents by calling intent.putExtra(...) before sending the intent, and retrieving it here.
    //I just assume you are passing GeofencingRequest objects, since they are pacelable.
    @Override
    public int onStartCommand(Intent intent, int flags, final int startId) {
        mRequest = intent.getParcelableExtra("request"); //Or whatever the key is for your request.
        if(mGoogleApiClient.isConnected()){
            LocationServices.GeofencingApi.addGeofences(
                mGoogleApiClient,
                mRequest,
                getGeofencePendingIntent()
            ).setResultCallback(this);
        }
    }

    @Override
    public void onConnected(Bundle connectionHint)
    {
        LocationServices.GeofencingApi.addGeofences(
            mGoogleApiClient,
            mRequest,
            getGeofencePendingIntent()
        ).setResultCallback(this);
    }

    // from a branch of the example that reuses the pending intent
    private PendingIntent getGeofencePendingIntent()
    {
        if (mGeofencePendingIntent != null)
        {
            return mGeofencePendingIntent;
        }

        mGeofencePendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(this, GoogleGeofenceReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT);
        return mGeofencePendingIntent;
    }

    //The rest of your code
    ....
}

请记住,Android在服务资源不足时会终止您的服务,如果有任何警告则没有太多。如果您需要此服务以更高的优先级运行,我强烈建议您查看starting in the foreground

第三次,现在我们已经进行了服务设置,您可能已经注意到getGeofencePendingIntent()功能现在使用BroadcastReceiver而不是运行它的服务。这是你是如何设置的:

public class GoogleGeofenceReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(final Context context, final Intent intent) {
        GeofencingEvent event = GeofencingEvent.fromIntent(intent);
        ...
        //Do whatever you did in your Service handleIntent function here.
    }
}

第四,您需要修改您的清单,让应用知道应该使用此BroadcastReceiver:

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

<application
    android:allowBackup="true"
    android:label="@string/app_name"
    android:theme="@style/AppTheme">

    <activity
        android:name=".MainActivity"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>

    <service android:name=".GeofenceTransitionsService"
             android:exported="true"
             android:enabled="true">
        <intent-filter >
            <action android:name="com.aol.android.geofence.ACTION_RECEIVE_GEOFENCE"/>
        </intent-filter>
    </service>
    <receiver android:name=".GoogleGeofenceReceiver"/>

    ...

</application>

我不确定你为什么要使用导出和启用标志,但是不需要声明它们,因为默认设置为enabled,导出默认为&#34; true&#34 ;如果你有一个意图过滤器。

我建议您阅读有关活动,服务和BroadcastReceiver生命周期的内容,因为理解这将使您对此项目大有裨益,并让您更好地了解Android的痛苦。