1
votes

L'emplacement est vide au départ

Je recadre ma dernière question, qui reste sans réponse, et j'ai réécrit le problème en suivant Google's BasicLocation .

Mon activité principale est définie comme:

E/MainActivity: Latit: 37.42342342342342

avec latlang. [Lat, Lang] est dans un fichier séparé :

 I/System.out: Position:0
 I/System.out: Position:1
 I/System.out: Position:2

et le fichier de localisation, qui est le premier fragment du visualiseur est défini comme:

I/System.out: location  null
 I/Google Maps Android API: Google Play services package version: 17785022
 I/Choreographer: Skipped 31 frames!  The application may be doing too much work on its main thread.
 I/System.out: Position:0
 I/System.out: Position:1
 I/System.out: Position:2
 I/zygote: Do full code cache collection, code=202KB, data=177KB
 I/zygote: After code cache collection, code=129KB, data=91KB
 I/zygote: JIT allocated 56KB for compiled code of void android.view.View.<init>(android.content.Context, android.util.AttributeSet, int, int)
 I/zygote: Background concurrent copying GC freed 44415(2MB) AllocSpace objects, 7(136KB) LOS objects, 49% free, 3MB/6MB, paused 294us total 102.458ms
 I/System.out: Position:3
 I/System.out: Position:4
 I/zygote: Do partial code cache collection, code=193KB, data=126KB
 I/zygote: After code cache collection, code=193KB, data=126KB
 I/zygote: Increasing code cache capacity to 1024KB
 I/zygote: JIT allocated 71KB for compiled code of void android.widget.TextView.<init>(android.content.Context, android.util.AttributeSet, int, int)
 I/zygote: Compiler allocated 4MB to compile void android.widget.TextView.<init>(android.content.Context, android.util.AttributeSet, int, int)
 E/MainActivity: Latit: 37.42342342342342

Le problème avec cela est évident à partir du logcat:

public class SunFragment extends Fragment {

    List<SunSession> sunsList;
    Typeface sunfont;


    //to be called by the MainActivity
    public SunFragment() {
        // Required empty public constructor
    }

