Geofence Android: PendingIntent не запускает IntentService

Я пытаюсь разработать приложение Geofence для Android, которое почти не уведомляет меня, когда я вхожу/выхожу/нахожусь в/из/в Geofence. Несмотря на все вопросы и ответы, которые я краснею, я до сих пор не могу разобраться в своей проблеме.

Я думаю, что что-то не так с моим PendinIntent и/или IntentService. Вот что я сделал до сих пор.

MainActivity.java

package it.coppola.geofencedetecttest1;

import android.app.Dialog;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.ActionBarActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationServices;




public class MainActivity extends ActionBarActivity implements 
ConnectionCallbacks,OnConnectionFailedListener{
    private GoogleApiClient mGoogleApiClient;
    private GeofenceSampleReceiver mGeofenceReceiver;
    private IntentFilter filter;
    private Location mCurrentLocation;
    private PendingIntent mPendingIntent;





    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mGoogleApiClient=new GoogleApiClient.Builder(this)
            .addApi(LocationServices.API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();
        filter=new IntentFilter();
        filter.addAction("it.coppola.geofencedetecttest1.ACTION_GEOFENCES_ERROR");
        filter.addAction("it.coppola.geofencedetecttest1.ACTION_GEOFENCES_SUCCESS");
        mGeofenceReceiver=new GeofenceSampleReceiver();
        LocalBroadcastManager.getInstance(this).registerReceiver(mGeofenceReceiver, filter);


    }



    @Override
    protected void onResume(){
        super.onResume();
        LocalBroadcastManager.getInstance(this).registerReceiver(mGeofenceReceiver, filter);

    }

    @Override
    protected void onPause(){
        super.onPause();
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mGeofenceReceiver);

    }

    @Override
    protected void onStop(){
        super.onStop();

        LocalBroadcastManager.getInstance(this).unregisterReceiver(mGeofenceReceiver);

    }

    @Override
    protected void onDestroy(){
        super.onDestroy();


    }

    public void onConnectToLocation(View v){
//stuff that happens when i press a button. Here is mGoogleApiClient.connect()

     }
    public void onConnected(Bundle connectionHint){


        mCurrentLocation= LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);

        if (mCurrentLocation != null){

            TextView lan=(TextView)findViewById(R.id.txtLan);
            lan.setText(String.valueOf(mCurrentLocation.getLatitude()));
            TextView lon=(TextView)findViewById(R.id.txtLong);
            lon.setText(String.valueOf(mCurrentLocation.getLongitude()));



            Geofence mGeofence1=new Geofence.Builder()
            .setRequestId("Geofence1")
            .setCircularRegion(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude(), 5)
 .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER|Geofence.GEOFENCE_TRANSITION_EXIT|Geofence.GEOFENCE_TRANSITION_DWELL)
            .setExpirationDuration(Geofence.NEVER_EXPIRE)
            .setLoiteringDelay(1000)
            .build();

            mPendingIntent=requestPendingIntent();


            GeofencingRequest mGeofenceRequest=new GeofencingRequest.Builder()
            .addGeofence(mGeofence1)
            .build();


            LocationServices.GeofencingApi.addGeofences(mGoogleApiClient, mGeofenceRequest, mPendingIntent);
        }
        else {

        }


    }



    /**
     * Define a Broadcast receiver that receives updates from connection listeners and
     * the geofence transition service.
     */



    public class GeofenceSampleReceiver extends BroadcastReceiver {
        /*
         * Define the required method for broadcast receivers
         * This method is invoked when a broadcast Intent triggers the receiver
         */
        @Override
        public void onReceive(Context context, Intent intent) {

            // Check the action code and determine what to do
            String action = intent.getAction();
            Log.d("miotag","ho ricevuto questo intent: "+action);
            if (TextUtils.equals(action, "it.coppola.geofencedetecttest1.ACTION_GEOFENCES_ERROR")){
                Log.d("miotag","ho ricevuto un errore dal Location Service");
            }
            else if (TextUtils.equals(action, "it.coppola.geofencedetecttest1.ACTION_GEOFENCES_SUCCESS")){
                Log.d("miotag","intent ricevuto: OK");
            }

        }
    }

    private PendingIntent requestPendingIntent(){

        if (null != mPendingIntent){

            return mPendingIntent;
        } else {


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

        }
    }

    public void stopIt(View v){

        LocationServices.GeofencingApi.removeGeofences(mGoogleApiClient, mPendingIntent);
        Log.d("miotag","geofence rimossa");
        mGoogleApiClient.disconnect();
    }

}

Я пропустил некоторые строки кода, которые не представляют интереса.

вот мой IntentService

package it.coppola.geofencedetecttest1;

import java.util.List;

import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;

import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingEvent;

