I am new to android development but am taking a shot at making myself a golf rangefinder.. I have this activity -
public class hole_1 extends Activity implements View.OnClickListener {
Button nextBtn;
GPSTracker gps;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hole_1);
gps = new GPSTracker(hole_1.this);
// Get Variable From Home Activity
Bundle extras = getIntent().getExtras();
String course = null;
if (extras != null) {
course = extras.getString("Course");
}
//Set Next Hole Button
nextBtn = (Button) findViewById(R.id.nextButton);
nextBtn.setOnClickListener(this);
gps = new GPSTracker(hole_1.this);
if (gps.canGetLocation()) {
double latitude = gps.getLatitude();
double longitude = gps.getLongitude();
double lat2 = 39.765718;
double lon2 = -121.860080;
Location loc1 = new Location("");
loc1.setLatitude(latitude);
loc1.setLongitude(longitude);
Location loc2 = new Location("");
loc2.setLatitude(lat2);
loc2.setLongitude(lon2);
float distanceInMeters = loc1.distanceTo(loc2);
int myDist = (int) (distanceInMeters * 1.0936);
TextView latView = (TextView) findViewById(R.id.yardage);
latView.setText(String.valueOf(myDist));
}else{
gps.showSettingsAlert();
}
}
#Override
public void onClick(View v) {
Intent myIntent = new Intent(this, end.class);
myIntent.putExtra("Hole",1);
startActivity(myIntent);
}
}
What I would like to do is update the myDist variable which is the distance between my current coordinates and the fixed coordinates (lat2, lon2). I have done some research and found asyncTask, threading and setting a timer but cannot figure out the best method for this application.. The app works great as is but I have to refresh the page to get updated distances and would like it to just update itself every few seconds.. What should I do?
Thanks!
1)You can't update every couple of seconds. GPS only updates every 30s to a minute.
2)You wouldn't use an async task here or any oter form of threading, GPS works on a callback system. You request updates and it will call you back whenever an update is available.
3)DO NOT USE the GpsTracker LIBRARY EVER. It's broken. Badly. See the full writeup I have on why its broken at http://gabesechansoftware.com/location-tracking/
Related
Assumption and what I want to achieve
I'm working on an application that receives current location information from an external RTK-GPS via serial communication, and draws dots or lines on an osmdroid map.
I have already realized receiving the location information and converting the received data to a type that can be displayed on TextView.
For serial communication, I am using FTDI's "usb-serial-for-android" library, and for map functions, I am using "osmdroid".
Currently
Receive location data from RTK-GPS via serial communication.
Get the latitude and longitude in double type from the received data (String type).
Create a GeoPoint from the acquired latitude and longitude, set it to a marker, and draw it on the map. At this time, the GeoPoint is also stored in the GeoPoint list.
The following procedure is used to display the marker of the current location on the map. Currently, the received latitude and longitude are set to the marker and all the markers are drawn.
Eventually, I'd like to draw the trajectory of movement as a line while updating the current location marker.
Problems and error messages
The problem we are experiencing is that when we start drawing, the application immediately becomes sluggish and freezes.
Since 10 data are sent from GPS per second, if we try to draw all the received data on the map, the number of markers will be huge and the app will freeze.
Therefore, we tried to draw markers in 10 marker skips, but even so, the application became sluggish and froze as soon as it started drawing.
Next, when the number of data exceeded 100, I deleted the oldest data first, and the application did not freeze after starting drawing. However, I don't think it is possible to draw all the loci with this method. If possible, I would like to draw all the loci that have been moved.
My questions are as follows.
Is it possible to draw the movement locus using the above method and policy?
Is it impossible to draw such a moving locus in Android?
Does OSMDROID have a function to draw the movement locus?
Are there any similar questions?
Please let me know.
Here is my code.
public class MapGeneratorMainActivity extends Activity {
private static final double MAP_ZOOM = 15.0;
private static final double MAP_ZOOM2 = 17.0;
static MapView mapGeneratorMainMap = null;
public static List<Marker> currentMarkers = new ArrayList<>();
ArrayList<GeoPoint> currentPoints = new ArrayList<>();
ArrayList<GeoPoint> currentPoints2hz = new ArrayList<>();
ArrayList<Polyline> currentTrajectory = new ArrayList<>();
public static int receiveCount = 0;
public static GeoPoint currentP2hz;
public MapGeneratorMainActivity() {
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
org.osmdroid.config.Configuration.getInstance().load(getApplicationContext(),
PreferenceManager.getDefaultSharedPreferences(getApplicationContext()));
setContentView(R.layout.map_generator_main_activity);
MapView mapGeneratorMainMap = findViewById(R.id.MapGaneratorMainMap);
mapGeneratorMainMap.setMultiTouchControls(true);
IMapController mapController = mapGeneratorMainMap.getController();
mapController.setZoom(MAP_ZOOM);
GeoPoint centerPoint = new GeoPoint(aveLat, aveLon);
mapController.setCenter(centerPoint);
mapGeneratorMainMap.setTilesScaledToDpi(true);
final MapTileProviderBasic tileProvider = new MapTileProviderBasic(getApplicationContext());
ITileSource tileSource = new XYTileSource("GSI", 14, 24, 256, ".jpg", new String[]{TILE_SEVER});
tileProvider.setTileSource(tileSource);
final TilesOverlay tilesOverlay = new TilesOverlay(tileProvider, this.getApplicationContext());
tilesOverlay.setLoadingBackgroundColor(Color.TRANSPARENT);
mapGeneratorMainMap.getOverlays().add(tilesOverlay);
mapGeneratorMainMap.invalidate();
FloatingActionButton myLocationButton = findViewById(R.id.myLocationButton);
myLocationButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intentService = new Intent(getApplication(), gpsService.class); //位置情報受信サービス
intentService.putExtra("REQUEST_CODE", 1);
startForegroundService(intentService);
}
});
//Receiver
UpdateReceiver receiver = new UpdateReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("DO_ACTION");
registerReceiver(receiver, filter);
}
protected class UpdateReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
String currentLat = null;
String currentLon = null;
MapView mapGeneratorMainMap = findViewById(R.id.MapGaneratorMainMap);
mapGeneratorMainMap.setMultiTouchControls(true);
IMapController mapController = mapGeneratorMainMap.getController();
mapController.setZoom(MAP_ZOOM2);
Bundle extras = intent.getExtras();
String msg = extras.getString("message"); //String型の位置情報
TextView currentLocatonTextView = findViewById(R.id.CurrentLocation);
currentLocatonTextView.setText(msg);
String[] currentLocaton = msg.split(",", -1);
currentLat = currentLocaton[0];
currentLon = currentLocaton[1];
double Lat = Double.parseDouble(currentLat);
double Lon = Double.parseDouble(currentLon);
GeoPoint currentP = new GeoPoint(Lat, Lon);
if(receiveCount == 0){
currentP2hz = new GeoPoint(Lat, Lon);
currentPoints.add(currentP);
currentPoints2hz.add(currentP2hz);
currentPtMarker = new Marker(mapGeneratorMainMap);
Drawable currentMarkerIcon = ResourcesCompat.getDrawable(getResources(), R.drawable.current_point_marker, null);
currentPtMarker.setIcon(currentMarkerIcon);
currentPtMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER);
currentPtMarker.setPosition(currentP);
currentMarkers.add(currentPtMarker);
mapGeneratorMainMap.getOverlayManager().add(currentPtMarker);
mapGeneratorMainMap.invalidate();
}
else if(receiveCount == 100) {
currentPoints.add(currentP);
currentP2hz = new GeoPoint(Lat, Lon);
currentPoints2hz.add(currentP2hz);
receiveCount = 0;
currentPtMarker = new Marker(mapGeneratorMainMap);
Drawable currentMarkerIcon = ResourcesCompat.getDrawable(getResources(), R.drawable.current_point_marker, null);
currentPtMarker.setIcon(currentMarkerIcon);
currentPtMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER);
currentPtMarker.setPosition(currentP);
currentMarkers.add(currentPtMarker);
mapGeneratorMainMap.getOverlayManager().add(currentPtMarker);
mapGeneratorMainMap.invalidate();
}
if(currentMarkers.size() >= 100){
currentMarkers.get(0).remove(mapGeneratorMainMap);
currentMarkers.remove(0);
}
receiveCount += 1;
}
}
Good morning everyone.
I was able to solve this problem.
The reason why it didn't work was that some of the data received by serial communication was not good.
After eliminating this bad data and receiving only the good data, I was able to do what I wanted.
thanks so much.
I am a new android programmer.
I have 4 activities: A B C D.
The order is A -> B -> C -> D -> A and A -> D using buttons.
I want to save data in ArrayList that is in activity D.
The problem is that when I move from D to A and come back to D, the data in the ArrayList didn't save.
Code for D activity here:
public class SchedulerActivity extends AppCompatActivity {
public String name = "";
public String number = "";
public String date = "";
public String hour = "";
public ArrayList<EventClass> scheduler = new ArrayList<>();
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scheduler);
Bundle extras = getIntent().getExtras();
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(SchedulerActivity.this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
finish();
}
});
if (extras != null) {
String sender = extras.getString("sender");
if(sender.compareTo("Hours") == 0) {
name = extras.getString("name");
number = extras.getString("number");
date = extras.getString("date");
hour = extras.getString("hour");
Date real_date = new Date();
SimpleDateFormat formatter1=new SimpleDateFormat("dd/MM/yyyy");
try {
real_date = formatter1.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
scheduler.add(new EventClass(real_date, name, number, "", hour));
for (EventClass event : scheduler){
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
final TextView t = new TextView(this);
t.setText(event.toString());
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.linearLayout);
linearLayout.addView(t, params);
}
}
else{
for (EventClass event : scheduler){
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
final Button btn = new Button(this);
final TextView t = new TextView(this);
t.setText(event.toString());
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.linearLayout);
linearLayout.addView(btn, params);
}
}
}
}
I want to change my ArrayList when C->D occurs and print it and when D->A occurs I just want to print it. I know that I can with SharedPreferences but for the first step, I want to do this with ArrayList.
What's the best way to do this?
Creating static objects is not a good approach. So you can use android activity stack in-place of using static Arraylist. Android activities are stored in the activity stack. Going back to a previous activity could mean two things.
You opened the new activity from another activity with startActivityForResult. In that case you can just call the finishActivity() function from your code and it'll take you back to the previous activity.
Keep track of the activity stack. Whenever you start a new activity with an intent you can specify an intent flag like FLAG_ACTIVITY_REORDER_TO_FRONT or FLAG_ACTIVITY_PREVIOUS_IS_TOP. You can use this to shuffle between the activities in your application.
The scheduler is a non-static field in the SchedulerActivity which means that its existance is tied to the instance of the activity. When the activity instance is destroyed, and that might happen for example when the screen orientation is destroyed or you move to another activity, so are all its non-static fields. You can change that by adding a static keyword before your field:
public static ArrayList<EventClass> scheduler = new ArrayList<>();
Now, your field is tied to the class itself, not the instance, whitch means it wont be destroyed along with the instance. But it also means that it is shared between all instances and must be referenced with the class name outside of the class body:
EventClass event = SchedulerActivity.scheduler.get(0)
A good approach is saving your data in a local database, like Room. You need to save before go to new activity, and get it back on OnResume().
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I tried to show the polylines and it shows the correct line when I put it in onLocationResult.
However, I only want it to show polylines when the user clicks on the start button.
So I tried to put the code into onClickListener, the screen only displays the marker but not the lines.
Location mLastLocation;
LocationRequest mLocationRequest;
private SupportMapFragment mapFragment;
private FusedLocationProviderClient mFusedLocationClient;
private FirebaseAuth myAuth;
private FirebaseDatabase mDatabase;
private DatabaseReference myRef;
private Marker currentUserLocationMarker;
private ArrayList<LatLng> points; //added
Polyline line;
private Button btnStartRun;
LatLng latLng;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_googls_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);
points = new ArrayList<LatLng>();
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
btnStartRun=findViewById(R.id.btnStartRun);
btnStartRun.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
points.add(latLng);//add points to the array
redrawLine();
myAuth=FirebaseAuth.getInstance();
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference().child("OnlineUsers");//.child("OnlineUser");
DatabaseReference currentUserDB=mDatabase.child(myAuth.getCurrentUser().getUid());
currentUserDB.child("CurrentLatitude").setValue(mLastLocation.getLatitude());
currentUserDB.child("CurrentLongitude").setValue(mLastLocation.getLongitude());
}
});
}
Here is my onLocationResult
LocationCallback mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
for (Location location : locationResult.getLocations()) {
mLastLocation = location;
latLng = new LatLng(location.getLatitude(), location.getLongitude());
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(15));
}
}
};
Here is my redrawline()
private void redrawLine(){
mMap.clear(); //clears all Markers and Polylines
PolylineOptions options = new PolylineOptions().width(5).color(Color.BLUE).geodesic(true);//set the colour and width of the polyline
for (int i = 0; i < points.size(); i++) {
LatLng point = points.get(i);
options.add(point);
}
addMarker(); //add Marker in current position
line = mMap.addPolyline(options); //add Polyline
}
Thank you.
You are only adding to points on the button click, but that is incorrect. You should be adding to points every time you get an onLocationChanged (or perhaps your location callback), otherwise, you don't have any line to draw.
Your onLocationChanged (or callback) should call the redrawLine method every time.
Your redrawLine method should have a flag, such as hasStarted. If hasStarted = false, then clear the map, but don't draw the line. If hasStarted = true, then clear the map and DO draw the line.
In the onClick listener, simply set hasStarted = true (or, if you want it to be a toggle, say hasStarted = !hasStarted).
As soon as the setOnClickListener executes I want to start another activity and transmit the variable cn.getID() to it. When inside the other activity I want to immidietaly start the method findlocation and give cn.getID() to it.
The method findLocation is not finished yet. The idea is, once it gets the ID of the other activities button, i can search with sqllite in my database for the place it belongs to, get longitude and latitude and tell mapcontroller focus the world map on this point.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.verladestellen);
final DB_Verladestellen db = new DB_Verladestellen(this);
List<DB_Place> placeList = db.getAllDBPlaces();
final LinearLayout layout = (LinearLayout) findViewById(R.id.verladestellen_liste);
for (final DB_Place cn : placeList) {
final LinearLayout row = new LinearLayout(this);
row.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
Button place = new Button(this);
place.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
place.setText(cn.getName());
place.setId(cn.getID());
row.addView(place);
row.setId(cn.getID());
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) place.getLayoutParams();
params.weight = 1.0f;
place.setLayoutParams(params);
place.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Here I want to call the method to start the other activity
//and transmit cn.getID().
openMap(null);
}
});
layout.addView(row);
}
}
//The method to start the other activity
public void openMap(View view) {
Intent intent = new Intent(this, UI_MainActivity.class);
startActivity(intent);
}
This is the method from inside the new activity I want to execute immidietaly after it has started:
public void findLocation(View view){
MapView map = (MapView) findViewById(R.id.map);
IMapController mapController = map.getController();
mapController.setZoom(17);
GeoPoint myLocation = new GeoPoint(PLACEHOLDER X , PLACEHOLDER Y);
mapController.animateTo(myLocation);
}
EDIT:
#Murat K. After some edits this is my whole class now:
public class UI_Verladestellen extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.verladestellen);
final DB_Verladestellen db = new DB_Verladestellen(this);
List<DB_Place> placeList = db.getAllDBPlaces();
final LinearLayout layout = (LinearLayout) findViewById(R.id.verladestellen_liste);
for (final DB_Place cn : placeList) {
final LinearLayout row = new LinearLayout(this);
row.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
Button place = new Button(this);
place.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
place.setText(cn.getName());
place.setId(cn.getID());
row.addView(place);
row.setId(cn.getID());
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) place.getLayoutParams();
params.weight = 1.0f;
place.setLayoutParams(params);
place.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
openMap(cn.getID());
}
});
layout.addView(row);
}
}
public void openMap(int view) {
Intent intent = new Intent(UI_Verladestellen.this, UI_MainActivity.class);
intent.putExtra("findLocation", 1);
startActivity(intent);
}
}
And this is the getIntent of my onCreate method in UI_MainActivity:
int i = getIntent().getIntExtra("findlocation", 999);
if(i == 1){
findLocation(i);
}
As I edited into my earlier comment, i cant see where my Button-ID is recieved. At first i thought i would be my ID, but that wouldnt work, since The Button ID can be every number from 1 to n.
You can achieve this with an Intent e.g.
Intent i = new Intent(BaseActivity.this, YourSecondActivity.class);
intent.putExtra("METHOD_TO_CALL", 1);
startActivity(i);
and in your onCreate() method of the starting Activity you check for it.
#Override
public void onCreate(Bundle savedInstanceState) {
int i = getIntent().getIntExtra("METHOD_TO_CALL", 999);
if(i == 1){
callMethod(i);
}
EDIT:
//The method to start the other activity
public void openMap(View view) {
Intent intent = new Intent(this, UI_MainActivity.class);
intent.putExtra("METHOD_TO_CALL", 1); // the 1 is a example, put your ID here
startActivity(intent);
}
Step #1: Use putExtra() to add your ID value to the Intent that you use with startActivity()
Step #2: In the other activity, call getIntent() in onCreate() to retrieve the Intent used to create the activity instance. Call get...Extra() (where ... depends on the data type) to retrieve your ID value. If the ID value exists, call your findLocation() method.
It depends on how you want it to work. If you only want it to execute when the activity is created (when it starts or screen rotates) then call the method within the activities onCreate method. If you want it called whenever the user returns to that activity which can include them leaving the app and coming back to it sometime later then onResume would be a better spot for it. Calling the method from either should work as you hope though.
I also recommend looking over the Activity lifecycle as that will help you a lot in the future.
I have made an Android app that gets location by longitude and latitude on a button click.
At first I get the last known location reading, which is, for argument sake, inaccurate when I first load up the app/turn on gps.
What I would like to know is how to wait for it to be accurate, like in Google maps when you get the toast message 'waiting for location'.
If you see any way the code can be improved it would also be helpful.
Code for reference:
public class Clue extends Activity {
public static double latitude;
public static double longitude;
Criteria criteria;
LocationManager lm;
LocationListener ll;
Location location;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.questions);
criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
ll = new MyLocationListener();
lm.requestLocationUpdates(lm.getBestProvider(criteria, true), 0, 0, ll);
}
private boolean weAreThere() {
location = getLocation();
longitude = location.getLongitude();
latitude = location.getLatitude();
return inCorrectPlace(param);
}
private Location getLocation() {
lm.requestLocationUpdates(lm.getBestProvider(criteria, true), 0, 0, ll);
return lm.getLastKnownLocation(lm.getBestProvider(criteria, true));
}
}
public class MyLocationListener implements LocationListener
{
public void onLocationChanged(Location loc)
{
Clue.longitude = loc.getLongitude();
Clue.latitude = loc.getLatitude();
}
}
Thanks for reading, all replies will be appreciated.
Ben
If Location.hasAccuracy() returns true, you could call Location.getAccuracy() to retrieve the accuracy in meters, then filter the ones you don't consider enough accurate.
Notice you are not using LocationManager.GPS_PROVIDER so your fixes could also be obtained by other means (like WiFi).
Usually expect about a minute for the GPS chip to get "hot"* before getting GPS fixes (outdoors).
*By hot I mean having satellites coverage. Some chipsets get disconnected ("cold") after some time to preserve battery. The Time To First Fix (TTFF) is greater when the chip is cold.
Here is an excellent explanation,
http://android-developers.blogspot.com/2011/06/deep-dive-into-location.html
helps you understand exactly how to implement it.
Initially , u should get fix using getlastknownLocation ()
In addition, U can use a background service that updates location using NETWORK.PROVIDER... which shall not drain ur battery if used judiciously...and also works if GPS is turned off
If there is no network provider, then u should try and ask user to turn on GPS.
If u r using 2.2 try PASSIVE PROVIDER