2017-07-20 2 views
0

Voici mon adaptateur pour un RecyclerView où j'ai besoin de mettre à jour l'un des TextView qui montre la distance de l'emplacement actuel à un autre emplacement.Android: Comment utiliser le rappel mFusedLocationClient (emplacement résultant) dans le thread principal courant

Maintenant, pour obtenir l'emplacement actuel, j'utilise mFusedLocationClient.requestLocationUpdates(mFusedLocationRquest,mLocationCallback,null);

Si je vais avec le code ci-dessous et je viens juste d'un GPS en application avec la permission d'exécution, je fais face à NPE en ligne:

float distance = updatedLoc.distanceTo(des); 

L'application ne plante pas lorsque j'ouvre avec gps déjà activé (probablement parce que la dernière loc connue n'est pas nulle dans ce cas). Donc pour m'assurer que updatedLoc n'est pas null, je veux m'assurer que mon TextView est mis à jour après le rappel de localisation seulement, comment cela serait-il possible?

Dans le rappel de cette API, createLocationCallback(), je ne peux pas mettre à jour le TextView correctement (essayé d'utiliser comme support var global, mais il était en désordre et les articles ne sont pas mis à jour correctement.)

Merci à l'avance.

public class PlaceListAdapter extends RecyclerView.Adapter<PlaceListAdapter.PlaceViewHolder> implements android.location.LocationListener{ 

    private static final long LOCATION_REFRESH_TIME = 2000; 
    private static final float LOCATION_REFRESH_DISTANCE = 100; 
    private static final int MY_PERMISSION_ACCESS_COURSE_LOCATION = 1001; 
    private Context mContext; 
    private PlaceBuffer mPlaces; 
    Location updatedLoc = null; 
    PlaceViewHolder myHolder; 
    boolean canGetLocation = false; 
    android.location.LocationListener locationListener; 
    double lat1,long1; 
    MySimpleCallback mySimpleCallback; 
    String dist; 
    private FusedLocationProviderClient mFusedLocationClient; 
    private LocationRequest mFusedLocationRquest; 
    private LocationCallback mLocationCallback; 

    /** 
    * Creates a callback for receiving location events. 
    */ 
    private void createLocationCallback() { 
     mLocationCallback = new LocationCallback() { 
      @Override 
      public void onLocationResult(LocationResult locationResult) { 
       super.onLocationResult(locationResult); 

       updatedLoc = locationResult.getLastLocation(); 

       Log.d("testingvalue",String.valueOf(updatedLoc==null)); 
       //mLastUpdateTime = DateFormat.getTimeInstance().format(new Date()); 

      } 
     }; 
    } 


    /** 
    * Constructor using the context and the db cursor 
    * 
    * @param context the calling context/activity 
    */ 
    public PlaceListAdapter(Context context, PlaceBuffer places) { 
     this.mContext = context; 
     this.mPlaces = places; 
     mFusedLocationClient = LocationServices.getFusedLocationProviderClient(mContext); 

     createLocationCallback(); 
     createLocationRequest(); 

     if (ActivityCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_FINE_LOCATION) 
       != PackageManager.PERMISSION_GRANTED) { 
      ActivityCompat.requestPermissions((Activity) mContext, 
        new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, 
        101); 
     } 

     mFusedLocationClient.requestLocationUpdates(mFusedLocationRquest,mLocationCallback,null); 

    } 

    private void createLocationRequest() { 
     mFusedLocationRquest = new LocationRequest(); 

     // Sets the desired interval for active location updates. This interval is 
     // inexact. You may not receive updates at all if no location sources are available, or 
     // you may receive them slower than requested. You may also receive updates faster than 
     // requested if other applications are requesting location at a faster interval. 
     mFusedLocationRquest.setInterval(100); 

     // Sets the fastest rate for active location updates. This interval is exact, and your 
     // application will never receive updates faster than this value. 
     mFusedLocationRquest.setFastestInterval(100); 

     mFusedLocationRquest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); 

    } 

    /** 
    * Called when RecyclerView needs a new ViewHolder of the given type to represent an item 
    * 
    * @param parent The ViewGroup into which the new View will be added 
    * @param viewType The view type of the new View 
    * @return A new PlaceViewHolder that holds a View with the item_place_card layout 
    */ 
    @Override 
    public PlaceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     // Get the RecyclerView item layout 
     LayoutInflater inflater = LayoutInflater.from(mContext); 
     View view = inflater.inflate(R.layout.item_place_card, parent, false); 
     return new PlaceViewHolder(view); 
    } 

    /** 
    * Binds the data from a particular position in the cursor to the corresponding view holder 
    * 
    * @param holder The PlaceViewHolder instance corresponding to the required position 
    * @param position The current position that needs to be loaded with data 
    */ 
    @Override 
    public void onBindViewHolder(PlaceViewHolder holder, int position) { 
     String placeName = mPlaces.get(position).getName().toString(); 
     String placeAddress = mPlaces.get(position).getAddress().toString(); 

     double lat = mPlaces.get(position).getLatLng().latitude; 
     double lng = mPlaces.get(position).getLatLng().longitude; 

     //Location currentLocation = getCurrentLocation(); 

     //Location currLoc = new GPSTracker(mContext).getLocation(); 

     //Toast.makeText(mContext, "distance is" + dist + "km", Toast.LENGTH_SHORT).show(); 

     Location des = new Location("destination"); 

     des.setLatitude(lat); 
     des.setLongitude(lng); 

     float distance = updatedLoc.distanceTo(des); 

     distance = distance/1000; 

     dist = ""; 
     if (distance < 1) { 
      dist = "less than km away"; 
     } else { 
      dist = String.format("%.2f", distance) + " km"; 
     } 


     holder.nameTextView.setText(placeName); 
     holder.addressTextView.setText(dist); 

     holder.taskTextView.setText(MainActivity.preference.getString(mPlaces.get(position).getId(), "chv")); 
    } 

    public void swapPlaces(PlaceBuffer newPlaces) { 
     mPlaces = newPlaces; 
     if (mPlaces != null) { 
      // Force the RecyclerView to refresh 
      this.notifyDataSetChanged(); 

     } 
    } 

    /** 
    * Returns the number of items in the cursor 
    * 
    * @return Number of items in the cursor, or 0 if null 
    */ 
    @Override 
    public int getItemCount() { 
     if (mPlaces == null) { 
      Log.d("countcheck", "zero bro"); 
      return 0; 
     } 
     return mPlaces.getCount(); 

    } 


    @Override 
    public void onLocationChanged(Location location) { 
     updatedLoc = location; 
    } 

    @Override 
    public void onStatusChanged(String s, int i, Bundle bundle) { 

    } 

    @Override 
    public void onProviderEnabled(String s) { 

    } 

    @Override 
    public void onProviderDisabled(String s) { 

    } 



    /** 
    * PlaceViewHolder class for the recycler view item 
    */ 
    class PlaceViewHolder extends RecyclerView.ViewHolder { 

     TextView nameTextView; 
     TextView addressTextView; 
     TextView taskTextView; 

     public PlaceViewHolder(View itemView) { 
      super(itemView); 
      nameTextView = (TextView) itemView.findViewById(R.id.name_text_view); 
      addressTextView = (TextView) itemView.findViewById(R.id.address_text_view); 
      taskTextView = (TextView) itemView.findViewById(R.id.task_text_view); 
     } 

    } 

} 