    // Keys for storing activity state.
//  private static final String KEY_CAMERA_POSITION = "camera_position";
    private static final String KEY_LOCATION_NAME = "location_name";
    public String location;//="No location name found";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Retrieve location and camera position from saved instance state.
        if (savedInstanceState != null) {
            location = savedInstanceState.getCharSequence(KEY_LOCATION_NAME).toString();
            System.out.println("OnCreate location  "+location);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View rootView = inflater.inflate(R.layout.fragment_sun, container, false);
        onSaveInstanceState(new Bundle());
        //SecondFragment secondFragment = new SecondFragment();
        //secondFragment.getDeviceLocation();

        RecyclerView rv = rootView.findViewById(R.id.rv_recycler_view);
        rv.setNestedScrollingEnabled(false);
        rv.setHasFixedSize(true);
        //MyAdapter adapter = new MyAdapter(new String[]{"Today", "Golden Hour", "Blue Hour", "Civil Twilight", "Nautical Twilight", "Astronomical Twilight", "Hello", "World"});
        //rv.setAdapter(adapter);
        LinearLayoutManager llm = new LinearLayoutManager(getActivity());
        rv.setLayoutManager(llm);
        System.out.println("location  "+location);



   /*
     Reversegeocoding location
     */
        String location="No location name found";
        String errorMessage = "";
        List<Address> addresses = null;

        Geocoder geocoder = new Geocoder(getContext(), Locale.getDefault());
        try {
            addresses = geocoder.getFromLocation(
                    latlang.Lat,
                    latlang.Lang,
                    1);
        } catch (IOException ioException) {
            // Catch network or other I/O problems.
            errorMessage = getString(R.string.service_not_available);
            // Log.e(TAG, errorMessage, ioException);
            if (getView() != null){
                Snackbar.make(getView(), errorMessage, Snackbar.LENGTH_LONG).show();
            }
        } catch (IllegalArgumentException illegalArgumentException) {
            // Catch invalid latitude or longitude values.
            errorMessage = getString(R.string.invalid_lat_long_used);
            if (getView() != null){
                Snackbar.make(getView(),
                        "Illegal Latitude = " + latlang.Lat + ", Longitude = " +
                                latlang.Lang, Snackbar.LENGTH_LONG).show();
            }
        }
        if (addresses == null || addresses.size() == 0) {
            if (errorMessage.isEmpty()) {
                System.out.println("Adress Empty No Address Found");// Snackbar.LENGTH_LONG).show();
                location = "Lat:"+latlang.Lat+" Lang: "+latlang.Lang;
            }
        } else {
            location = addresses.get(0).getAddressLine(0);//+", "+ addresses.get(0).getLocality();
        /* for(int i = 0; i <= addresses.get(0).getMaxAddressLineIndex(); i++) {
          location = addresses.get(0).getAddressLine(i);
        }*/
        }

Cela montre, au début, l'emplacement est nul,

I / System.out: emplacement nul

puis la vue de recyclage du sunfragment est créée

public class latlang {
    public static double Lat;
    public static double Lang;
}

et après cela, j'obtiens l'emplacement:

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {
//    private LocationCallback locationCallback;
//     private FusedLocationProviderClient mFusedLocationClient;
    private FusedLocationProviderClient mFusedLocationClient;
    protected Location mLastLocation;
    private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;
    private static final String TAG = MainActivity.class.getSimpleName();



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.drawer_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
        SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());
        ViewPager viewPager = findViewById(R.id.view_pager);
        viewPager.setAdapter(sectionsPagerAdapter);
        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        NavigationView navigationView = findViewById(R.id.nav_view);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.addDrawerListener(toggle);
        toggle.syncState();
        navigationView.setNavigationItemSelectedListener(this);

        ImageButton leftNav = findViewById(R.id.left_nav);
        ImageButton rightNav = findViewById(R.id.right_nav);
        leftNav.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int tab = viewPager.getCurrentItem();
                if (tab > 0) {
                    tab--;
                    viewPager.setCurrentItem(tab);
                } else if (tab == 0) {
                    viewPager.setCurrentItem(tab);
                }
            }
        });

        rightNav.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int tab = viewPager.getCurrentItem();
                tab++;
                viewPager.setCurrentItem(tab);
            }
        });

    }
    @Override
    public void onStart() {
        super.onStart();
        if (!checkPermissions()) {
            requestPermissions();
        } else {
            getLastLocation();
        }
    }


11 commentaires

Vous devez soit retarder la création du fragment jusqu'à ce que mLastLocation soit initialisé par getLastLocation . Ou mettre à jour le fragment une fois que mLastLocation est initialisé.


Voulez-vous dire quelque chose comme onsuccesslistner ? Je suis très nouveau sur Java, alors pouvez-vous nous aider un peu plus?


Pas tout à fait en utilisant un auditeur. Il vous suffit d'ajouter une méthode pour informer le fragment des changements d'emplacement. Comment créez-vous le fragment? Est-ce via votre SectionsPagerAdapter ?


Oui. Fondamentalement, je l'ai créé dans android studio-> nouveau projet-> activité à onglets, et je viens de remplacer l'espace réservé de la sectionpageradapter par le sunFragment.


Bonjour, si quelqu'un est intéressé, je suis prêt à télécharger le code complet. Mais, aidez-moi gentiment à résoudre ce problème.


pourquoi vous ne pouvez pas enregistrer le dernier emplacement dans sharedpreference ??? et Appelez l'emplacement dans MainActivity et transmettez-le en fragment plutôt que pour obtenir le loc en fragment.


veuillez télécharger le code complet afin que nous ayons une idée de ce que vous faites


