I have a Google maps app that grabs the users lat and long values, and through the use of a Google JSON response stores a range of supermarket objects with their relative lat and long values. I use an overlay class to the place a marker onto the map dependent on the selected supermarket from the listview that shows the available supermarkets.
This all works fine, where I seem to be having a slight issue is with the accuracy of my overlay class. The map marker doesn't seem to be very accurate, in that the marker is pointing at the wrong place of the specified lat and long points passed to it from my geopoint object. (sometimes up to 11 miles away from where it should be).
I have tried declaring the LOCATION_FINE in my manifest on the uses permissions but this doesn't seem to make any difference. Do I need this as I'm using a JSON response rather than GPS?
How accurate is the map on the emulator? I may-be clutching at straws here but I have heard multiple people saying that when using the Google API's on the emulator it isn't that accurate.
No GPS is being used.
EDIT
To add to this question. I have another question that goes into more depth. I believe the issue is within my update() method as the issue is the incorrect object lat and long values are being sent to the marker.
I will post my code, just to see if anyone can find any issues.
GeoName class:
public class GeoName {
private String id;
private Geometry geometry;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Geometry getGeometry() {
return geometry;
}
public void setGeometry(Geometry geometry) {
this.geometry = geometry;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
PostalCodeAdapter class:
package com.example.restfulweb;
public class PostalCodeAdapter extends BaseAdapter {
private Context ctx = null;
Location l;
Dialog d;
Double Latt;
Double Longg;
private List<GeoName> names = new ArrayList<GeoName>();
public PostalCodeAdapter(Context ctx, List<GeoName> locations) {
this.ctx = ctx;
this.names = locations;
}
#Override
public int getCount() {
return names.size();
}
#Override
public Object getItem(int arg0) {
return null;
}
#Override
public long getItemId(int arg0) {
return 0;
}
#Override
public View getView(int arg0, View arg1, ViewGroup arg2) {
LinearLayout layout = new LinearLayout(ctx);
AbsListView.LayoutParams params = new AbsListView.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT);
layout.setLayoutParams(params);
layout.setOrientation(LinearLayout.HORIZONTAL);
GeoName location = this.names.get(arg0);
Location l = location.getGeometry().getLocation();
Latt = l.getLat();
Longg = l.getLng();
TextView value = new TextView(this.ctx);
value.setText(location.getName());
value.setMaxHeight(100);
value.setTypeface(Typeface.DEFAULT, Typeface.NORMAL);
value.setGravity(Gravity.CENTER);
value.setOnClickListener(new CityClickListener(location));
layout.addView(value);
return layout;
}
class CityClickListener implements OnClickListener {
private GeoName geoName = null;
CityClickListener(GeoName name) {
this.geoName = name;
}
#Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setView(createView());
builder.setTitle("Details of " + geoName.getName());
builder.setCancelable(true);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
updateMap();
}
private void updateMap() {
MapActivity mapAct = (MapActivity)ctx;
MapView map = (MapView)mapAct.findViewById(R.id.map);
map.setScrollBarStyle(MapView.SCROLLBARS_INSIDE_INSET);
map.setBuiltInZoomControls(Boolean.TRUE);
map.displayZoomControls(Boolean.TRUE);
********** ISSUE: THE PASSED LAT AND LONG VALUES ARE NOT BEING PASSED TO THE OVERLAY **********
GeoPoint point = new GeoPoint((int)(Latt* 1E6), (int)(Longg * 1E6));
MapController mc = map.getController();
mc.setZoom(17);
mc.setCenter(point);
mc.animateTo(point);
List<Overlay> overlay = map.getOverlays();
overlay.clear();
Drawable marker = ctx.getResources().getDrawable(R.drawable.marker);
MyItemizedOverlay overlays = new MyItemizedOverlay(marker, map, ctx);
OverlayItem pointerConverted = new OverlayItem(point, geoName.getName(), null);
overlay.add(overlays);
overlays.addOverlay(pointerConverted);
}
private View createView() {
LinearLayout l = new LinearLayout(ctx);
l.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams params = new LayoutParams(100, 300);
l.setLayoutParams(params);
TextView city = new TextView(ctx);
city.setText("Supermarket: " + geoName.getName() + "");
city.setMaxHeight(100);
city.setTypeface(Typeface.DEFAULT, Typeface.NORMAL);
city.setGravity(Gravity.CENTER);
//city.setTextColor(ctx.getResources().getColor(R.color.white));
TextView orientation = new TextView(ctx);
//orientation.setText("Orientation : " + geoName.lat + " || " + geoName.lng);
orientation.setMaxHeight(100);
orientation.setTypeface(Typeface.DEFAULT, Typeface.NORMAL);
orientation.setGravity(Gravity.CENTER);
l.addView(city);
l.addView(orientation);
return l;
}
}
}
Managed to sort this.
For anyone else who is using a JSON layered response. Make sure you access you lat and long values from the correct GeoPoint object classes.
for simplicity you can use Google Maps Android API v2 with recent updates your task becomes simpler.
https://developers.google.com/maps/documentation/android/start
You just need to create GoogleMap object and add appropriate listeners.
Related
It's happening for 0.08% of our users.
One of the crashes happening on Samsung Galaxy S10 running Android 11
It's not crashing on my Samsung Galaxy S10 running Android 11 though!
Does anyone know why?
Line where it crashes
Photo[] photoArray = (Photo[]) bundle.getParcelableArray(EXTRA_PHOTOS);
1st finding
Photo photo1 = new Photo(231, "url", "photoid", "profilid", "caption");
Parcelable[] parcelables1 = new Parcelable[]{photo1};
Photo[] array = (Photo[]) parcelables1;
Throws ClassCastException
This couple with the fact that Bundle#getParcelableArray only returns a Parcelable array, not the the concrete class Photo array explains why the crash is expected
But why is it only happening for some users only?
2nd finding
This post claims that getParcelableArray() won't work, only getParcelableArrayListExtra() or individual casting will work but the why is unclear to me
3rd finding
So I've learnt that downcasting arrays is not supposed to work in Java or Kotlin, at least not in the way Android Bundle do it.
The reason why getParcelableArrayListExtra() works is because it assume generic type and did work to handle the type.
Question remains: how come getParcelableArray() works nicely in my real device and emulator? Is there some black magic hidden in plain sight here?
Code below
Photo.java
public class Photo implements Serializable, Model, Parcelable {
private String caption;
private String id, idProfile;
private int position;
private String iphoneFullscreen;
public Photo(int position, String url, String photoId, String profileId, String caption) {
iphoneFullscreen = url;
this.position = position;
this.id = photoId;
idProfile = profileId;
this.caption = caption;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.caption);
dest.writeString(this.id);
dest.writeString(this.idProfile);
dest.writeInt(this.position);
dest.writeString(this.iphoneFullscreen);
}
protected Photo(Parcel in) {
this.caption = in.readString();
this.id = in.readString();
this.idProfile = in.readString();
this.position = in.readInt();
this.iphoneFullscreen = in.readString();
}
public static final Parcelable.Creator<Photo> CREATOR = new Parcelable.Creator<Photo>() {
#Override
public Photo createFromParcel(Parcel source) {
return new Photo(source);
}
#Override
public Photo[] newArray(int size) {
return new Photo[size];
}
};
}
How it's provided and consumed
DialogFragmentPhotoGallery.java
public static DialogFragment newInstance(
Photo[] photos) {
DialogFragmentPhotoGallery dialogFragmentPhotoGallery = new DialogFragmentPhotoGallery();
Bundle args = new Bundle();
args.putParcelableArray(DialogFragmentPhotoGallery.EXTRA_PHOTOS, photos);
dialogFragmentPhotoGallery.setArguments(args);
return dialogFragmentPhotoGallery;
}
public View onCreateView(
#NonNull LayoutInflater inflater,
ViewGroup parent,
Bundle savedInstanceState) {
if (getArguments() != null) {
Photo[] photos = (Photo[]) getArguments().getParcelableArray(EXTRA_PHOTOS); // <-- CRASH
// do things with photos
}
I am quite new to the Android Development and I really need your help. My problem is in the MainActivity below. The app essentially displays a list of movies in the main activity and the movie details in another activity. And the problem is that whenever a user comes back from the MovieActivity to the MainActivity, the loader starts loading data again, although the movies are already there. And then it can not stop loading the data. It is really annoying. I want to get rid of this. So when a user comes back to the MainActivity, the loader will know that there is already loaded data and will not load anything again.If it helps, here is my full GitHub repo https://github.com/mateuszwojnarowicz/PopularMovies
I am stuck for about 3 weeks and have tried hundreds of possible solutions. Nothing seems to work. I feel really desperate.
Thank you so much for help,
Matthew
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<String> {
private MovieAdapter mAdapter;
private ArrayList<Movie> mMoviesCollection;
private SharedPreferences sharedPreferences;
private Resources resources;
private LoaderManager loaderManager;
private Loader<String> loader;
private RecyclerView.LayoutManager layoutManager;
private String sortBy;
#BindView(R.id.pb)
ProgressBar progressBar;
#BindView(R.id.er)
TextView errorTextView;
#BindView(R.id.rv)
RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
mMoviesCollection = new ArrayList<Movie>();
sharedPreferences = getSharedPreferences(Constants.SHARED_PREFS, Activity.MODE_PRIVATE);
resources = getResources();
sortBy = sharedPreferences.getString(Constants.KEY_SORT, null);
setSharedPref();
layoutManager = new GridLayoutManager(this, calculateNoOfColumns(this));
loaderManager = getLoaderManager();
loader = loaderManager.getLoader(Constants.LOADER_MOVIES_ID);
initialize();
makeOperationLoadMovies(sortBy);
}
public static int calculateNoOfColumns(Context context) {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
float dpWidth = displayMetrics.widthPixels / displayMetrics.density;
int noOfColumns = (int) (dpWidth / 150);
return noOfColumns;
}
//Set first-launch pref and set title according to pref
private void setSharedPref(){
if(!sharedPreferences.contains(Constants.KEY_SORT)) {
saveData(Constants.VALUE_POP);
setTitle(resources.getString(R.string.title_pop));
} else {
if (Objects.equals(sharedPreferences.getString(Constants.KEY_SORT, null), Constants.VALUE_POP)) {
setTitle(resources.getString(R.string.title_pop));
}
if (Objects.equals(sharedPreferences.getString(Constants.KEY_SORT, null), Constants.VALUE_TOP)) {
setTitle(resources.getString(R.string.title_top));
}
}
}
//Set up the RecyclerView
private void initialize(){
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
mMoviesCollection = new ArrayList<>();
mAdapter = new MovieAdapter(mMoviesCollection, this, this);
recyclerView.setAdapter(mAdapter);
}
private void makeOperationLoadMovies(String SORT_BY){
Bundle bundle = new Bundle();
bundle.putString(Constants.LOADER_MOVIES_EXTRA, SORT_BY);
if(recyclerView.isDirty()){
}
else if(loader==null){
loaderManager.initLoader(Constants.LOADER_MOVIES_ID, bundle, this);
}else{
loaderManager.restartLoader(Constants.LOADER_MOVIES_ID, bundle, this);
}
}
//Update shared pref
private void saveData(String SORT_VALUE){
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(Constants.KEY_SORT, SORT_VALUE);
editor.apply();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id){
case R.id.menu_fav:
startActivity(new Intent(MainActivity.this, FavoritesActivity.class));
break;
case R.id.menu_pop:
saveData(Constants.VALUE_POP);
Toast.makeText(this, resources.getString(R.string.message_popularity),Toast.LENGTH_LONG).show();
break;
case R.id.menu_top:
saveData(Constants.VALUE_TOP);
Toast.makeText(this, resources.getString(R.string.message_rating),Toast.LENGTH_LONG).show();
break;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onPause() {
super.onPause();
Parcelable recyclerViewState;
recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState();//save
recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);
}
#Override
protected void onPostResume() {
super.onPostResume();
Parcelable recyclerViewState;
recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState();//save
recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);
}
#SuppressLint("StaticFieldLeak")
#Override
public Loader<String> onCreateLoader(int id, final Bundle args) {
return new AsyncTaskLoader<String>(this) {
#Override
protected void onStartLoading() {
super.onStartLoading();
forceLoad();
progressBar.setVisibility(View.VISIBLE);
errorTextView.setVisibility(View.INVISIBLE);
}
#Override
public void deliverResult(String data) {
super.deliverResult(data);
}
#Override
public String loadInBackground() {
String jsonString = "";
URL url = NetworkUtils.buildUrl(args.getString(Constants.LOADER_MOVIES_EXTRA));
try {
jsonString += NetworkUtils.getResponseFromHttpUrl(url);
} catch (IOException e) {
e.printStackTrace();
}
if(jsonString.isEmpty()){
} else {
try {
JSONObject jsonObject = new JSONObject(jsonString);
JSONArray jsonArray = jsonObject.getJSONArray(Constants.JSON_KEY_MOVIE_RESULTS);
for (int i = 0; i < jsonArray.length(); i++) {
//Get 1 movie from JSON
String mTitle;
int mId;
String mPosterUrl;
String mPlot;
double mUserRating;
String mReleaseDate;
JSONObject Jmovie = (JSONObject) jsonArray.get(i);
mTitle = Jmovie.getString(Constants.JSON_KEY_MOVIE_TITLE);
mId = Jmovie.getInt(Constants.JSON_KEY_MOVIE_ID);
mPosterUrl = NetworkUtils.getPosterString(Jmovie.getString(Constants.JSON_KEY_MOVIE_POSTER_PATH));
mPlot = Jmovie.getString(Constants.JSON_KEY_MOVIE_OVERVIEW);
mUserRating = Jmovie.getDouble(Constants.JSON_KEY_MOVIE_VOTE_AVERAGE);
mReleaseDate = Jmovie.getString(Constants.JSON_KEY_MOVIE_RELEASE_DATE);
//Get videos
ArrayList<Video> mVideos = new ArrayList<Video>();
URL videosURL = NetworkUtils.buildUrlVideos(String.valueOf(mId));
String videosJSON = NetworkUtils.getResponseFromHttpUrl(videosURL);
JSONObject jsonObjectVideos = new JSONObject(videosJSON);
JSONArray jsonArrayVideos = jsonObjectVideos.getJSONArray(Constants.JSON_KEY_VIDEO_RESULTS);
if(jsonArrayVideos.length()==0){
mVideos = null;
} else {
for(int v = 0; v < jsonArrayVideos.length(); v++){
JSONObject Jvideo = (JSONObject) jsonArrayVideos.get(v);
String mVideoName;
String mVideoUrlString;
mVideoName = Jvideo.getString(Constants.JSON_KEY_VIDEO_NAME);
mVideoUrlString = "https://www.youtube.com/watch?v="+Jvideo.getString(Constants.JSON_KEY_VIDEO_KEY);
Video video = new Video(mVideoName, mVideoUrlString);
mVideos.add(video);
}
}
//GetReviews
ArrayList<Review> mReviews = new ArrayList<Review>();
URL reviewsURL = NetworkUtils.buildUrlReviews(String.valueOf(mId));
String reviewsJSON = NetworkUtils.getResponseFromHttpUrl(reviewsURL);
JSONObject jsonObjectReviews = new JSONObject(reviewsJSON);
JSONArray jsonArrayReviews = jsonObjectReviews.getJSONArray(Constants.JSON_KEY_REVIEW_RESULTS);
if(jsonArrayReviews.length()!=0) {
for(int r = 0; r < jsonArrayReviews.length(); r++){
JSONObject Jreview = (JSONObject) jsonArrayReviews.get(r);
String mReviewName;
String mReviewText;
mReviewName = Jreview.getString(Constants.JSON_KEY_REVIEW_AUTHOR);
mReviewText = Jreview.getString(Constants.JSON_KEY_REVIEW_CONTENT);
Review review = new Review(mReviewName, mReviewText);
mReviews.add(review);
}
}
Movie movie = new Movie(mTitle, mId, mPosterUrl, mPlot, mUserRating, mReleaseDate, mVideos, mReviews);
mMoviesCollection.add(movie);
}
} catch (JSONException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}
}
return null;
}
};
}
#Override
public void onLoadFinished(Loader<String> loader, String data) {
progressBar.setVisibility(View.GONE);
mAdapter.notifyDataSetChanged();
}
#Override
public void onLoaderReset(Loader<String> loader) {
}
}
Because you are new to Android there is a lot wrong. So, many people probably won't want to chime in. Regardless, I'm new as well and in the same class as you are right now, so I'll give it a shot.
First, your loader is not returning the correct data type. Your loader should be of Loader<List<Movie>> and it should return a new AsyncTaskLoader<List<Movie>>. The reason you want this is to make use of everything the AsyncTaskLoader has to offer. I'll explain further.
Second, we'll cache the data inside the loader by moving the initial reference from the Activity into the loader.
So move private ArrayList<Movie> mMoviesCollection; as an instance variable of your AsyncTaskLoader. Remove the line mMoviesCollection = new ArrayList<Movie>(); from both your onCreate and initialize methods.
In your AsyncTaskLoader, you need to check if your data exists already in your onStartLoading before forceLoad and implement deliverResult.
So, your onStartLoading() should look like this:
#Override
protected void onStartLoading() {
super.onStartLoading();
if(mMoviesCollection.isEmpty()){
forceLoad();
progressBar.setVisibility(View.VISIBLE);
errorTextView.setVisibility(View.INVISIBLE);
} else {
deliverResult(mMoviesCollection)
}
}
And your deliverResult should look like this:
#Override
public void deliverResult(List<Movie> data) {
mMoviesCollection = data;
super.deliverResult(data);
}
Now you need to implement a setData(List<Movie> movies) method that sets your adapter's data instance variable and calls notifyDataSetChanged() in your Adapter. Like so:
public void setData(List<Movie> movies){
mMovies = movies;
notifyDataSetChanged();
}
Get rid of the List<Movie> from your adapter's constructor. This way you can construct the adapter without any data. The adapter's getItemCount() should return 0 if the data is null and the recyclerView will not try to build the view.
With that done you can then call onLoadFinished like this:
#Override
public void onLoadFinished(Loader<List<Movie>> loader, List<Movie> data) {
progressBar.setVisibility(View.GONE);
mAdapter.setData(data);
}
EDIT: Made a correction to account for the ArrayList instantiating as an Instance variable. You can either not instantiate the mMoviesCollection there and then do so later or just check if its empty with mMoviesCollection.isEmpty() as I changed above in onStartLoading.:
EDIT:
You need to get your libraries straight, you are using android.app in some places and android.support in others.
So in your imports change these:
import android.app.LoaderManager;
import android.content.AsyncTaskLoader;
import android.content.Loader;
all to:
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
Now the TMDB.org API has a request limit of 40 requests per 10 seconds.
https://developers.themoviedb.org/3/getting-started/request-rate-limiting
Because of this, your Loader is not even completing everything and is throwing an exception. I would suggest breaking up when you call the videos and reviews into the MovieActivity by creating another AsyncTaskLoader there and calling each when the details screen loads.
You could also technically add a Thread.sleep(300) or less to your AsyncTaskLoader but it makes it seriously slow. In other words, you would have to push the data beyond the 10-second mark to load completely.
Now, with that and the changes we have made, everything does survive config changes such as screen rotation.
If you want the data to survive any further you will have to persist the data somehow. Like saving the json response as a string in onSaveInstanceState or saving the JSon String to the database you created.
I have an 4 array list which i used in my custom adapter class. I want it to be in descending form depending on their ratings. i used collection.sort(ratings.Collection.reverseOrder()); it works fine it is arranging the ratings in descending form depending on their ratings but the other array list retain the same. i want them to be specify depending on their position.
i am using this code.
Collections.sort(mRatings,Collections.reverseOrder());
adapterz = new SummaryAdapter(MapsActivity.this, mNames,
mAddress, mRatings, mDistance);
recyclerView.setAdapter(adapterz);
adapterz.notifyDataSetChanged();
I have edited my answer to purposely clear anyone. im sorry im not much familiar in java. so hmm you suggested ill work on with comparable i tried it but it doesnt work well how am i going to deal with it? this is where i add data in my array list. btw i am using google nearby places and this is i add place details to the respective array list.
in my GetNearbyPlace class
else if (MapsActivity.x == "pStore") {
for (int i = 0; i < nearbyPlaceList.size(); i++) {
MarkerOptions markerOptions = new MarkerOptions();
HashMap<String, String> googlePlace = nearbyPlaceList.get(i);
placeName = googlePlace.get("place_name");
vicinity = googlePlace.get("vicinity");
String rating = googlePlace.get("rating");
double lat = Double.parseDouble(googlePlace.get("lat"));
double lng = Double.parseDouble(googlePlace.get("lng"));
String snippet = "Address: " + vicinity + "\n" +
// "Phone Number: " + formatted_phone_number + "\n" +
// "Website: " + url + "\n" +
"Place Rating: " + rating + "\n";
LatLng latLng = new LatLng(lat, lng);
markerOptions.position(latLng);
markerOptions.title(placeName);
markerOptions.snippet(snippet);
markerOptions.icon
(BitmapDescriptorFactory.fromResource(R.drawable.ic_pstore));
mMap.addMarker(markerOptions);
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(10));
MapsActivity.mNames.add( googlePlace.get("place_name"));
MapsActivity.mAddress.add(googlePlace.get("vicinity"));
int x = 0;
try {
x = Integer.parseInt(googlePlace.get("rating"));
} catch (NumberFormatException e) {
e.printStackTrace();
}
float results[] = new float[10];
Location.distanceBetween(MapsActivity.latitude,
MapsActivity.longitude,lat,lng,results);
int rate= 0;
try {
rate = new Integer(googlePlace.get("rating"));
} catch (NumberFormatException e) {
e.printStackTrace();
}
MapsActivity.mRatings.add(rate);
MapsActivity.mDistance.add(results[0]);
and in my MainActivity
I declare arraylist as global
public static ArrayList<String> mNames = new ArrayList<>();
public static ArrayList<String> mAddress = new ArrayList<>();
public static ArrayList<Integer> mRatings = new ArrayList<>();
public static ArrayList<Float> mDistance = new ArrayList<>();
//and then added it in to the adapter
Collections.sort(mDistance);
adapterz = new SummaryAdapter(MapsActivity.this, mNames,
mAddress, mRatings, mDistance);
recyclerView.setAdapter(adapterz);
adapterz.notifyDataSetChanged();
//My adapter
public class SummaryAdapter extends
RecyclerView.Adapter<SummaryAdapter.ViewHolder> {
private static final String TAG = "RecyclerViewAdapter";
//vars
private ArrayList<String> mNames = new ArrayList<>();
private ArrayList<String> mAddress = new ArrayList<>();
private ArrayList<Integer> mRatings = new ArrayList<>();
private ArrayList<Float> mDistance = new ArrayList<>();
private Context mContext;
public SummaryAdapter(Context context, ArrayList<String> name, ArrayList<String> address , ArrayList<Integer> ratings , ArrayList<Float> distance ) {
this.mNames = name;
this.mAddress = address;
this.mRatings = ratings;
this.mDistance = distance;
mContext = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.summaryadapter, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
holder.name.setText(mNames.get(position));
holder.address.setText(mAddress.get(position));
holder.distance.setText("Distance: "+mDistance.get(position)+"meters");
Toast.makeText(mContext,mImage.toString(),Toast.LENGTH_LONG).show();
float w = 0;
try {
w = new Float(mRatings.get(position));
} catch (NumberFormatException e) {
e.printStackTrace();
}
holder.rtnbar.setRating(w);
}
#Override
public int getItemCount() {
return mNames.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView name,address,distance;
RatingBar rtnbar;
ImageView img;
View mView;
public ViewHolder(View itemView) {
super(itemView);
mView = itemView;
address = itemView.findViewById(R.id.addresslist);
name = itemView.findViewById(R.id.namelist);
distance = itemView.findViewById(R.id.distancelist);
img=itemView.findViewById(R.id.imagelist);
rtnbar=itemView.findViewById(R.id.ratinglist);
}
}
}
Question, how am i going to switch my array list items in to a custom class where in ill put on my array list like names,rating etc.
Take one class define all the variable like rating,name ,etc and that class pass into list and that list pass into adapter..
after that if your rating value as long then perfrom decending order sorting like below ..
Collections.sort(indexResponsesList, new Comparator<UserData>() {
#Override
public int compare(UserData userData, UserData t1) {
Long idea1 = new Long(userData.getCreatedAt());// here pass rating value.
Long idea2 = new Long(t1.getCreatedAt());// here pass rating value.
return idea2.compareTo(idea1);
}
});
if (indexItemAdapter != null)
indexItemAdapter.notifyDataSetChanged();
anb if integer then replace Long data type as integer.
Create a class like this:
public class Person implements Comparable<Person> {
private String mName;
private String mAddress;
private int mRating;
private int mDistance;
Person(String name, String address, int rating, int distance) {
this.mName = name;
this.mAddress = address;
this.mRating = rating;
this.mDistance = distance;
}
#Override
public int compareTo(Person p) {
return -Integer.valueOf(mRating).compareTo(p.mRating);
}
}
and store all your data in 1 array persons of Person objects.
Then you sort the array: Arrays.sort(persons); and use it in your adapter.
First of all I am new to android and JAVA and as registered user of stackoverflow, but it helped me many times to find a good answer so, thank you for this community, got me many times out of mud with my school projects
I am here because I'm stuck in this small project, is an university one so no money involved.
I am trying to get a route displayed and update it as I move through the city using android google maps api. Until now I managed to get my location, and I can display a route between two points, but the problem is when I want to have the starting point from my current location, it seems I can't save it to a variable (or I don't know how) I used google example for map display as base.
I will post the entire code, maybe someone can also find it useful. Since is an university small project I don't have secrets to hide and I am here to learn so is nice to post the full code.
If someone has a hint for my problem I would appreciate. Thank you!
NOTE: the problem is getting this baby displaying the route from my current location to the second location that is a fixed one.
The main code is the following:
public class mapDisplay extends ActionBarMapActivity {
private LocationManager myLocationManager;
private LocationListener myLocationListener;
private MapController myMapController;
private MapView myMapView;
private MyLocationOverlay myLocation;
private void CenterLocatio(GeoPoint centerGeoPoint)
{
myMapController.animateTo(centerGeoPoint);
};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.map_screen);
myMapView = (MapView) findViewById(R.id.mapview);
//mapView.setBuiltInZoomControls(true);
myMapView.setSatellite(false); //Set satellite view
myMapController = myMapView.getController();
myMapController.setZoom(15); //Fixed Zoom Level
myLocationManager = (LocationManager)getSystemService(
Context.LOCATION_SERVICE);
//For enable location services dialogue
if (!myLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
createGpsDisabledAlert();
}
// see createGpsDisabledAlert function below
myLocationListener = new MyLocationListener();
myLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
0,
0,
myLocationListener);
//Get the current location in start-up
GeoPoint initGeoPoint = new GeoPoint(
(int)(myLocationManager.getLastKnownLocation(
LocationManager.GPS_PROVIDER)
.getLatitude()*1000000),
(int)(myLocationManager.getLastKnownLocation(
LocationManager.GPS_PROVIDER)
.getLongitude()*1000000));
CenterLocatio(initGeoPoint);
//draw the sample route
MapView mv = (MapView) findViewById(R.id.mapview);
mv.setBuiltInZoomControls(true);
MapController mc = mv.getController();
ArrayList all_geo_points = getDirections(50.0536, 8.69339, 50.021973, 8.69584);
GeoPoint moveTo = (GeoPoint) all_geo_points.get(0);
mc.animateTo(moveTo);
mc.setZoom(12);
mv.getOverlays().add(new MyOverlay(all_geo_points));
//Adding position icon for current location
// Add the MyLocationOverlay
myLocation = new MyLocationOverlay(this, myMapView);
myMapView.getOverlays().add(myLocation);
myLocation.enableMyLocation();
myLocation.runOnFirstFix(new Runnable() {
public void run() {
myMapController.animateTo(myLocation.getMyLocation());
}
});
}
private class MyLocationListener implements LocationListener{
public void onLocationChanged(Location argLocation) {
// TODO Auto-generated method stub
GeoPoint myGeoPoint = new GeoPoint(
(int)(argLocation.getLatitude()*1000000),
(int)(argLocation.getLongitude()*1000000));
CenterLocatio(myGeoPoint);
}
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
//toast shown if GPS is disabled
Context context = getApplicationContext();
CharSequence text = "GPS is disabled! If you want to take full advantage of map please enable the GPS!";
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
public void onStatusChanged(String provider,
int status, Bundle extras) {
// TODO Auto-generated method stub
}
}
#Override
protected void onResume() {
super.onResume();
myLocation.enableMyLocation();
}
#Override
protected void onPause() {
super.onPause();
myLocation.disableMyLocation();
}
//Back button press returns to first activity (selection screen)
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
//super.onBackPressed();
}
#Override
protected boolean isRouteDisplayed() {
return false;
}
//rest of functions for GPS alert
private void createGpsDisabledAlert(){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Your GPS is disabled! Would you like to enable it?")
.setCancelable(false)
.setPositiveButton("Enable GPS",
new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int id){
showGpsOptions();
}
});
builder.setNegativeButton("Do nothing",
new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int id){
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}
private void showGpsOptions(){
Intent gpsOptionsIntent = new Intent(
android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(gpsOptionsIntent);
}
//Testing - directions
public static ArrayList getDirections(double lat1, double lon1, double lat2, double lon2) {
String url = "http://maps.googleapis.com/maps/api/directions/xml?origin=" +lat1 + "," + lon1 + "&destination=" + lat2 + "," + lon2 + "&sensor=false&units=metric";
String tag[] = { "lat", "lng" };
ArrayList list_of_geopoints = new ArrayList();
HttpResponse response = null;
try {
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpPost httpPost = new HttpPost(url);
response = httpClient.execute(httpPost, localContext);
InputStream in = response.getEntity().getContent();
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = builder.parse(in);
if (doc != null) {
NodeList nl1, nl2;
nl1 = doc.getElementsByTagName(tag[0]);
nl2 = doc.getElementsByTagName(tag[1]);
if (nl1.getLength() > 0) {
list_of_geopoints = new ArrayList();
for (int i = 0; i < nl1.getLength(); i++) {
Node node1 = nl1.item(i);
Node node2 = nl2.item(i);
double lat = Double.parseDouble(node1.getTextContent());
double lng = Double.parseDouble(node2.getTextContent());
list_of_geopoints.add(new GeoPoint((int) (lat * 1E6), (int) (lng * 1E6)));
}
} else {
// No points found
}
}
} catch (Exception e) {
e.printStackTrace();
}
return list_of_geopoints;
}}
EDIT 10.07.2012: I start to wonder if is a stupid question, no one knows the answer or no one wants to answer.
I have tried to save into local variables and use them in get Directions() function but for some reason is crashing my app. Or better, I am invited to fix the error before compiling.
I'm passing data to a ListView to display some restaurant names. Now when clicking on an item I'd like to start another activity to display more restaurant data. I'm not sure about how to do it. Shall I pass all the restaurant data in a bundle through the intent object? Or shall I just pass the restaurant id and get the data in the other activity? In that case, how can I access my restaurantList from the other activity? In any case, how can I get data from the restaurant I clicked on (the view only contains the name)?
Any help, pointers welcome!
ListView lv= (ListView)findViewById(R.id.listview);
lv.setAdapter( new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,restaurantList.getRestaurantNames()));
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent i = new Intent(Atable.this, RestaurantEdit.class);
Bundle b = new Bundle();
//b.putInt("id", ? );
startActivityForResult(i, ACTIVITY_EDIT);
}
});
RestaurantList.java
package org.digitalfarm.atable;
import java.util.ArrayList;
import java.util.List;
public class RestaurantList {
private List<Restaurant> restaurants = new ArrayList<Restaurant>();
public List<Restaurant> getRestaurants() {
return this.restaurants;
}
public void setRestaurants(List<Restaurant> restaurants) {
this.restaurants = restaurants;
}
public List<String> getRestaurantNames() {
List<String> restaurantNames = new ArrayList<String>();
for (int i=0; i<this.restaurants.size(); i++) {
restaurantNames.add(this.restaurants.get(i).getName());
}
return restaurantNames;
}
}
Restaurant.java
package org.digitalfarm.atable;
public class Restaurant {
private int id;
private String name;
private float latitude;
private float longitude;
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public float getLatitude() {
return this.latitude;
}
public void setLatitude(float latitude) {
this.latitude = latitude;
}
public float getLongitude() {
return this.longitude;
}
public void setLongitude(float longitude) {
this.longitude = longitude;
}
}
You can not access data from other activities. If you need data in the activity that is started through clicking on the item in the list pass it to the new activity through the message bundle.
If you pass only the id to the next activity you could reload the restaurant from a database or from the internet but you can not retrieve it from the list used in the first activity.
If the restaurants are heavy to create objects you could implement you own application subclass and attach the restaurant list to this application subclass. Now you can access the list like this:
shopList = (YourSubclass)getApplication().getRestaurantList()
This would result in your shoplist being in the memory the wohl runtime of you application even if the app is in the background and all activities are paused.