Répondre

1

Lorsque le onBindViewHolder est appelé, updatedLoc est toujours nul, désigne un fournisseur d'emplacement n'a pas encore reçu lieu.

Vous devriez envelopper le updatedLoc dans onBindViewHolder contre au cas nul comme ci-dessous

if(updatedLoc != null){ 
    float distance = updatedLoc.distanceTo(des); 
    distance = distance/1000; 
    dist = ""; 

    if (distance < 1) { 
     dist = "less than km away"; 
    } else { 
     dist = String.format("%.2f", distance) + " km"; 
    } 
} else { 
    dist = "Waiting for location..."; 
} 

holder.nameTextView.setText(placeName); 
holder.addressTextView.setText(dist); 

Et chaque fois que vous recevez l'emplacement, onBindViewHolder doit être appelé à nouveau pour le calcul et la distance parcourue de lieu de Waiting for location...

Vous besoin de mettre à jour la méthode createLocationCallback. Il suffit d'ajouter notifyDataSetChanged()

private void createLocationCallback() { 
    mLocationCallback = new LocationCallback() { 
     @Override 
     public void onLocationResult(LocationResult locationResult) { 
      super.onLocationResult(locationResult); 

      updatedLoc = locationResult.getLastLocation(); 

      Log.d("testingvalue",String.valueOf(updatedLoc==null)); 
      //mLastUpdateTime = DateFormat.getTimeInstance().format(new Date()); 

      notifyDataSetChanged(); 
     } 
    }; 
} 
+0

exactement ce dont j'avais besoin, merci, résolu !! – user3820753

0

Je ne suis pas sûr, mais je ne peux pas voir notifyDataSetChanged() l'intérieur de votre rappel. Essayez de l'ajouter.

+0

si vous dites, prenez titulaire dans une variable globale, affecter titulaire de onBindViewHolder à un mondial, puis l'utiliser à l'intérieur de rappel, de texte à textview puis notifyDataSetChanged()? – user3820753

+0

non. Je veux dire utiliser PlaceListAdapter.this.notifyDataSetChanged() 'dans le rappel. – Vyacheslav

+0

désolé, je ne comprends pas comment cela va résoudre mon numéro actuel de NPE pour 'updatedLoc' – user3820753