@BaRud Veuillez télécharger le code de la fonction getLocation dans l'activité? Cela nous aidera à savoir ce qui se passe exactement. 1. Je peux voir ce que fait le code sur les google-samples , mais dans votre cas, je ne vois pas comment vous poussez cet emplacement vers le fragment. 2. L'emplacement prendra plus de temps pour être reçu de l'appareil. Le fragment aura déjà commencé, vous devez donc ajouter un écouteur à l'activité dans le fragment afin que vous puissiez recevoir des mises à jour d'emplacement.


Salut, le lien du code complet est joint. Veuillez jeter un œil.


Bonjour, j'ai téléchargé et exécuté votre code, je veux juste comprendre ce que vous essayez d'accomplir ici sur SunFragment . Comme je peux le voir, il y a recyclerview et la première entrée dit «Recherche d'emplacement», voulez-vous vous assurer que l'emplacement y arrive tout le temps?


ddassa: oui ... exactement


5 Réponses :


3
votes

J'ai trouvé quelque chose qui ne va pas dans votre code (je me trompe peut-être):

  1. Pourquoi les champs de latlang sont statiques ? Il ne semble pas qu'ils devraient le faire.

  2. Dans SunFragment.onCreate () , vous lisez location si savedInstanceState! = null . savedInstanceState n'est pas nul uniquement si l'activité contenant ce fragment a été restaurée à partir de l'état enregistré. Cela peut ne pas arriver du tout.

  3. Vous devez utiliser les arguments (Bundle) du fragment pour transmettre les données initiales au fragment

  4. Vous devez implémenter l'interface Parcelable pour latlang afin de pouvoir passer une classe personnalisée via Bundle

Je pense que ce n'est pas tout, mais pour moi, cela semble suffisant pour que ce code ne fonctionne pas comme prévu


0 commentaires

2
votes

Comme indiqué dans la réponse précédente, il y a beaucoup de problèmes dans votre code.

En dehors de cela, sachez que le dernier emplacement connu peut ne pas toujours renvoyer une valeur. Le GPS a essentiellement deux types de données: les éphémérides (données de navigation précises) et l'almanach (données grossières). Maintenant, lorsque le récepteur est démarré à froid, c'est-à-dire après que le GPS a été éteint pendant plus de 8 à 10 minutes, il n'y a pratiquement pas de dernier emplacement connu (la durée peut varier en fonction de l'appareil, mais l'idée de base est la suivante).

Ainsi, lorsque vous n'obtenez pas le dernier emplacement connu, récupérez l'emplacement réel en direct à l'aide du client fusionné. De plus, puisque vous enregistrez les données dans les préférences partagées et que vous les récupérez dans votre fragment, je pense que votre fragment va fortement s'appuyer sur ces données. Je suggérerais donc l'une des deux approches suivantes pour obtenir un résultat correct

1) ne récupère pas du tout l'emplacement dans l'activité d'imbrication. Faites-le simplement dans le fragment où il est nécessaire. Cela ne fonctionnera pas si d'autres fragments de votre visionneur ont également besoin de l'emplacement.

2) Si vous devez avoir l'emplacement dans votre activité et qu'il s'agit d'une dépendance dans les fragments de conteneur, vous pouvez également utiliser deux approches ici. Mes approches reposent sur le bus événementiel. Bus événementiel, otto ou rxbus, tout fera l'affaire

2a) n'ajoute rien au visualiseur. en gros, commencez par récupérer entièrement l'emplacement, puis ajoutez des éléments au visualiseur une fois que vous avez obtenu le rappel de l'emplacement.

2b) Ajoutez des éléments au visualiseur depuis le début. Dans l'activité, une fois que vous avez obtenu l'emplacement, utilisez le bus d'événements pour informer les fragments de la même chose et pour obtenir l'événement dans les fragments, commencez réellement ce que vous devez faire.

