I'm making an app that needs to get the results in my MainActivity, when I call getData() I get the data from my instantiation, but when i try to calculate the position it returns null.
This is my Location.class
public class Location implements GoogleApiClient.OnConnectionFailedListener {
private List<Integer> mTypeList;
private ArrayList<String> listItems;
ArrayAdapter<String> adapter;
ListView listView;
LatLng mLatLang;
private PlaceLikelihood pl;
private Context mContext;
private GoogleApiClient mGoogleApiClient;
public Location(Context context) {
this.listItems = new ArrayList<>();
this.mTypeList = new ArrayList<>();
mContext = context;
buildGoogleApiClient();
connect();
getData();
}
public void buildGoogleApiClient(){
mGoogleApiClient = new GoogleApiClient
.Builder(mContext)
.addApi(Places.GEO_DATA_API)
.addApi(Places.PLACE_DETECTION_API)
.build();
}
public void connect() {
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
}
public void getData() {
if (ActivityCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
final PendingResult<PlaceLikelihoodBuffer> result = Places.PlaceDetectionApi
.getCurrentPlace(mGoogleApiClient, null);
result.setResultCallback(new ResultCallback<PlaceLikelihoodBuffer>() {
#Override
public void onResult(#NonNull PlaceLikelihoodBuffer placeLikelihoods) {
pl = placeLikelihoods.get(0);
Log.e("singleplacetype", "onResult: "+pl.getPlace().getPlaceTypes());
Log.e("singleliketype2", "onResult: "+pl.getLikelihood());
Log.e("singleliketype3", "onResult: "+pl.getPlace().getName());
mTypeList = pl.getPlace().getPlaceTypes();
//Latitude and longitude
mLatLang = pl.getPlace().getLatLng();
String latlongshrink = mLatLang.toString();
Matcher m = Pattern.compile("\\(([^)]+)\\)").matcher(latlongshrink);
while (m.find()) {
Log.e("Test", "" + m.group(1));
latlongshrink = m.group(1);
}
for (int i = 0; i < mTypeList.size(); i++) {
try {
nearestPlaces(latlongshrink, getPlaceTypeForValue(mTypeList.get(i)));
} catch (Exception e) {
e.printStackTrace();
}
try {
listItems.add(pl.getPlace().getName() + " " + pl.getLikelihood() + " " + mTypeList + " " + getPlaceTypeForValue(mTipoList.get(i)));
Log.e("singleList", "onResult: "+listItems );
} catch (Exception e) {
e.printStackTrace();
}
}
placeLikelihoods.release();
}
});
}
public Integer getTypes(int posicion) {
Log.e("listType", "getTypes: "+mTypeList);
int type;
if(mTypeList.size()>0){
type = mTypeList.get(posicion);
}else{
return null;
}
return type;
}
Now, that's my Location.class, I call that class in my MainActivity like this
Location loc = new Location(getApplicationContext());
I have another class that calculates some values with the first class, so after I instantiate the Location.class I can succefull see that getData() is executed as it returns to me some places.
json.class
private Integer getPosition(Location loc) {
return loc.getTypes(0);
}
so, now again into my MainActivity i'm trying to fetch te values from Location.class but from json.class, since getPosition does something else before it is beign executed
MainActivity.class
Json json = new Json(getApplicationContext());
Log.e("jsonClassData", "onCreate: "+json.getPosition(loc));
now, this line is returning null , but I dont know why since getData() have been created but getTypes have inside mTypeList that is returning 0 as size and returning null since mTypeList.size is 0
Also if in MainActivity.class I call this line it returns null too
Location loc = new Location(getApplicationContext());
loc.getType(0);
it seems getData() is not saving the values inside mTypeList
Why is this happening ?
thanks
Location loc = new Location(getApplicationContext());
You are not supposed to create an activity with the new operator.
You should use an intent for that.
And so do away with all those public member functions.
The problem was that getData() is an asynchronous operation that is waiting for the results. Now, if I don't wait for that data to be done, getTypes does not have any value on it. Now, thanks to Mike M. I just solved the problem using a simple interface.
I created an interface called PlaceSuccessListener
public interface PlaceSuccessListener {
void onPlaceFound(int placeFound);
}
called it at the last of my pendingResult
private PlaceSuccessListener mPlaceSuccessListener;
getData();
.....
placeLikelihoods.release();
mPlaceSuccessListener.onPlaceFound(200);
}
And then in my MainActivity I just waited for the result to be done in order to access my data. I implemented PlaceSuccessListener and attached the setInterface(this)
#Override
public void onPlaceFound(int placeFound) {
if(placeFound==200){
Log.e("jsonClassData", "onCreate: "+json.getPosition(loc));
}
}
Related
Basically, I am trying to get some value from the Api callback response, then assign those value to some of my member variables, but It seems like the program has to run over my getPatientRecord() method each time before it could go to my call, which I have never encountered before.
The Log output result is :
viewPatient: paitient method
viewPatient: secondHello worldnullnull
100SN9 - David Hello H M H 1971-08-09
This is my code:
public class ViewPatientRecord extends AppCompatActivity{
TextView tvName, tvGender, tvBirthDate, tvAddress;
String pGender, pAddress, pBirthdate;
String pName = "Hello world";
Patient myPatient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view_patient_record);
tvName = findViewById(R.id.tvFullName);
tvGender = findViewById(R.id.tvGender);
tvBirthDate = findViewById(R.id.tvDb);
tvAddress = findViewById(R.id.tvAddress);
myPatient= new Patient();
try {
getPatientRecord();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void getPatientRecord() throws InterruptedException {
SharedPreferences myPre = getSharedPreferences("PatientRecord", MODE_PRIVATE);
if(myPre.getString("uuid",null)!=null){
retrievePatientByUuid(myPre.getString("uuid",null));
Log.d("viewPatient", "second"+pName+pGender+pBirthdate);
tvName.setText(pName);
tvGender.setText(pGender);
tvBirthDate.setText(pBirthdate);
tvAddress.setText(pAddress);
}else{
Toast.makeText(ViewPatientRecord.this, "Something went wrong, please contact the administrator for help!", Toast.LENGTH_SHORT).show();
}
}
private void retrievePatientByUuid(String uuid) throws InterruptedException {
RestApi api = RetrofitInstance.getRetrofitInstance().create(RestApi.class);
Log.d("viewPatient", "paitient method");
Call<Patient> call = api.getPatientByUUID(uuid, null);
call.enqueue(new Callback<Patient>() {
private volatile Patient obj = new Patient();
#Override
public void onResponse(Call<Patient> call, Response<Patient> response) {
if (response.body() != null) {
Patient patient = response.body();
if (patient != null) {
if (!patient.getDisplay().isEmpty()) {
pName = patient.getDisplay();
pGender = patient.getPerson().getGender();
pBirthdate = patient.getPerson().getBirthdate();
Log.d("viewPatient", pName.toString() + " H " + pGender.toString() + " H " + pBirthdate.toString() + " ?? ");
pAddress = "";
} else {
Log.d("viewPatient", "no results");
}
} else {
Toast.makeText(ViewPatientRecord.this, "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(ViewPatientRecord.this, "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<Patient> call, Throwable t) {
t.printStackTrace();
}
});
}
}
I don't see the problem. The call is done in retrievePatientByUuid which is called by getPatientRecord. So yes, you have to go through getPatientRecord. The call is async. It's in the callback that you should set your TextViews :
tvName.setText(pName);
tvGender.setText(pGender);
tvBirthDate.setText(pBirthdate);
tvAddress.setText(pAddress);
The app just would not move past the log in page and the error pointing me to an inbuilt documentation
04-14 22:10:48.482 4206-4206/com.onyebuchboss.bossweatherbitcoinapp E/StorageHelpers: No value for version
org.json.JSONException: No value for version
at org.json.JSONObject.get(JSONObject.java:389)
at org.json.JSONObject.getString(JSONObject.java:550)
at com.google.firebase.auth.internal.zzz.zzc(Unknown Source)
at com.google.firebase.auth.internal.zzz.zzbi(Unknown Source)
at com.google.firebase.auth.FirebaseAuth.(Unknown Source)
at com.google.firebase.auth.FirebaseAuth.(Unknown Source)
at com.google.firebase.auth.internal.zzj.(Unknown Source)
at com.google.firebase.auth.FirebaseAuth.zza(Unknown Source)
at com.google.firebase.auth.FirebaseAuth.getInstance(Unknown Source)
at java.lang.reflect.Method.invoke(Native Method)
at com.google.firebase.FirebaseApp.zza(Unknown Source)
at com.google.firebase.FirebaseApp.zzc(Unknown Source)
at com.google.firebase.FirebaseApp.initializeApp(Unknown Source)
at com.google.firebase.FirebaseApp.initializeApp(Unknown Source)
at com.google.firebase.FirebaseApp.initializeApp(Unknown Source)
at com.google.firebase.provider.FirebaseInitProvider.onCreate(Unknown Source)
at android.content.ContentProvider.attachInfo(ContentProvider.java:1748)
at android.content.ContentProvider.attachInfo(ContentProvider.java:1723)
at com.google.firebase.provider.FirebaseInitProvider.attachInfo(Unknown Source)
at android.app.ActivityThread.installProvider(ActivityThread.java:5153)
at android.app.ActivityThread.installContentProviders(ActivityThread.java:4748)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4688)
at android.app.ActivityThread.-wrap1(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
my code
public class WeatherActivity extends AppCompatActivity {
final int REQUEST_CODE = 123;
//the openweather url to be used
final String WEATHER_URL = "http://api.openweathermap.org/data/2.5/weather";
//the API key
final String APP_ID = "c9e6cb73daaf09d1bf0d1502d964bf60";
//time between location update (5000 milliseconds or 5 seconds)
final long MIN_TIME = 5000;
//Distance between location in metres
final float MIN_DISTANCE = 1000;
final String TAG = "WeatherApp";
//For the app to detect the user's location,
//we set the LOCATION_PROVIDER
String LOCATION_PROVIDER = LocationManager.GPS_PROVIDER;
//declare the variables to be linked to the layout
TextView mTemperature;
TextView mCity;
ImageView mWeatherImage;
//declare the LocationListener and LocationManager
LocationManager mLocationManager;
LocationListener mLocationListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.weather_layout);
//Link the elements in the Layout here
mCity = (TextView) findViewById(R.id.locationFetching);
mTemperature = (TextView) findViewById(R.id.tempereatureView);
mWeatherImage = (ImageView) findViewById(R.id.weatherImage);
ImageButton ChangeCityButton = (ImageButton) findViewById(R.id.changeCityButton);
//The Intent method used below is mostly used for switching between Activities
ChangeCityButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent changeCityIntent = new Intent(WeatherActivity.this, ChangeCityController.class);
// finish();
startActivity(changeCityIntent);
}
});
}
//the onResume method is one of android lifecycle method
//that starts/execute after the onCreate method
#Override
protected void onResume() {
super.onResume();
//retrieving the city name passed in the
//ChangecityController
//City was used in the PutExtra method in changeCity
Intent myIntent = getIntent();
String city =myIntent.getStringExtra("City");
//if the user does not enter a particular city
//retrieve user current city
if(city != null) {
getWeatherForNewLocation(city);
} else {
getWeatherForCurrentLocation();
}
}
//The method to retrieve any city entered by the user
private void getWeatherForNewLocation(String city) {
//the request params passes in the required parameters to retrieve data using the API
//The openWeatherMap API being used in this project, "q" and acity's name
//is to be assigned to iy
RequestParams params = new RequestParams();
params.put("q", city);
params.put("appid", APP_ID);
networkingCalls(params);
}
// get weather situation for current city -getWeatherForCurrentCityHere()
private void getWeatherForCurrentLocation() {
//create an instance of LocationManager
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
//the Location listener does the checking of the location for update
mLocationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
Log.d(TAG, "onLocationChanged: callback received");
//get the longitude and latitude of current locaion
//stored as a string
String Longitude = String.valueOf(location.getLongitude());
String Latitude = String.valueOf(location.getLatitude());
Log.d(TAG, "onLocation Latitude is: " + Latitude);
Log.d(TAG, "onLocationChanged: longitude " + Longitude);
RequestParams params = new RequestParams();
params.put("lat", Latitude);
params.put("lon", Longitude);
params.put("appid", APP_ID);
networkingCalls(params);
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
Log.d(TAG, "onProviderDisabled: callback");
}
};
//REQUEST A LOCATION UPDATE PASSING THE LOCATION PROVIDER TO BE USED, MIN TIME,
// MIN DISTANCE AND mLISTENER as the receiver
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
//request permissions to use the user's device GPS
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_FINE_LOCATION},REQUEST_CODE);
return;
}
mLocationManager.requestLocationUpdates(LOCATION_PROVIDER, MIN_TIME, MIN_DISTANCE, mLocationListener);
}
//the override method below gives the result of the
// permission request to use the user's GPS
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//check to see if the request code matches the Request Code we gave
//during the request
if(requestCode == REQUEST_CODE){
if(grantResults.length> 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
Log.d(TAG, "onRequestPermissionsResult(): Granted!");
getWeatherForCurrentLocation();
}else{
Log.d(TAG, "onRequestPermissionsResult: Permission Denied");
}
}
}
//create the networkingCalls method here
//this method, we implement an HttpRequest, using it to make a Get request
private void networkingCalls(RequestParams params){
AsyncHttpClient client = new AsyncHttpClient();
//the Json object handler is used to notify whether the Getrequest failed or was successful
//the json response hanler receive 2 messages - onSucess and onFailure
//both methods are declared below
client.get(WEATHER_URL, params, new JsonHttpResponseHandler(){
#Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response){
Log.d(TAG, "onSuccess: " + response.toString());
// call the json from the WeatherDataModel
WeatherDataModel weatherData = WeatherDataModel.fromJson(response);
updateUI(weatherData);
}
#Override
public void onFailure(int statuscode, Header[] headers, Throwable e, JSONObject response){
Log.e(TAG, "onFailure: "+ e.toString());
Log.d(TAG, "Status code: " + statuscode);
Toast.makeText(WeatherActivity.this, "Request failed", Toast.LENGTH_SHORT).show();
}
});
}
private void updateUI(WeatherDataModel weather){
mTemperature.setText(weather.getTemperature());
mCity.setText(weather.getCity());
int resourceID = getResources().getIdentifier(weather.getIconname(), "drawable", getPackageCodePath());
mWeatherImage.setImageResource(resourceID);
}
//This code below frees up memory
//when mListener is not in use and it is automatically generated
#Override
protected void onPause() {
super.onPause();
if(mLocationManager != null) mLocationManager.removeUpdates(mLocationListener);
}
}
public class WeatherDataModel {
private String mTemperature;
private String mCity;
private String mIconname;
private int mCondition;
//create a weatherdatamodel fromJson:
public static WeatherDataModel fromJson(JSONObject jsonObject) {
WeatherDataModel weatherData = new WeatherDataModel();
//we surround the json parsing code with a try-catch statement
//to handle errors like nan and empty values
try {
//get json object called -id, that is nested oin an object "0", thats also nested in an array called weather
weatherData.mCondition = jsonObject.getJSONArray("weather").getJSONObject(0).getInt("id");
weatherData.mCity = jsonObject.getString("name");
weatherData.mIconname = updateWeatherIcon(weatherData.mCondition);
double temp = jsonObject.getJSONObject("main").getDouble("temp") - 273.15;
int rdValue = (int) Math.rint(temp);
weatherData.mTemperature= Integer.toString(rdValue);
return weatherData;
}catch (JSONException e){
e.printStackTrace();
return null;
}
}
private static String updateWeatherIcon(int condition) {
if (condition >= 0 && condition < 300) {
return "tstorm1";
} else if (condition >= 300 && condition < 500) {
return "light_rain";
} else if (condition >= 500 && condition < 600) {
return "shower3";
} else if (condition >= 600 && condition <= 700) {
return "snow4";
} else if (condition >= 701 && condition <= 771) {
return "fog";
} else if (condition >= 772 && condition < 800) {
return "tstorm3";
} else if (condition == 800) {
return "sunny";
} else if (condition >= 801 && condition <= 804) {
return "cloudy2";
} else if (condition >= 900 && condition <= 902) {
return "tstorm3";
} else if (condition == 903) {
return "snow5";
} else if (condition == 904) {
return "sunny";
} else if (condition >= 905 && condition <= 1000) {
return "tstorm3";
}
return "dunno";
}
//create a Get() for the variable created, so it can be retrieved in the weatherActivity
public String getTemperature() {
return mTemperature + "°";
}
public String getCity() {
return mCity;
}
public String getIconname() {
return mIconname;
}
}
Try checking if the JSON object exists first:
if (jsonObjectjsonObject.getJSONArray("weather").getJSONObject(0).has("id")) {
weatherData.mCity = jsonObject.getString("name");
weatherData.mIconname = updateWeatherIcon(weatherData.mCondition);
}
I'm seeing the same stacktrace with slightly different message after building with Firebase SDK 15.0.0 (released April 10):
org.json.JSONException: No value for userMetadata
For me, the exception is non-fatal and only occurs the first time the new build is run on a device. I think it can be ignored.
If you are seeing the error repeatedly, or it is causing problems, downgrade to Firebase 12.0.1.
I'm new to the Android Development and I'm trying to accomplish a Android application, Where I can Search the Places using Auto-Complete and mark that place on a Google Map.
Here's my activity_city_maps.xml file
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/constraintLayout_map_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CityMapsActivity">
<AutoCompleteTextView
android:id="#+id/editText_source"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:ems="10"
android:hint="Select Source"
android:inputType="textPersonName"
app:layout_constraintEnd_toStartOf="#+id/button_source_update"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/button_source_update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:text="Set Source"
app:layout_constraintBaseline_toBaselineOf="#+id/editText_source"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="#+id/editText_source" />
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/button_source_update"
tools:context=".CityMapsActivity" />
</android.support.constraint.ConstraintLayout>
And here my CityMapsActivity.java file
package com.softvision.gotogether.app;
//Imports hidden
public class CityMapsActivity extends FragmentActivity implements
GoogleMap.OnMyLocationButtonClickListener,
GoogleMap.OnMyLocationClickListener,
OnMapReadyCallback,
OnRequestPermissionsResultCallback,
GoogleApiClient.OnConnectionFailedListener,
GoogleApiClient.ConnectionCallbacks{
/* AUTO-COMPLETE PROPERTIES
* ----------------------------------------------------------------------------------------------*/
private static final String LOG_TAG = "CityMapsActivity";
private GoogleApiClient client;
private static final int GOOGLE_API_CLIENT_ID = 0;
private static final LatLngBounds BOUNDS_MOUNTAIN_VIEW = new LatLngBounds(
new LatLng(37.398160, -122.180831), new LatLng(37.430610, -121.972090));
private PlaceArrayAdapter mPlaceArrayAdapter;
private AutoCompleteTextView editTextSource;
/* MAP PROPERTIES
* ----------------------------------------------------------------------------------------------*/
private GoogleMap mMap;
private ArrayList<LatLng> markerPoints = new ArrayList<>();
//Request code for location permission request.
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1;
//Flag indicating whether a requested permission has been denied after returning in
private boolean mPermissionDenied = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_city_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);
// Location Auto complete
client = new GoogleApiClient.Builder(CityMapsActivity.this)
.addApi(Places.GEO_DATA_API)
.enableAutoManage(this, GOOGLE_API_CLIENT_ID, this)
.addConnectionCallbacks(this)
.build();
editTextSource = (AutoCompleteTextView) findViewById(R.id.editText_source);
editTextSource.setThreshold(3);
editTextSource.setOnItemClickListener(autoCompleteClickListener);
mPlaceArrayAdapter = new PlaceArrayAdapter(this, android.R.layout.simple_list_item_1,BOUNDS_MOUNTAIN_VIEW, null);
editTextSource.setAdapter(mPlaceArrayAdapter);
}
/* ----------------------------------------------------------------------------------------------------
BEGIN: LOCATION AUTO COMPLETE SECTION
------------------------------------------------------------------------------------------------------*/
private AdapterView.OnItemClickListener autoCompleteClickListener = new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final PlaceArrayAdapter.PlaceAutocomplete item = mPlaceArrayAdapter.getItem(position);
final String placeId = String.valueOf(item.placeId);
Log.i(LOG_TAG, "Selected: " + item.description);
PendingResult<PlaceBuffer> placeResult = Places.GeoDataApi.getPlaceById(client, placeId);
placeResult.setResultCallback(mUpdatePlaceDetailsCallback);
Log.i(LOG_TAG, "Fetching details for ID: " + item.placeId);
}
};
private ResultCallback<PlaceBuffer> mUpdatePlaceDetailsCallback
= new ResultCallback<PlaceBuffer>() {
#Override
public void onResult(PlaceBuffer places) {
if (!places.getStatus().isSuccess()) {
Log.e(LOG_TAG, "Place query did not complete. Error: " +
places.getStatus().toString());
return;
}
// Selecting the first object buffer.
final Place place = places.get(0);
/*
CharSequence attributions = places.getAttributions();
mNameTextView.setText(Html.fromHtml(place.getName() + ""));
mAddressTextView.setText(Html.fromHtml(place.getAddress() + ""));
mIdTextView.setText(Html.fromHtml(place.getId() + ""));
mPhoneTextView.setText(Html.fromHtml(place.getPhoneNumber() + ""));
mWebTextView.setText(place.getWebsiteUri() + "");
if (attributions != null) {
mAttTextView.setText(Html.fromHtml(attributions.toString()));
}*/
}
};
/* ----------------------------------------------------------------------------------------------------
END: LOCATION AUTO COMPLETE SECTION
------------------------------------------------------------------------------------------------------*/
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// Enable my location option for map.
enableMyLocation();
mMap.setOnMyLocationButtonClickListener(this);
mMap.setOnMyLocationClickListener(this);
// Creating Markers by clicking on map
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
#Override
public void onMapClick(LatLng latLng) {
MarkerOptions options = new MarkerOptions();
if(markerPoints.size()>1){
markerPoints.clear();
mMap.clear();
}
// Add new Point
markerPoints.add(latLng);
options.position(latLng);
if(markerPoints.size()==1){
options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
options.title("Source");
editTextSource.setText(getCompleteAddressString(latLng.latitude, latLng.longitude));
}else if(markerPoints.size()==2){
options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
options.title("Destination");
}
mMap.addMarker(options);
if(markerPoints.size() >= 2){
LatLng origin = markerPoints.get(0);
LatLng dest = markerPoints.get(1);
String url = getDirectionsUrl(origin, dest);
DownloadTask downloadTask = new DownloadTask();
downloadTask.execute(url);
}
}
});
mMap.setOnMarkerClickListener((new GoogleMap.OnMarkerClickListener(){
#Override
public boolean onMarkerClick(Marker marker) {
if(marker.isInfoWindowShown()) {
marker.hideInfoWindow();
} else {
marker.showInfoWindow();
}
//.setText(myMarker.getTitle()); //Change TextView text here like this
return true;
}
}));
// Add a marker in Sydney and move the camera
/*
LatLng destination = new LatLng(12.354509, 76.603085);
mMap.addMarker(new MarkerOptions().position(destination).title("Softvision, LLC (DBA Software Paradigms Infotech Pvt Ltd)"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(destination));
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(destination.latitude, destination.longitude), 12.0f));
*/
}
#Override
public void onMyLocationClick(#NonNull Location location) {
Toast.makeText(this, "Current location:\n" + location, Toast.LENGTH_LONG).show();
}
private void enableMyLocation() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// Permission to access the location is missing.
PermissionUtils.requestPermission(this, LOCATION_PERMISSION_REQUEST_CODE, Manifest.permission.ACCESS_FINE_LOCATION, true);
} else if (mMap != null) {
// Access to the location has been granted to the app.
mMap.setMyLocationEnabled(true);
}
}
#Override
public boolean onMyLocationButtonClick() {
Toast.makeText(this, "Searching for location...", Toast.LENGTH_SHORT).show();
// Return false so that we don't consume the event and the default behavior still occurs
// (the camera animates to the user's current position).
return false;
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,#NonNull int[] grantResults) {
if (requestCode != LOCATION_PERMISSION_REQUEST_CODE) {
return;
}
if (PermissionUtils.isPermissionGranted(permissions, grantResults, Manifest.permission.ACCESS_FINE_LOCATION)) {
// Enable the my location layer if the permission has been granted.
enableMyLocation();
} else {
// Display the missing permission error dialog when the fragments resume.
mPermissionDenied = true;
}
}
#Override
protected void onResumeFragments() {
super.onResumeFragments();
if (mPermissionDenied) {
// Permission was not granted, display error dialog.
showMissingPermissionError();
mPermissionDenied = false;
}
}
private void showMissingPermissionError() {
PermissionUtils.PermissionDeniedDialog.newInstance(true).show(getSupportFragmentManager(), "dialog");
}
/* -------------------------------------------------------------------------------------------------------------
BEGIN [GoogleApiClient] :Overrides for :
GoogleApiClient.OnConnectionFailedListener,
GoogleApiClient.ConnectionCallback
---------------------------------------------------------------------------------------------------------------*/
#Override
public void onConnected(#Nullable Bundle bundle) {
mPlaceArrayAdapter.setGoogleApiClient(client);
Log.i(LOG_TAG, "Google Places API connected.");
}
#Override
public void onConnectionSuspended(int i) {
mPlaceArrayAdapter.setGoogleApiClient(null);
Log.e(LOG_TAG, "Google Places API connection suspended.");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.e(LOG_TAG, "Google Places API connection failed with error code: "
+ connectionResult.getErrorCode());
Toast.makeText(this,
"Google Places API connection failed with error code:" + connectionResult.getErrorCode(), Toast.LENGTH_LONG)
.show();
}
/* -------------------------------------------------------------------------------------------------------------
END [GoogleApiClient]
---------------------------------------------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------------------------------------------*/
/* Map Utility Section */
/*-------------------------------------------------------------------------------------------------------------*/
private String getCompleteAddressString(double LATITUDE, double LONGITUDE) {
String strAdd = "";
Geocoder geocoder = new Geocoder(this, Locale.getDefault());
try {
List<Address> addresses = geocoder.getFromLocation(LATITUDE,LONGITUDE, 1);
if (addresses != null) {
Address returnedAddress = addresses.get(0);
StringBuilder strReturnedAddress = new StringBuilder("");
for (int i = 0; i < returnedAddress.getMaxAddressLineIndex(); i++) {
strReturnedAddress.append(returnedAddress.getAddressLine(i)).append(",");
}
strAdd = strReturnedAddress.toString();
} else {
strAdd = "No Address returned!";
}
} catch (Exception e) {
e.printStackTrace();
strAdd = e.getMessage();
}
return strAdd;
}
private String getDirectionsUrl(LatLng origin,LatLng dest){
// Origin of route
String str_origin = String.format("origin=%s,%s", origin.latitude, origin.longitude);
// Destination of route
String str_dest = "destination="+dest.latitude+","+dest.longitude;
// Sensor enabled
String sensor = "sensor=false";
// Building the parameters to the web service
String parameters = str_origin+"&"+str_dest+"&"+sensor;
// Output format
String output = "json";
String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parameters;
return url;
}
#SuppressLint("LongLogTag")
private String downloadUrl(String strUrl) throws IOException {
String data = "";
InputStream iStream = null;
HttpURLConnection urlConnection = null;
try{
URL url = new URL(strUrl);
urlConnection = (HttpURLConnection) url.openConnection();
// Connecting to url
urlConnection.connect();
// Reading data from url
iStream = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(iStream));
StringBuffer sb = new StringBuffer();
String line = "";
while( ( line = br.readLine()) != null){
sb.append(line);
}
data = sb.toString();
br.close();
}catch(Exception e){
Log.d("Exception while downloading url", e.toString());
}finally{
iStream.close();
urlConnection.disconnect();
}
return data;
}
// Fetches data from url passed
private class DownloadTask extends AsyncTask<String, Void, String> {
// Downloading data in non-ui thread
#Override
protected String doInBackground(String... url) {
// For storing data from web service
String data = "";
try{
// Fetching the data from web service
data = downloadUrl(url[0]);
}catch(Exception e){
Log.d("Background Task",e.toString());
}
return data;
}
// Executes in UI thread, after the execution of
// doInBackground()
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
ParserTask parserTask = new ParserTask();
// Invokes the thread for parsing the JSON data
parserTask.execute(result);
}
}
private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String,String>>>> {
#Override
protected List<List<HashMap<String, String>>> doInBackground(String... jsonData) {
JSONObject jObject;
List<List<HashMap<String, String>>> routes = null;
try{
jObject = new JSONObject(jsonData[0]);
GmapUtility parser = new GmapUtility();
// Starts parsing data
routes = parser.parseJson(jObject);
}catch(Exception e){
e.printStackTrace();
}
return routes;
}
#Override
protected void onPostExecute(List<List<HashMap<String, String>>> result) {
ArrayList<LatLng> points = null;
PolylineOptions lineOptions = null;
MarkerOptions markerOptions = new MarkerOptions();
// Traversing through all the routes
for(int i=0;i<result.size();i++){
points = new ArrayList<LatLng>();
lineOptions = new PolylineOptions();
// Fetching i-th route
List<HashMap<String, String>> path = result.get(i);
// Fetching all the points in i-th route
for(int j=0;j<path.size();j++){
HashMap<String,String> point = path.get(j);
double lat = Double.parseDouble(point.get("lat"));
double lng = Double.parseDouble(point.get("lng"));
LatLng position = new LatLng(lat, lng);
points.add(position);
}
// Adding all the points in the route to LineOptions
lineOptions.addAll(points)
.width(12)
.color(Color.parseColor("#05b1fb"))//Google maps blue color
.geodesic(true);
}
// Drawing polyline in the Google Map for the i-th route
mMap.addPolyline(lineOptions);
}
}
}
And here is my PlaceArrayAdapter.java file
package com.softvision.gotogether.app;
/*imports hidden*/
public class PlaceArrayAdapter
extends ArrayAdapter<PlaceArrayAdapter.PlaceAutocomplete> implements Filterable {
private static final String TAG = "PlaceArrayAdapter";
private GoogleApiClient mGoogleApiClient;
private AutocompleteFilter mPlaceFilter;
private LatLngBounds mBounds;
private ArrayList<PlaceAutocomplete> mResultList;
/**
* Constructor
*
* #param context Context
* #param resource Layout resource
* #param bounds Used to specify the search bounds
* #param filter Used to specify place types
*/
public PlaceArrayAdapter(Context context, int resource, LatLngBounds bounds,AutocompleteFilter filter) {
super(context, resource);
mBounds = bounds;
mPlaceFilter = filter;
}
public void setGoogleApiClient(GoogleApiClient googleApiClient) {
if (googleApiClient == null || !googleApiClient.isConnected()) {
mGoogleApiClient = null;
} else {
mGoogleApiClient = googleApiClient;
}
}
#Override
public int getCount() {
return mResultList.size();
}
#Override
public PlaceAutocomplete getItem(int position) {
return mResultList.get(position);
}
private ArrayList<PlaceAutocomplete> getPredictions(CharSequence constraint) {
if (mGoogleApiClient != null) {
Log.i(TAG, "Executing autocomplete query for: " + constraint);
PendingResult<AutocompletePredictionBuffer> results =
Places.GeoDataApi.getAutocompletePredictions(mGoogleApiClient, constraint.toString(),mBounds, mPlaceFilter);
// Wait for predictions, set the timeout.
AutocompletePredictionBuffer autocompletePredictions = results.await(60, TimeUnit.SECONDS);
final Status status = autocompletePredictions.getStatus();
if (!status.isSuccess()) {
Toast.makeText(getContext(), "Error: " + status.toString(),Toast.LENGTH_SHORT).show();
Log.e(TAG, "Error getting place predictions: " + status.toString());
autocompletePredictions.release();
return null;
}
Log.i(TAG, "Query completed. Received " + autocompletePredictions.getCount()
+ " predictions.");
Iterator<AutocompletePrediction> iterator = autocompletePredictions.iterator();
ArrayList resultList = new ArrayList<>(autocompletePredictions.getCount());
while (iterator.hasNext()) {
AutocompletePrediction prediction = iterator.next();
resultList.add(new PlaceAutocomplete(prediction.getPlaceId(),prediction.getFullText(null)));
}
// Buffer release
autocompletePredictions.release();
return resultList;
}
Log.e(TAG, "Google API client is not connected.");
return null;
}
#Override
public Filter getFilter() {
Filter filter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null) {
// Query the autocomplete API for the entered constraint
mResultList = getPredictions(constraint);
if (mResultList != null) {
// Results
results.values = mResultList;
results.count = mResultList.size();
}
}
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results != null && results.count > 0) {
// The API returned at least one result, update the data.
notifyDataSetChanged();
} else {
// The API did not return any results, invalidate the data set.
notifyDataSetInvalidated();
}
}
};
return filter;
}
class PlaceAutocomplete {
public CharSequence placeId;
public CharSequence description;
PlaceAutocomplete(CharSequence placeId, CharSequence description) {
this.placeId = placeId;
this.description = description;
}
#Override
public String toString() {
return description.toString();
}
}
}
Here, when I build the application, I'm getting the following build warnings on Gradle Console and Build was successful:
:app:compileDebugJavaWithJavac
E:\AndroidApps\GoTogether\app\src\main\java\com\softvision\gotogether\app\PlaceArrayAdapter.java:88: warning: [unchecked] unchecked call to add(E) as a member of the raw type ArrayList
resultList.add(new PlaceAutocomplete(prediction.getPlaceId(),prediction.getFullText(null)));
^
where E is a type-variable:
E extends Object declared in class ArrayList
E:\AndroidApps\GoTogether\app\src\main\java\com\softvision\gotogether\app\PlaceArrayAdapter.java:92: warning: [unchecked] unchecked conversion
return resultList;
^
required: ArrayList<PlaceArrayAdapter.PlaceAutocomplete>
found: ArrayList
E:\AndroidApps\GoTogether\app\src\main\java\com\softvision\gotogether\app\GmapUtility.java:47: warning: [unchecked] unchecked call to add(E) as a member of the raw type List
path.add(hm);
^
where E is a type-variable:
E extends Object declared in interface List
E:\AndroidApps\GoTogether\app\src\main\java\com\softvision\gotogether\app\GmapUtility.java:50: warning: [unchecked] unchecked method invocation: method add in interface List is applied to given types
routes.add(path);
^
required: E
found: List
where E is a type-variable:
E extends Object declared in interface List
E:\AndroidApps\GoTogether\app\src\main\java\com\softvision\gotogether\app\GmapUtility.java:50: warning: [unchecked] unchecked conversion
routes.add(path);
^
required: E
found: List
where E is a type-variable:
E extends Object declared in interface List
5 warnings
And when I run the application on my device, It's crashing. Errors on Run Console as below:
Exception_1 = java.lang.ClassNotFoundException: Didn't find class "com.qualcomm.qti.Performance" on path: DexPathList[[],nativeLibraryDirectories=[/system/lib64, /vendor/lib64]]
V/BoostFramework: BoostFramework() : mPerf = null
D/ViewRootImpl#27d899d[CityMapsActivity]: ViewPostImeInputStage processPointer 1
D/InputMethodManager: ISS - flag : 0Pid : 21012 view : com.softvision.gotogether.app
D/ViewRootImpl#27d899d[CityMapsActivity]: MSG_RESIZED: ci=Rect(0, 42 - 0, 0) vi=Rect(0, 42 - 0, 494) or=1
I/PlaceArrayAdapter: Executing autocomplete query for: usa
E/PlaceArrayAdapter: Error getting place predictions: Status{statusCode=ERROR, resolution=null}
Please help me on this.
Try setting multiDexEnabled true in your app Gradle file, inside android {defaultConfig{}}.
And I would suggest using the default ArrayAdapter instead of a custom adapter for the AutoCompleteTextView.
EDIT:
The standard way of using an ArrayAdapter is:
// The sample String array, you can use either this or List<String>
String[] countries = getResources().getStringArray(R.array.list_of_countries);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, countries);
editTextSource.setAdapter(adapter);
Android documentation for AutoCompleteTextView: https://developer.android.com/reference/android/widget/AutoCompleteTextView.html
Useful tutorial: https://www.tutorialspoint.com/android/android_auto_complete.htm
I am fairly new to Android development and am creating an application which uses a Google map fragment. I am querying the Google Directions Api and retrieving JSON data using an AsyncTask method. I then decode the polyline and in turn gain a string array of LatLon pairs. I now would now like to use this string array back in my MainActivity. I have tried many ways to do this, however every single way has made the string array null.
Method tried = 1) using a static field 2) using Intent objects to transfer data 3) creating an interface.
Could someone please tell me as to how I should go around this and why it keeps becoming null in my MainActivity? Snippets of my code are below, thanks.
public class GetDirectionsData extends AsyncTask<Object, String,
String>
{
private GoogleMap mMap;
private Context context;
private String url , googleDirectionsData;
private String distance,duration;
private LatLng destinationLatLng;
private String[] directionsList;
public GetDirectionsData(Context context)
{
this.context = context;
}
#Override
protected String doInBackground(Object... objects)
{
mMap = (GoogleMap)objects[0];
url = (String)objects[1];
destinationLatLng = (LatLng)objects[2];
DownloadUrl downloadURL = new DownloadUrl();
try
{
googleDirectionsData = downloadURL.readUrl(url);
}
catch (IOException e)
{
e.printStackTrace();
}
return googleDirectionsData;
}
#Override
protected void onPostExecute(String s)
{
// uses other class DataParser to extract relevant JSONdata and
// displays polyline
DataParser directionParser = new DataParser();
directionsList = directionParser.parseDirections(s);
displayDirection(directionsList);
}
public void displayDirection(String[] directionsList)
{
int count = directionsList.length;
for(int i = 0; i < count; i++)
{
PolylineOptions options = new PolylineOptions();
options.color(Color.BLUE);
options.width(10);
options.addAll(PolyUtil.decode(directionsList[i])); // decode polylines
mMap.addPolyline(options);
}
}
I now want to pass directionsList string array back to MapsActivity Below
public class MapsActivity extends FragmentActivity
{
public void onClick(View v)
{
Object directionDataTransfer[];
// DIRECTIONS BUTTON
switch(v.getId())
{
case R.id.IB_search:
directionDataTransfer = new Object[3];
GetDirectionsData getDirectionsData = new GetDirectionsData(this);
String directionsUrl = getDirectionsUrl();
directionDataTransfer[0] = mMap;
directionDataTransfer[1] = directionsUrl;
directionDataTransfer[2] = new LatLng(//destination LatLon)
getDirectionsData.execute(directionDataTransfer);
Toast.makeText(MapsActivity.this, "Fetching directions", Toast.LENGTH_LONG).show();
}
}
private String getDirectionsUrl()
{
StringBuilder googleDirectionsUrl = new StringBuilder("https://maps.googleapis.com/maps/api/directions/json?");
googleDirectionsUrl.append("origin=" + originLat + "," + originLon);
googleDirectionsUrl.append("&destination=" + destinationLat + "," + destinationLon);
googleDirectionsUrl.append("&mode=" + modeOfTransport);
googleDirectionsUrl.append("&waypoints=via:" + waypointsLat + "," + waypointsLon);
googleDirectionsUrl.append("&key=" + googleApiKey);
return( googleDirectionsUrl.toString() );
}
}
Here is one of the example using Interface - hope this helps.
DummyAsyncTask.java
import android.os.AsyncTask;
public class DummyAsyncTask extends AsyncTask<Void, Void, String> {
private DummyInterface mListener = null;
DummyAsyncTask(DummyInterface listener) {
mListener = listener;
}
#Override
protected String doInBackground(Void... voids) {
return s; // return your string from doInBackground(it will be available as a parameter in onPostExecute())
}
#Override
protected void onPostExecute(String s) {
if(mListener != null) {
mListener.onCallback(s); // sending string s back to activity which registered for callback
}
}
}
DummyInterface.java
public interface DummyInterface {
void onCallback(String s); // callback API
}
DummyActivity.java
import android.app.Activity;
import android.os.Bundle;
public class DummyActivity extends Activity implements DummyInterface{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new DummyAsyncTask(this).execute();
}
#Override
public void onCallback(String s) {
System.out.println("String s = " + s);
}
}
The following app upload video to Dropbox when it is start, I added finish() in the end of onCreate to exit the app when its completed the uploading, but I got "Unfortunately, DBRoulette has stopped.".
In the Eclipse LogCat:
Activity com.dropbox.android.sample.DBRoulette has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView#42a7ee38 that was originally added here
android.view.WindowLeaked: Activity com.dropbox.android.sample.DBRoulette has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView#42a7ee38 that was originally added here
I have Progress viewer which may cause the problem but I don't know how to solve it!
What I want to do is closing the app automatically when the uploading completed.
DBRoulette.java
#SuppressLint("SimpleDateFormat")
public class DBRoulette extends Activity {
private static final String TAG = "DBRoulette";
final static private String APP_KEY = "<My APP_KEY>";
final static private String APP_SECRET = "<My APP_SECRET>";
// You don't need to change these, leave them alone.
final static private String ACCOUNT_PREFS_NAME = "prefs";
final static private String ACCESS_KEY_NAME = "ACCESS_KEY";
final static private String ACCESS_SECRET_NAME = "ACCESS_SECRET";
private static final boolean USE_OAUTH1 = false;
DropboxAPI<AndroidAuthSession> mApi;
private boolean mLoggedIn;
// Android widgets
private Button mSubmit;
private RelativeLayout mDisplay;
private Button mGallery;
private ImageView mImage;
private final String PHOTO_DIR = "/Motion/";
#SuppressWarnings("unused")
final static private int NEW_PICTURE = 50;
private String mCameraFileName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mCameraFileName = savedInstanceState.getString("mCameraFileName");
}
// We create a new AuthSession so that we can use the Dropbox API.
AndroidAuthSession session = buildSession();
mApi = new DropboxAPI<AndroidAuthSession>(session);
// Basic Android widgets
setContentView(R.layout.main);
checkAppKeySetup();
mSubmit = (Button) findViewById(R.id.auth_button);
mSubmit.setOnClickListener(new OnClickListener() {
#SuppressWarnings("deprecation")
public void onClick(View v) {
// This logs you out if you're logged in, or vice versa
if (mLoggedIn) {
logOut();
} else {
// Start the remote authentication
if (USE_OAUTH1) {
mApi.getSession().startAuthentication(DBRoulette.this);
} else {
mApi.getSession().startOAuth2Authentication(
DBRoulette.this);
}
}
}
});
mDisplay = (RelativeLayout) findViewById(R.id.logged_in_display);
// This is where a photo is displayed
mImage = (ImageView) findViewById(R.id.image_view);
File outFile = new File("/mnt/sdcard/ipwebcam_videos/video.mov");
mCameraFileName = outFile.toString();
UploadPicture upload = new UploadPicture(DBRoulette.this, mApi, PHOTO_DIR,outFile);
upload.execute();
// Display the proper UI state if logged in or not
setLoggedIn(mApi.getSession().isLinked());
finish();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putString("mCameraFileName", mCameraFileName);
super.onSaveInstanceState(outState);
}
#Override
protected void onResume() {
super.onResume();
AndroidAuthSession session = mApi.getSession();
if (session.authenticationSuccessful()) {
try {
session.finishAuthentication();
storeAuth(session);
setLoggedIn(true);
} catch (IllegalStateException e) {
showToast("Couldn't authenticate with Dropbox:"
+ e.getLocalizedMessage());
Log.i(TAG, "Error authenticating", e);
}
}
}
private void logOut() {
// Remove credentials from the session
mApi.getSession().unlink();
clearKeys();
// Change UI state to display logged out version
setLoggedIn(false);
}
#SuppressWarnings("deprecation")
public String getRealPathFromURI(Uri contentUri)
{
String[] proj = { MediaStore.Audio.Media.DATA };
Cursor cursor = managedQuery(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
private void setLoggedIn(boolean loggedIn) {
mLoggedIn = loggedIn;
if (loggedIn) {
mSubmit.setText("Logout from Dropbox");
mDisplay.setVisibility(View.VISIBLE);
} else {
mSubmit.setText("Login with Dropbox");
mDisplay.setVisibility(View.GONE);
mImage.setImageDrawable(null);
}
}
private void checkAppKeySetup() {
// Check to make sure that we have a valid app key
if (APP_KEY.startsWith("CHANGE") || APP_SECRET.startsWith("CHANGE")) {
showToast("You must apply for an app key and secret from developers.dropbox.com, and add them to the DBRoulette ap before trying it.");
finish();
return;
}
// Check if the app has set up its manifest properly.
Intent testIntent = new Intent(Intent.ACTION_VIEW);
String scheme = "db-" + APP_KEY;
String uri = scheme + "://" + AuthActivity.AUTH_VERSION + "/test";
testIntent.setData(Uri.parse(uri));
PackageManager pm = getPackageManager();
if (0 == pm.queryIntentActivities(testIntent, 0).size()) {
showToast("URL scheme in your app's "
+ "manifest is not set up correctly. You should have a "
+ "com.dropbox.client2.android.AuthActivity with the "
+ "scheme: " + scheme);
finish();
}
}
private void showToast(String msg) {
Toast error = Toast.makeText(this, msg, Toast.LENGTH_LONG);
error.show();
}
/**
* Shows keeping the access keys returned from Trusted Authenticator in a
* local store, rather than storing user name & password, and
* re-authenticating each time (which is not to be done, ever).
*/
private void loadAuth(AndroidAuthSession session) {
SharedPreferences prefs = getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
String key = prefs.getString(ACCESS_KEY_NAME, null);
String secret = prefs.getString(ACCESS_SECRET_NAME, null);
if (key == null || secret == null || key.length() == 0
|| secret.length() == 0)
return;
if (key.equals("oauth2:")) {
// If the key is set to "oauth2:", then we can assume the token is
// for OAuth 2.
session.setOAuth2AccessToken(secret);
} else {
// Still support using old OAuth 1 tokens.
session.setAccessTokenPair(new AccessTokenPair(key, secret));
}
}
/**
* Shows keeping the access keys returned from Trusted Authenticator in a
* local store, rather than storing user name & password, and
* re-authenticating each time (which is not to be done, ever).
*/
private void storeAuth(AndroidAuthSession session) {
// Store the OAuth 2 access token, if there is one.
String oauth2AccessToken = session.getOAuth2AccessToken();
if (oauth2AccessToken != null) {
SharedPreferences prefs = getSharedPreferences(ACCOUNT_PREFS_NAME,
0);
Editor edit = prefs.edit();
edit.putString(ACCESS_KEY_NAME, "oauth2:");
edit.putString(ACCESS_SECRET_NAME, oauth2AccessToken);
edit.commit();
return;
}
// Store the OAuth 1 access token, if there is one. This is only
// necessary if
// you're still using OAuth 1.
AccessTokenPair oauth1AccessToken = session.getAccessTokenPair();
if (oauth1AccessToken != null) {
SharedPreferences prefs = getSharedPreferences(ACCOUNT_PREFS_NAME,
0);
Editor edit = prefs.edit();
edit.putString(ACCESS_KEY_NAME, oauth1AccessToken.key);
edit.putString(ACCESS_SECRET_NAME, oauth1AccessToken.secret);
edit.commit();
return;
}
}
private void clearKeys() {
SharedPreferences prefs = getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
Editor edit = prefs.edit();
edit.clear();
edit.commit();
}
private AndroidAuthSession buildSession() {
AppKeyPair appKeyPair = new AppKeyPair(APP_KEY, APP_SECRET);
AndroidAuthSession session = new AndroidAuthSession(appKeyPair);
loadAuth(session);
return session;
}
}
UploadPicture.java
public class UploadPicture extends AsyncTask<Void, Long, Boolean> {
private DropboxAPI<?> mApi;
private String mPath;
private File mFile;
private long mFileLen;
private UploadRequest mRequest;
private Context mContext;
private final ProgressDialog mDialog;
private String mErrorMsg;
private File outFiles;
public UploadPicture(Context context, DropboxAPI<?> api, String dropboxPath,
File file) {
// We set the context this way so we don't accidentally leak activities
mContext = context.getApplicationContext();
mFileLen = file.length();
mApi = api;
mPath = dropboxPath;
mFile = file;
Date dates = new Date();
DateFormat dfs = new SimpleDateFormat("yyyyMMdd-kkmmss");
String newPicFiles = dfs.format(dates) + ".mov";
String outPaths = new File(Environment
.getExternalStorageDirectory(), newPicFiles).getPath();
outFiles = new File(outPaths);
mDialog = new ProgressDialog(context);
mDialog.setMax(100);
mDialog.setMessage("Uploading " + outFiles.getName());
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.setProgress(0);
mDialog.setButton(ProgressDialog.BUTTON_POSITIVE, "Cancel", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// This will cancel the putFile operation
mRequest.abort();
}
});
mDialog.show();
}
#Override
protected Boolean doInBackground(Void... params) {
try {
// By creating a request, we get a handle to the putFile operation,
// so we can cancel it later if we want to
FileInputStream fis = new FileInputStream(mFile);
String path = mPath + outFiles.getName();
mRequest = mApi.putFileOverwriteRequest(path, fis, mFile.length(),
new ProgressListener() {
#Override
public long progressInterval() {
// Update the progress bar every half-second or so
return 500;
}
#Override
public void onProgress(long bytes, long total) {
publishProgress(bytes);
}
});
if (mRequest != null) {
mRequest.upload();
return true;
}
} catch (DropboxUnlinkedException e) {
// This session wasn't authenticated properly or user unlinked
mErrorMsg = "This app wasn't authenticated properly.";
} catch (DropboxFileSizeException e) {
// File size too big to upload via the API
mErrorMsg = "This file is too big to upload";
} catch (DropboxPartialFileException e) {
// We canceled the operation
mErrorMsg = "Upload canceled";
} catch (DropboxServerException e) {
// Server-side exception. These are examples of what could happen,
// but we don't do anything special with them here.
if (e.error == DropboxServerException._401_UNAUTHORIZED) {
// Unauthorized, so we should unlink them. You may want to
// automatically log the user out in this case.
} else if (e.error == DropboxServerException._403_FORBIDDEN) {
// Not allowed to access this
} else if (e.error == DropboxServerException._404_NOT_FOUND) {
// path not found (or if it was the thumbnail, can't be
// thumbnailed)
} else if (e.error == DropboxServerException._507_INSUFFICIENT_STORAGE) {
// user is over quota
} else {
// Something else
}
// This gets the Dropbox error, translated into the user's language
mErrorMsg = e.body.userError;
if (mErrorMsg == null) {
mErrorMsg = e.body.error;
}
} catch (DropboxIOException e) {
// Happens all the time, probably want to retry automatically.
mErrorMsg = "Network error. Try again.";
} catch (DropboxParseException e) {
// Probably due to Dropbox server restarting, should retry
mErrorMsg = "Dropbox error. Try again.";
} catch (DropboxException e) {
// Unknown error
mErrorMsg = "Unknown error. Try again.";
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return false;
}
#Override
protected void onProgressUpdate(Long... progress) {
int percent = (int)(100.0*(double)progress[0]/mFileLen + 0.5);
mDialog.setProgress(percent);
}
#Override
protected void onPostExecute(Boolean result) {
mDialog.dismiss();
if (result) {
showToast("Image successfully uploaded");
} else {
showToast(mErrorMsg);
}
}
private void showToast(String msg) {
Toast error = Toast.makeText(mContext, msg, Toast.LENGTH_LONG);
error.show();
}
}
Your problem is that you are trying to update an Activity's UI after the activity has finished.
First, you kick of an AsyncTask which posts progress updates to the UI thread. Then, before the task completes, you call finish(). Any updates to the Activity's UI after finish() is called are liable to throw exceptions, cause window leak issues, etc.
If you want to have any UI behavior as you perform your AsyncTask, you do not want to finish() the Activity until it the task is completed.
To achieve this, you could include a callback in the onPostExecute which tells the activity it is OK to finish once the AsyncTask completes.
This is how I would do it:
Change the signature of UploadPicture:
final Activity callingActivity;
public UploadPicture(final Activity callingActivity, DropboxAPI api, String dropboxPath, File file) {
Context mContext = callingActivity.getApplicationContext();
this.callingActivity = callingActivity;
Add the finish call to onPostExecute:
#Override
protected void onPostExecute(Boolean result) {
mDialog.dismiss();
if (result) {
showToast("Image successfully uploaded");
} else {
showToast(mErrorMsg);
}
callingActivity.finish(); //Finish activity only once you are done
}