I'm writing a lambda expression to convert the given latitude and longitude into an address. The expression is supposed to take co-ordinates as arguments and returns their corresponding address. However, the value returned is null. Following is my class:
public class LambdaDeclarations {
String loc;
private static final String TAG = "LambdaDeclarations";
public CoordinatesToAddressInterface convert = (latitude, longitude, context) -> {
RequestQueue queue = Volley.newRequestQueue(context);
Log.d(TAG, "onCreate: Requesting: Lat: "+latitude+" Lon: "+longitude);
String url ="https://maps.googleapis.com/maps/api/distancematrix/json?units=metric&origins="+latitude+","+longitude+"&destinations="+latitude+","+longitude+"&key=AIzaSyCdKSW0glin4h9sGYa_3hj0L83zI0NsNRo";
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
(String response) -> {
try {
JSONObject jsonObject = new JSONObject(response);
JSONArray destinations = jsonObject.getJSONArray("destination_addresses");
Log.d(TAG, "GETRequest: JSON Object: "+destinations.toString());
String location = destinations.toString();
Log.d(TAG, "Location: "+location);
setLocation(location);
} catch (JSONException e) {
e.printStackTrace();
}
}, error -> Log.d(TAG, "onErrorResponse: That didn't work!"));
queue.add(stringRequest);
return getLocation();
};
public String getLocation() {
return loc;
}
public void setLocation(String location) {
this.loc = location;
}
}
Following is the output from logcat:
09-16 10:31:09.160 26525-26525/com.rmit.tejas.mad_foodtruck_2 D/LambdaDeclarations: GETRequest: JSON Object: ["77 State Route 32, West Melbourne VIC 3003, Australia"]
Location: ["77 State Route 32, West Melbourne VIC 3003, Australia"]
09-16 10:31:09.176 26525-26525/com.rmit.tejas.mad_foodtruck_2 D/LambdaDeclarations: GETRequest: JSON Object: ["111 Adderley St, West Melbourne VIC 3003, Australia"]
Location: ["111 Adderley St, West Melbourne VIC 3003, Australia"]
09-16 10:31:09.177 26525-26525/com.rmit.tejas.mad_foodtruck_2 D/LambdaDeclarations: GETRequest: JSON Object: ["4\/326 William St, Melbourne VIC 3000, Australia"]
Location: ["4\/326 William St, Melbourne VIC 3000, Australia"]
Following is my usage:
myViewHolder.textView3.setText("Location: i->"+i+" add: "+l.convert.toAddress(trackingInfos.get(i).getLatitude(),trackingInfos.get(i).getLongitude(),context));
l is an object of the class LambdaDeclarations and following is the relevant interface:
public interface CoordinatesToAddressInterface {
String toAddress(double latitude, double longitude, Context context);
}
When I try to print the coordinates from the relevant adapter they are getting printed correctly. So the location is getting set properly but when I try to access it from another class it shows me a null value for the string. Can you please advise an alternate method to extract the location from the expression?
First of all, Lambda Expression is just a anonymous class implementation, it was design to be used as a method or class argument and solve shadowing issues of anonymous class.
So in your case, you don't need it at all, just simply implement CoordinatesToAddressInterface interface as named class as usual.
Second, you used Volley wrong, the first lambda you provided to StringRequest, hereafter will be call response callback, is going to be called when HTTP request finish but the return statement
return getLocation();
will return null immediately before your setLocation(location) or even your response callback ever get executed, that why you got null every time you call convert(), though you can still see log that you print because the response callback will be executed anyway (assume that request is success).
To use response callback correctly, you have to update your UI inside callback, pretty much like this
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
public static final String TAG = "MyAdapter";
private RequestQueue mQueue;
public MyAdapter(Context context) {
this.mQueue = Volley.newRequestQueue(context);
}
public RequestQueue getMyAdapterRequestQueue() {
return this.mQueue;
}
...
#Override
public void onBindViewHolder(#NonNull final MyViewHolder holder, int position) {
String url ="some url";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
(String response) -> {
try {
JSONObject jsonObject = new JSONObject(response);
JSONArray destinations = jsonObject.getJSONArray("destination_addresses");
Log.d(TAG, "GETRequest: JSON Object: "+destinations.toString());
String location = destinations.toString();
Log.d(TAG, "Location: "+location);
// update UI
holder.mTextView.setText(location);
} catch (JSONException e) {
e.printStackTrace();
}
}, error -> Log.d(TAG, "onErrorResponse: That didn't work!"));
stringRequest.setTag(TAG);
mQueue.add(stringRequest);
}
Of course, you can edit your interface's method signature and make your adapter implement that interface (I would rather do it this way though) but the point is that you have to process asynchronous results in callback method, never expect asynchronous operation's callback to finish before your next lines of code.
RequestQueue shouldn't be created per-request since it manages internal state that help you make request faster (caching), you can also cancel requests too in an event like phone rotation and your will get destroy, in this case, just call cancel method in Activity/Fragment's onStop()
#Override
protected void onStop () {
super.onStop();
if (myAdapter.getMyAdapterRequestQueue() != null) {
myAdapter.getMyAdapterRequestQueue().cancelAll(MyAdapter.TAG);
}
}
Response callback won't be called after you cancel request.
Related
I have two global variables currentTemp and currentHum that are set when Volley's onResponse method is called. My code looks like this:
// Request a string response from the provided URL.
private JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, WEATHER_URL, null, new Response.Listener<JSONObject>() {
public void onResponse(JSONObject response) {
try {
JSONObject main = new JSONObject(response.getString("main"));
currentTemp = main.getString("temp");
currentHum = main.getString("humidity");
Log.i("RES", "Temp: " + main.getString("temp") + " Hum: " + main.getString("humidity"));
} catch (JSONException e) {
e.printStackTrace();
}
}}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(appContext, "An error occurred while retrieving weather info", Toast.LENGTH_LONG).show();
Log.e("ERR", "ERROR RET WEATHER DATA");
}
});
// Call the OpenWeatherMap API and get data such as temperature and humidity
private String getWeatherInfo(String key) {
// Add the request to the RequestQueue to invoke the API
queue.add(jsonObjectRequest);
// Access variables set by Volley's onResponse here.
switch (key) {
case "temp":
return String.valueOf(Float.parseFloat(currentTemp) - 273.15);
case "hum":
return currentHum;
default:
return " ";
}
}
I want to be able to access the values of the global variables set by the onResponse method in the getWeatherInfo method that invoked it. Then pass the values to a switch statement for processing. How do I do it without getting empty values for currentTemp and currentHum?
This work is meant to be done with use of an interface. If you don't know about an interface callbacks then please go through this answer. Which will help you understand interface, and plus point that this will guide you for handling volley response.
Also this is not recommended to take global variables to set any response, rather you can pass your whole JsonObject from volley class. and parse it where you make a call. You can use Gson for parsing the response to your Model or ArrayList.
I have an activity implementing OnMapReadyCallback to display some markers.
Before opening the map i provide a target city which i'd like to look at closer on the map basically by calling :
LatLng currentCity = new LatLng(cityLat,cityLng)
CameraUpdate location = CameraUpdateFactory.newLatLngZoom(currentCity,13);
googleMap.animateCamera(location);
The main problem here is that the zoom level is just an arbitrary number which works fine for some city and bad for others (Too zoomed in, Not enough zoomed in).
What i would like to achieve is to determine the zoom level dynamically depending on the city in the same way Google Maps does.
I know that the bigger the ViewPort of the city is, the smaller the zoom needs to be but i can't find a method to get the ViewPort for a given city and then changing the zoom level accordingly
EDIT : I was thinking about using a Geocoder to get a list of adress using the latitude and longitude of the city using
List<Address> addresses = mGeocoder.getFromLocation(Lat,Lon,maxLimit);
and then iterating over this list to find out the outermost adresses avaible for that city, in order to build a LatLngBounds to pass at setLatLngBoundsForCameraTarget() method.
The main problem with this approach is that, once again, the "maxLimit" is arbitrary and needs to be quite big for a big city, eventually returning a really big List
You can retrieve a view port for the city from the Geocoding API reverse geocoding response.
You should execute HTTP request to retrieve city view port from your activity. Once you receive the response you can construct the LatLngBounds instance and move camera accordingly.
Sample reverse geocoding request that gets city from coordinates is the following
https://maps.googleapis.com/maps/api/geocode/json?latlng=47.376887%2C8.541694&result_type=locality&key=YOUR_API_KEY
I wrote a small example for Map activity that receives lat and lng from the intent, executes the reverse geocoding HTTP request using the Volley library and moves camera to show the city view port.
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
private float lat;
private float lng;
private String name;
private RequestQueue mRequestQueue;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent i = getIntent();
this.lat = i.getFloatExtra("lat", 0);
this.lng = i.getFloatExtra("lng", 0);
this.name = i.getStringExtra("name");
mRequestQueue = Volley.newRequestQueue(this);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// Add a marker in Sydney and move the camera
LatLng pos = new LatLng(this.lat, this.lng);
mMap.addMarker(new MarkerOptions().position(pos).title(this.name));
mMap.moveCamera(CameraUpdateFactory.newLatLng(pos));
this.fetchReverseGeocodeJson();
}
private void fetchReverseGeocodeJson() {
// Pass second argument as "null" for GET requests
JsonObjectRequest req = new JsonObjectRequest(Request.Method.GET,
"https://maps.googleapis.com/maps/api/geocode/json?latlng=" + this.lat + "%2C" + this.lng + "&result_type=locality&key=AIzaSyBrPt88vvoPDDn_imh-RzCXl5Ha2F2LYig",
null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
String status = response.getString("status");
if (status.equals("OK")) {
JSONArray results = response.getJSONArray("results");
JSONObject item = results.getJSONObject(0);
JSONObject geom = item.getJSONObject("geometry");
JSONObject bounds = geom.getJSONObject("viewport");
JSONObject ne = bounds.getJSONObject("northeast");
JSONObject sw = bounds.getJSONObject("southwest");
LatLngBounds mapbounds = new LatLngBounds(new LatLng(sw.getDouble("lat"),sw.getDouble("lng")),
new LatLng(ne.getDouble("lat"), ne.getDouble("lng")));
mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(mapbounds, 0));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.e("Error: ", error.getMessage());
}
}
);
/* Add your Requests to the RequestQueue to execute */
mRequestQueue.add(req);
}
}
You can find a complete sample project at github:
https://github.com/xomena-so/so44735477
Hope this helps!
i'm using for firts time Retrofit on my Android app.
This is the structure of json object that i have to retrive:
{
"placemarks":[
{
"address":"Via di Santa Maria a Marignolle, 15, 50124 Firenze",
"coordinates":[
11.23348,
43.75855,
0
],
"engineType":"CE",
"exterior":"GOOD",
"fuel":100,
"interior":"GOOD",
"name":"049/EV284TP",
"smartPhoneRequired":false,
"vin":"WME4513341K774636"
}
]
}
i have write this Pojo model for object "placemarks" and all otehr items.
And i have write this code to retrive the json data and put it into map:
private void getPlacemark(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://www.car2go.com/api/v2.1/vehicles?loc=roma&oauth_consumer_key=roadzapp&format=json")
.addConverterFactory(GsonConverterFactory.create())
.build();
APIService service = retrofit.create(APIService.class);
Call<ResponsePlacemarks> call = service.getPlacemark();
call.enqueue(new Callback<ResponsePlacemarks>() {
#Override
public void onResponse(Response<ResponsePlacemarks> response, Retrofit retrofit) {
Log.d("response: ", String.valueOf(response.body()));
try {
mMap.clear();
// This loop will go through all the results and add marker on each location.
for (int i = 0; i < response.body().getPlacemarks().size(); i++) {
Double lat = response.body().getPlacemarks().get(i).getCoordinates().get(1);
Double lng = response.body().getPlacemarks().get(i).getCoordinates().get(0);
String placeName = response.body().getPlacemarks().get(i).getAddress();
MarkerOptions markerOptions = new MarkerOptions();
LatLng latLng = new LatLng(lat, lng);
// Position of Marker on Map
markerOptions.position(latLng);
// Adding Title to the Marker
markerOptions.title(placeName);
// Adding Marker to the Camera.
Marker m = mMap.addMarker(markerOptions);
// Adding colour to the marker
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
// move map camera
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(11));
}
} catch (Exception e) {
Log.d("onResponse", "There is an error");
e.printStackTrace();
}
}
#Override
public void onFailure(Throwable t) {
}
});
}
but now when i run app the json are note load and i have error in the first line of for loop:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.List android.mobility.com.mobiity.model.ResponsePlacemarks.getPlacemarks()' on a null object reference
Hi have found the error.
On APIService i have set #GET method in this way: #GET(".") because i use as URL the URL into BaseURL. So if i set all url into #GET the method works fine.
How i can use only the url into BaseULRalso into #GET?
First, you can only call response.body() exactly once.
So, comment this.
// Log.d("response: ", String.valueOf(response.body()));
And extract that list variable
final ResponsePlacemarks _response = response.body();
final List<Placemark> placemarks = _response.getPlacemarks();
for (int i = 0; i < placemarks.size(); i++) {
final Placemark p = placemarks.get(i);
Coordinates c = p.getCoordinates();
Double lat = c.get(1);
Double lng = c.get(0);
String placeName = p.getAddress();
And if that doesn't work, then you need for the Java object to exactly match the JSON response, otherwise it is null
How i can use only the url into BaseULRalso into #GET?
Your base URL should look like something this
https://www.car2go.com/api/v2.1
Then you should be able to have something like
#GET("/vehicles")
public ResponsePlacemarks getVehicles(
#Query("oauth_consumer_key") String key,
#Query("format") String format
#Query("loc") String loc
);
public ResponsePlacemarks getVehicles(String loc) {
return getVehicles("roadzapp", "json", loc);
}
Or maybe just
#GET("/vehicles?format=json")
public ResponsePlacemarks getVehicles(
#Query("oauth_consumer_key") String key,
#Query("loc") String loc
);
The reason for putting the key into the method call is that you shouldn't store the key as a string on your device for security reasons.
Most likely your POJO does not match the JSON structure.
Can you post your POJO class and how are you deserializing the JSON?
I am looking for an example how could I send file and other params together to server.
I have to send server JSON which
{
"title": "title",
"file": "uploaded file instance",
"location": {
"lat": 48.8583,
"lng": 2.29232,
"place": "Eiffel Tower"
}
}
How could I create Retrofit to handle this case?
If file is a string I know how to handle this. If file is File object I have no idea how to do this.
Use gson and create a model class for the location.
Add the following dependencies to your build.gradle.
compile 'com.squareup.retrofit2:converter-gson:2.0.0'
compile 'com.google.code.gson:gson:2.5'
Create a model to represent the location.
public class Location {
double lat;
double lng;
String location;
public Location(double lat, double lon, String place) {
this.lat = lat;
this.lon = long;
this.place = place;
}
}
If the variable names for the payload fields don't match the actual required name for the endpoint you will need to add the annotation #SerializedName([expected name])
ex:
import com.google.gson.annotations.SerializedName;
public class Location {
#SerializedName("lat")
double latitude;
#SerializedName("lng")
double longitude;
#SerializedName("place")
String location;
public Location(double lat, double lon, String place) {
latitude = lat;
longitude = long;
location = place;
}
}
Define the api interface.
public interface Api {
#POST("upload/")
#Multipart
Call<ResponseBody> uploadFile(#Part("title") RequestBody title,
#Part MultipartBody.Part imageFile,
#Part("location") Location location
);
}
Create a Retrofit instance and call the api.
File file;
// create retrofit instance
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://baseurl.com/api/")
.addConverterFactory(GsonConverterFactory.create())
.build();
// create api instance
Api api = retrofit.create(Api.class);
// create call object
Call<ResponseBody> uploadFileCall = api.uploadFile(
RequestBody.create(MediaType.parse("text/plain"), "title"),
MultipartBody.Part.createFormData(
"file",
file.getName(),
RequestBody.create(MediaType.parse("image"), file)),
new Location(48.8583, 2.29232, "Eiffel Tower"));
// sync call
try {
ResponseBody responseBody = uploadFileCall.execute().body();
} catch (IOException e) {
e.printStackTrace();
}
// async call
uploadFileCall.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
// TODO
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
// TODO
}
});
You will need to change the MediaType.parse() call if you are not using an image file.
You can similarly create a custom response type object and replace ResponseBody with it to receive a deserialized result object.
Let me know if this works. I didn't have a chance to test in your exact scenario obviously but I'm fairly confident this should work. The only part I'm not 100% on is whether #Part("location") Location location should be #Body("location") Location location
As of 02.2020 #Abtin Gramian's answer is great, except RequestBody.create() and MediaType.parse() are deprecated in Kotlin, so you have to use:
file.asRequestBody("image".toMediaTypeOrNull())
instead of:
RequestBody.create(MediaType.parse("image"), file)
Also, I had to write the following manually:
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.asRequestBody
I'm working on MapBox off line. The code was OK, able to download map but after adding some peice of code which have nothing to do with the map, the download stop to work and the give an HTTP401 Error.
I've noticed that depending on where you call MapboxAccountManager.start sometimes it fails.
Here's the code:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
DB_Handler db_ansb = new DB_Handler(Init_Carte.this,null,null,1);
// Get data from DB, about the map
HashMap<String, String> data_mapbox = db_ansb.do_get_mapbox(0);
the_mapbox_token = data_mapbox.get("tmapbox_token");
the_mapbox_style = data_mapbox.get("tmapbox_style");
the_mapbox_zoom_min = Integer.parseInt(data_mapbox.get("tmapbox_zoom_min"));
the_mapbox_zoom_max = Integer.parseInt(data_mapbox.get("tmapbox_zoom_max"));
the_mapbox_inter = Double.parseDouble(data_mapbox.get("tmapbox_inter"));
OfflineManager offlineManager = OfflineManager.getInstance(this);
MapboxAccountManager.start(this,the_mapbox_token);
setContentView(R.layout.activity_init_carte);
// Menu with APP compat
// https://developer.android.com/training/appbar/setting-up.html
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(myToolbar);
// Find our truck GPS position for road map
HashMap<String, String> my_truck = db_ansb.do_get_my_truck();
String str_truck_lagps = my_truck.get("frota_lagps");
String str_truck_logps = my_truck.get("frota_logps");
the_lagps_truck = Double.parseDouble(str_truck_lagps);
the_logps_truck = Double.parseDouble(str_truck_logps);
// Find accident location for road map
HashMap<String, String> my_inter = db_ansb.do_get_inter_resume();
String str_inter_lagps = my_inter.get("inter_lagps");
String str_inter_logps = my_inter.get("inter_logps");
the_lagps_inter = Double.parseDouble(str_inter_lagps);
the_logps_inter = Double.parseDouble(str_inter_logps);
// Compute area to get
HashMap<String, Double> data_gps_inter = db_ansb.do_get_bounds_inter(the_lagps_inter,the_logps_inter,the_mapbox_inter);
final double inter_lagps_ne = data_gps_inter.get("inter_max_lagps"); // Nord Est
final double inter_logps_ne = data_gps_inter.get("inter_max_logps");
final double inter_lagps_so = data_gps_inter.get("inter_min_lagps"); // Sud Ouest
final double inter_logps_so = data_gps_inter.get("inter_min_logps");
// Display what we're doing
tmp_id_msg = (TextView) findViewById(R.id.txt_action);
tmp_id_msg.setText(R.string.str_telechargement_carte);
// Create zone
LatLngBounds latLngBounds = new LatLngBounds.Builder()
.include(new LatLng(inter_lagps_ne, inter_logps_ne)) // Northeast
.include(new LatLng(inter_lagps_so, inter_logps_so)) // Southwest
.build();
OfflineTilePyramidRegionDefinition definition = new OfflineTilePyramidRegionDefinition(
the_mapbox_style,
latLngBounds,
the_mapbox_zoom_min,
the_mapbox_zoom_max,
(Init_Carte.this).getResources().getDisplayMetrics().density);
byte[] metadata;
try
{
JSONObject jsonObject = new JSONObject();
jsonObject.put(JSON_FIELD_REGION_NAME, "Carte");
String json = jsonObject.toString();
metadata = json.getBytes(JSON_CHARSET);
} catch (Exception e)
{
Log.e("TAG", "Failed to encode metadata: " + e.getMessage());
metadata = null;
}
// Get data
offlineManager.createOfflineRegion(definition, metadata, new OfflineManager.CreateOfflineRegionCallback()
{
#Override
public void onCreate(OfflineRegion offlineRegion)
{
offlineRegion.setDownloadState(OfflineRegion.STATE_ACTIVE);
// Monitor the download progress using setObserver
offlineRegion.setObserver(new OfflineRegion.OfflineRegionObserver()
{
#Override
public void onStatusChanged(OfflineRegionStatus status)
{
Log.i("DBUG","onStatusChanged");
// Calculate the download percentage and update the progress bar
double percentage = status.getRequiredResourceCount() >= 0 ?
(100.0 * status.getCompletedResourceCount() / status.getRequiredResourceCount()) :
0.0;
long long_pourcentage = Math.round(percentage);
String str_pourcentage = Long.toString(long_pourcentage)+" %";
// Display on screen
tmp_id_valeur = (TextView) findViewById(R.id.val_action);
tmp_id_valeur.setText(str_pourcentage);
Log.i("DBUG",str_pourcentage+"%");
if (status.isComplete())
{
// OK so now, ask the road
do_get_trajet();
}
}
#Override
public void onError(OfflineRegionError error)
{
// If an error occurs, print to logcat
Log.i("DBUG", "onError reason: " + error.getReason());
Log.e("DBUG", "onError message: " + error.getMessage());
}
#Override
public void mapboxTileCountLimitExceeded(long limit)
{
// Notify if offline region exceeds maximum tile count
Log.i("DBUG", "Mapbox tile count limit exceeded: " + limit);
}
});
}
#Override
public void onError(String error)
{
Log.e("TAG", "Error: " + error);
}
});
}
I enter the Aysnc part, get 3 or 4 times
Log.i("DBUG",str_pourcentage+"%");
with a value of 0% then get I get:
I/System.out: [CDS]rx timeout:10000
D/NativeCrypto: ssl=0x619629c8 sslWrite buf=0x41e60068 len=222 write_timeout_millis=0
D/NativeCrypto: ssl=0x619629c8 sslRead buf=0x41e60068 len=8192,timeo=10000
I/DBUG: onError reason: REASON_OTHER
E/DBUG: onError message: HTTP status code 401
D/com.mapbox.mapboxsdk.http.HTTPRequest: [HTTP] Request with response code = 401: Unauthorized
I've noticed same strange behaviour on another page: depending on the fact you perform or not, action before of after MapboxAccountManager.start(this,the_mapbox_token); it works or not.
Notice the token is correct.
Any idea?
After changing the token in our DB, it was OK but only for a short time: I was able to download 26% of the map and then, I get again the HTTP 401 message...
Found. In fact there is a small mistake in the code that help me understand: how can this code work sometimes, as I call
OfflineManager offlineManager = OfflineManager.getInstance(this);
MapboxAccountManager.start(this,the_mapbox_token);
so as I call the init after the use of the Lib? In fact all example at Mapbox are made with one activity performing all the jobs. So when you have more than one activity using Mapbox, you quickly believe you need to put a MapboxAccountManager.start in each ones. Which is wrong. In that case (more than one activity), you must call MapboxAccountManager.start at App level. Like that:
public class App_Start extends Application
{
#Override
public void onCreate()
{
super.onCreate();
String the_mapbox_token = "pk.eyJ1IjoiYW5.....";
MapboxAccountManager.start(this,the_mapbox_token);
}
public void customAppMethod()
{
// Custom application method
}
}
and add this class at application level on your Manifest:
<application android:icon="#drawable/ic_launcher" android:label="#string/app_name" android:theme="#style/AppTheme" android:name="net.ansb_brasil.xxxx.App_Start">
Concerning the fact the second activity was performing two times the download, it came from the fact the if (status.isComplete()) part of the onStatusChanged() is always called two times. Seems to be a bug in the Lib. On some example at Mapbox, they use a boolean flag in order to avoid taking two times this call in account.
As my first activity was downloading one map and then call a second activity for a second map, this "double call" had as result two call for the second activity and so many troubles.
Hope this will avoid headaches to others