public class GeofenceReceiverSample extends IntentService{

 public GeofenceReceiverSample(){
        super("GeofenceReceiverSample");
    }

     @Override
        protected void onHandleIntent(Intent intent) {
        GeofencingEvent geoEvent=GeofencingEvent.fromIntent(intent);
         if (geoEvent.hasError()) {
                //todo error process
            } else {
                int transitionType = geoEvent.getGeofenceTransition();
                if (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER ||
                        transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
                    List<Geofence> triggerList = geoEvent.getTriggeringGeofences();

                    for (Geofence geofence : triggerList) {
                        generateNotification(geofence.getRequestId(), "address you defined");
                    }
                }
            }
        }

        private void generateNotification(String locationId, String address) {
            long when = System.currentTimeMillis();
            Intent notifyIntent = new Intent(this, MainActivity.class);
            notifyIntent.putExtra("id", locationId);
            notifyIntent.putExtra("address", address);
            notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);

            NotificationCompat.Builder builder =
                    new NotificationCompat.Builder(this)
                            .setSmallIcon(R.drawable.ic_launcher)
                            .setContentTitle(locationId)
                            .setContentText(address)
                            .setContentIntent(pendingIntent)
                            .setAutoCancel(true)
                            .setDefaults(Notification.DEFAULT_SOUND)
                            .setWhen(when);

            NotificationManager notificationManager =
                    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            notificationManager.notify((int) when, builder.build());
        }
     }

Я только что вставил этот IntentService из enter ссылка на описание здесь с небольшими изменениями. Прямо сейчас я хочу сосредоточиться на IntentService и его обработчике: поэтому на данный момент я не запрашиваю Broadcast Receiver, который будет запускаться из IntentService после уведомления. Вот почему в моей MainActivity не объявлен класс BroadcastReceiver.

Мой AndroidМанифест

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

    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="21" />
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
   <!-- 
    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
    -->
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="it.coppola.geofencedetecttest1.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=".GeofenceReceiverSample" 
        android:exported="false">     
    </service>

      <receiver android:name="it.coppola.geofencedetecttest1.GeofenceSampleReceiver"
        android:exported="false">
        <intent-filter >
            <action android:name="it.coppola.geofencedetecttest1.ACTION_RECEIVE_GEOFENCE"/>
        </intent-filter>
    </receiver>


         <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

    </application>

</manifest>

Еще несколько замечаний: я действительно не знаю, почему, но пару раз приложение действительно работало: мой IntentService запускался из намерения службы Google Play и выполнял предыдущую версию кода. Как ни странно, когда я снова запустил то же приложение без каких-либо изменений в коде, IntentService не запустился.

Я разрабатываю свой планшет / смартфон в качестве устройства эмулятора: я пытался ходить, но не повезло.

Любая помощь очень ценится.

Спасибо.


person AntCopp    schedule 09.01.2015    source источник
comment
Является ли mCurrentLocation null? Похоже, что ведение журнала было бы полезно при отладке любых проблем.   -  person ianhanniballake    schedule 09.01.2015
comment
Нет, он возвращается как задумано. Я использую его, чтобы показать на экране фактическую широту и долготу, которые затем передаются в качестве аргумента для Geofence. Я опустил код, потому что я думал, что это не важно. Какая регистрация вам нужна? Извините, я новичок, но я опубликую все, что вы просите   -  person AntCopp    schedule 09.01.2015
comment
5 м — это очень маленький радиус (большинство приемников GPS рассчитаны на точность 8–15 м). Пробовали ли вы использовать больший радиус?   -  person ianhanniballake    schedule 09.01.2015
comment
Я установил интервал между радиусом = 5,10,15,100 с различными настройками для .setExpirationDuration()= 1 минута, .setLoiteringDelay()=5 секунд, .setNotificationResponsiveness()=10 секунд, играя с этими числами, чтобы увидеть, изменится ли что-то. Ничего, поэтому я решил придерживаться NEVER_EXPIRE, думая, что это лучше для тестирования.   -  person AntCopp    schedule 09.01.2015
comment
@ianhanniballake Не могли бы вы взглянуть на этот вопрос, пожалуйста?   -  person Skizo-ozᴉʞS    schedule 04.10.2015


Ответы (1)


Следуя ответу, предоставленному ianhanniballake, я провел больше тестов с радиусом, равным 20-30-40 метрам, и Выяснил, что все работает как задумано. Как он сказал, моя проблема заключалась в том, что настройки радиуса слишком малы, чтобы GPS мог распознать собственное положение.

Искренне спасибо.

person AntCopp    schedule 10.01.2015
comment
Не могли бы вы взглянуть на этот вопрос, пожалуйста? - person Skizo-ozᴉʞS; 04.10.2015