J'ai déjà utilisé ces deux approches et tout fonctionne. Il appartient désormais entièrement à votre cas d'utilisation d'utiliser ce qui vous convient. Quoi qu'il en soit, c'est un code trop long et trop compliqué pour tout publier ici.


0 commentaires

0
votes

En ce moment, vous utilisez comme ceci:

@Override
public void onStart() {
    super.onStart();
    if (!checkPermissions()) {
        requestPermissions();
    } else {
        if(getLastLocation() != null){
           //replace your fragment
        }else{//Null Location}
    }
}

Dans votre instruction else vérifiez si getLastLocation () n'est pas nul. s'il n'est pas nul, remplacez le fragment.

@Override
public void onStart() {
    super.onStart();
    if (!checkPermissions()) {
        requestPermissions();
    } else {
        getLastLocation();
    }
}


0 commentaires

0
votes

Utilisez une classe de service pour gérer précisément le service de localisation. Ici, je vous donne une classe LocationService personnalisée que j'ai utilisée dans de nombreux projets pour collecter les données de localisation en arrière-plan en continu

LocationService.kt

import android.Manifest
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Binder
import android.os.Build
import android.os.IBinder
import android.os.Looper
import android.util.Log
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat

import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationServices


class LocationService : Service() {

    //Custom Location Binder class
    inner class LocationBinder : Binder() {
        val locationService: LocationService
            get() = this@LocationService
    }

    companion object {
        val TAG = "LocationService_123"
        private val UPDATE_INTERVAL = (4 * 1000).toLong()  /* 4 secs */
        private val FASTEST_INTERVAL: Long = 2000 /* 2 sec */

        private var INSTANCE: LocationService? = null
        fun isInstanceCreated(): Boolean {
            return (INSTANCE != null)
        }
    }


    private var mFusedLocationClient: FusedLocationProviderClient? = null
    private var mLocationListener: LocationListener? = null
    private var mLocationBinder = LocationBinder()

    fun setLocationListener(locationListener: LocationListener) {
        this.mLocationListener = locationListener
    }

    override fun onBind(intent: Intent): IBinder? {
        return mLocationBinder
    }

    override fun onCreate() {
        INSTANCE = this
        super.onCreate()

        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this)

        if (Build.VERSION.SDK_INT >= 26) {
            val CHANNEL_ID = "ostad_gps"
            val channel = NotificationChannel(
                    CHANNEL_ID,
                    "Ostad GPS",
                    NotificationManager.IMPORTANCE_DEFAULT)

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

            val notification = NotificationCompat.Builder(this, CHANNEL_ID)
                    .setContentTitle("")
                    .setContentText("").build()

            startForeground(1, notification)
        }
    }

    override fun onDestroy() {
        INSTANCE = null
        super.onDestroy()
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        Log.d(TAG, "onStartCommand: called.")
        getLocation()
        return Service.START_NOT_STICKY
    }

    private fun getLocation() {

        // ---------------------------------- LocationRequest ------------------------------------
        // Create the location request to start receiving updates
        val mLocationRequestHighAccuracy = LocationRequest()
        mLocationRequestHighAccuracy.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        mLocationRequestHighAccuracy.interval = UPDATE_INTERVAL
        mLocationRequestHighAccuracy.fastestInterval = FASTEST_INTERVAL


        // new Google API SDK v11 uses getFusedLocationProviderClient(this)
        if (ActivityCompat.checkSelfPermission(
                        this,
                        Manifest.permission.ACCESS_FINE_LOCATION
                ) != PackageManager.PERMISSION_GRANTED
        ) {
            Log.d(TAG, "getLocation: stopping the location mitchService.")
            stopSelf()
            return
        }
        Log.d(TAG, "getLocation: getting location information.")
        mFusedLocationClient!!.requestLocationUpdates(
                mLocationRequestHighAccuracy, object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult?) {

                val location = locationResult!!.lastLocation

                Log.d(TAG, "onLocationResult: got location result: $location")

                if (location != null) {
                    if (mLocationListener != null)
                        mLocationListener!!.onLocationChanged(location)
                }

            }
        },
                Looper.myLooper()
        ) // Looper.myLooper tells this to repeat forever until thread is destroyed
    }

}

ajoutez ceci dans votre AndroidManifest et démarrez le LocationService à partir de votre MainActivity.


0 commentaires

0
votes

En regardant le code, il semble que vous n'ayez pas besoin d'un emplacement très précis, vous serez d'accord avec le dernier emplacement connu. Cette valeur peut être nulle dans certains cas, comme vous l'avez déjà fait. La réponse simple à votre question est non, vous ne pouvez pas obtenir un emplacement non nul avant de créer SunFragment . Les étapes suivantes consistent à charger l'emplacement en arrière-plan et à mettre à jour l'interface utilisateur une fois trouvée.

  1. Demander le dernier emplacement connu dans MainActivity
  2. Conservez une référence du dernier emplacement dans le cache pour un chargement facile et un meilleur utilisateur expérience
  3. Si le dernier emplacement est nul, demandez les mises à jour de l'emplacement jusqu'à ce que vous obteniez une bonne solution
  4. Avoir un auditeur dans SunFragment pour suivre les mises à jour de localisation

Voici quelques codes dont vous avez besoin (veuillez les lire)

Utilisez LocationUtil pour gérer les événements liés à la localisation (I préférez LocationManager à FusedLocationProviderClient);

             sunsList.add(
                new SunSession(
                        AppCache.getLastLocation("Searching location..."),
                        "&#xf051;",
                        sun_rise,
                        "&#xf052;",
                        sun_set,
                        "&#xf0c9",
                        moon_rise,
                        "&#xf0ca",
                        moon_set));

Utilisez AppCache pour stocker le dernier emplacement;

@Override
public void onStart() {
    super.onStart();
    AppCache.registerPreferenceChangeListener(mPreferenceChangeListener);
}

@Override
public void onStop() {
    super.onStop();
    AppCache.unregisterPreferenceChangeListener(mPreferenceChangeListener);
}

Mettez le code suivant dans votre MainActivity onCreate () Cela appellera locationManager pour obtenir le dernier emplacement connu et mettre à jour l'application cache.

SunAdapter mAdapter;

SharedPreferences.OnSharedPreferenceChangeListener mPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
        @Override
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {

            if(AppCache.KEY_LAST_LOCATION.equalsIgnoreCase(key)) {
                // location value has change, update data-set
                SunSession sunSession = sunsList.get(0);
                sunSession.setId(sharedPreferences.getString(key, "No Location"));
                sunsList.add(0, sunSession);
                mAdapter.notifyDataSetChanged();
            }
        }
    };

Remplacez également fetchLocation (); dans la méthode onRequestPermissionsResult par la ligne de code ci-dessus, pour qu'elle ressemble comme;

public class LocationLite {

    public double lat;
    public double lon;
    public String address;
}

Je n'ai pas utilisé votre classe latlang. (Veuillez vous assurer que tous les noms de classe suivent les normes de codage Java) Utilisez plutôt LocationLite pour stocker l'emplacement dans le cache. J'ai également utilisé la bibliothèque google GSON pour convertir et restaurer pojo en JSON et en arrière.

@Override
    public void onRequestPermissionsResult(...){
        switch (requestCode) {
            case 101:
            {
                ...
                    // permission was granted
                    //fetchLocation();
                    LocationUtil.updateLastKnownLocation(MainActivity.this);
                } else {
                   // Show some error
                }
                return;
            }
        }
    }

Modifications finales dans SunFragment .

Définissez SunAdapter comme variable membre et SharedPreferences.OnSharedPreferenceChangeListener pour écouter les modifications apportées à la valeur de l'emplacement.

LocationUtil.updateLastKnownLocation(MainActivity.this);


0 commentaires