-1

I am trying to get markers placed on the map and fly to their destination. within a forloop i have an if statement, i wish it to do this:

for(i loop){
If (array(i) == null{ spawn plane code}
else {move plane code}

here is the code:

 package com.fly.plane;

import java.sql.Time;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.fly.plane.R;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.Projection;
import com.google.android.gms.maps.SupportMapFragment;

import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;


import android.R.array;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.graphics.Point;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.support.v4.app.FragmentActivity;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.View;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.widget.TextView;

public class MyMapActivity extends ListActivity {

    private ProgressDialog pDialog;

    // URL to get data JSON
    private static String url = "http://edmundgentle.com/snippets/flights/api.php";

    // JSON Node speeds
    private static final String TAG_data = "data";
    private static final String TAG_BEARING = "bearing";
    private static final String TAG_SPEED = "speed";
    private static final String TAG_ARR = "arr";
    private static final String TAG_ARR_TIME = "time";
    private static final String TAG_ARR_LAT = "lat";
    private static final String TAG_ARR_LON = "lon";
    private static final String TAG_DEP = "dep";
    private static final String TAG_DEP_TIME = "time";
    private static final String TAG_DEP_LAT = "lat";
    private static final String TAG_DEP_LON = "lon";

    // data JSONArray
    JSONArray data = null;

    // Hashmap for ListView
    ArrayList<HashMap<String, Double>> contactList;

    // Hashmap for ListView
    ArrayList<Double> ct;

    List<Marker> markers = new ArrayList<Marker>();

    //final Handler handler;
    private GoogleMap mMap; 
    public static final LatLng dest(Double alt,Double aln, int i){
        //final double latitude = Double.parseDouble(alt);
        //final double longitude = Double.parseDouble(aln);
        return new LatLng(alt, aln);
    }
    public double latt = -15.48169437461;
    public double lng = -15.48169437461;
    public ArrayList<Integer> dLat;

    public String[] markerList;

    public String dlat;
    public String dlon;
    public String alat;
    public String alon;

    private int count;

    public boolean wait = true;

    //private Button startB;
    public TextView text;

    Timer timing;
    double time = 600;
    double timm = 1;

    long timer = 18000000;
    long newTime;
    TextView tv, test;
    Thread t;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my_map);

        contactList = new ArrayList<HashMap<String, Double>>();

        ct = new ArrayList<Double>();

        //ListView lv = getListView();

      //create markers  
        new Getdata().execute();
        // timer showing time of day in fast time
        t = new Thread() {

              @Override
              public void run() {
                try {
                  while (!isInterrupted()) {
                    Thread.sleep(600);
                    runOnUiThread(new Runnable() {
                      @Override
                      public void run() {
                          timer = timer +60000;
                          if (timer >= 64000000) timer = 18000000;
                          newTime = timer;
                        // update TextView here!
                         //String time = "HH:mm:ss";
                         //tv.setText(DateFormat.format(time , timer));
                         tv.setText(Double.toString(time));
                         test.setText(Double.toString(timm));
                         //tv.setText(Double.toString(contactList.get(20).get("time")));
                         //Timer();
                      }
                    });
                  }
                } catch (InterruptedException e) {
                }
              }
            };

            tv = new TextView(this); 
            test = new TextView(this); 
            tv=(TextView)findViewById(R.id.timer); 
            test=(TextView)findViewById(R.id.test); 
         // run the mUpdateUITimerTask's run() method in 10 seconds from now
    }    


    // animate each plane
    public void animateMarker(final Marker marker , final LatLng toPosition,
            final boolean hideMarker, final double spd) {

        float speed = (float) spd;// Float.parseFloat(spd);
        final Handler handler = new Handler();
        final long start = SystemClock.uptimeMillis();
        Projection proj = mMap.getProjection();
        Point startPoint = proj.toScreenLocation(marker.getPosition());
        final LatLng startLatLng = proj.fromScreenLocation(startPoint);
        final float duration = 10 * speed;
        final Interpolator interpolator = new LinearInterpolator();
        handler.post(new Runnable() {
            @Override
            public void run() {
                long elapsed = SystemClock.uptimeMillis() - start;
                float t = interpolator.getInterpolation((float) ((float) elapsed
                        / duration));
                double lng = t * toPosition.longitude + (1 - t)
                        * startLatLng.longitude;
                double lat = t * toPosition.latitude + (1 - t)
                        * startLatLng.latitude;
                marker.setPosition(new LatLng(lat, lng));
                if (t < 1.0) {
                    // Post again 16ms later.
                    handler.postDelayed(this, 16);
                } else {
                    handler.postDelayed(this, 16);
                    if (hideMarker) {
                        marker.setVisible(false);
                    } else {
                        marker.setVisible(true);
                    }
                }
            }
        });
    }

    public void Timer(){
        //TimerTask tasknew = new TimerTask();
        timing = new Timer();
        timing.schedule(new CreateMarker(), 1000, 1000);
    }


    public String calcCurPos(double curlat, double curlon, double deslat, double deslon, double avgSpd, double bearing){

        double distance = avgSpd * 0.0167;

        // check if degrees or radians
        //deslat = distance * Math.cosh(bearing);

        //double retLat = curlat + deslat;
        //double dPhi = Math.log(Math.tan(retLat/2+Math.PI/4)/Math.tan(curlat/2+Math.PI/4));
        //double q = deslat/dPhi  deslat/dPhi : Math.cos(curlat);
        bearing = bearing * Math.PI / 180;

        int radius = 6371;

        double nextLat = Math.asin(Math.sin(curlat)* Math.cos(distance/radius)
                + Math.cos(curlat)*Math.sin(distance/radius)*Math.cos(bearing));

        double nextLon = curlon + Math.atan2(Math.sin(bearing)* Math.sin(distance/ radius)
                * Math.cos(curlat), Math.cos(distance/radius)-Math.sin(curlat) * Math.sin(nextLat));

        nextLat = (nextLat * 180) / Math.PI;
        nextLon = (nextLon * 180) / Math.PI;


        /**
         * Warning might want to convert them to string prior to return.
         */
        return nextLat + ";" + nextLon;
    }

public class CreateMarker extends TimerTask{

    @Override
    public void run() {
        // TODO Auto-generated method stub

        // print test
        //tv.setText(Double.toString(time));
        //tv.setText(Double.toString(time));
        if (time >= 2400){
            time=0;
        }

        time += 1;
        //mMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();

        for (int i =0; i < 100;i++){
            // get data from array list
            final double depLat = contactList.get(i).get("dlat");
            final double depLon =  contactList.get(i).get("dlon");
            final double arLat = contactList.get(i).get("alat");
            final double arLon =  contactList.get(i).get("alon");
            final double spd = contactList.get(i).get("speed");
            final double dTime = contactList.get(i).get("time");
            double curLat = contactList.get(i).get("clat");
            double curLon = contactList.get(i).get("clon");
            final double bearing = contactList.get(i).get("bearing");

            final int j = i;
            //int dTime = Integer.parseInt(dtime);

            double oldLat = curLat;

            if (time >= dTime)
            {
                if (curLat < arLat || curLat > 0){

                    String latlng = calcCurPos(curLat, curLon, arLat, arLon ,spd, bearing );

                    String[] values = latlng.split(";");

                    curLat = Double.parseDouble(values[0]);
                    curLon = Double.parseDouble(values[1]);
                    final double crLat = curLat;
                    final double crLon = curLon;

                    final LatLng position = new LatLng(crLat,crLon);


                    /*Marker mo =  mMap.addMarker(new MarkerOptions()
                    .position(new LatLng(depLat, depLon))
                    .icon(BitmapDescriptorFactory.fromResource(R.drawable.planemarker)));*/
                        //DrawMarker();

                    //animateMarker(markers.get(i), position , true, spd);
                    try{
                    if (markers.get(i) == null){
                        //timm += 1;
                        timm += 1;
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {

                        final Marker marker =  mMap.addMarker(new MarkerOptions()
                        .position(new LatLng(depLat, depLon))
                        .title("Hello world")
                        .icon(BitmapDescriptorFactory.fromResource(R.drawable.planemarker)));
                        markers.add(marker);
                        //marker.setVisible(false);
                        //animateMarker(markers.get(j), new LatLng(arLat,arLon) , true, spd);
                        //Marker marker = markers.get(i);

                        //marker.setPosition(position);
                          }
                        });

                    }
                    else //(markers.get(i) != null){
                    {
                        Marker marker = markers.get(i);
                        marker.setPosition(position);
                        marker.setVisible(false);
                        //animateMarker(markers.get(i), position , true, spd);
                    }
                    }
                    catch(NullPointerException npe)
                    {
                        //do something else
                    }

                }
            }
        }


        //return null;

    }
    }


    /**
     * Async task class to get json by making HTTP call
     * */
    private class Getdata extends AsyncTask<Void, Void, Void> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            // Showing progress dialog
            pDialog = new ProgressDialog(MyMapActivity.this);
            pDialog.setMessage("Please wait...");
            pDialog.setCancelable(false);
            pDialog.show();

        }

        @Override
        protected Void doInBackground(Void... arg0) {
            // Creating service handler class instance
            HTTPHandler sh = new HTTPHandler();

            // Making a request to url and getting response
            String jsonStr = sh.makeServiceCall(url, HTTPHandler.GET);

            Log.d("Response: ", "> " + jsonStr);
            boolean limit = false;
            if (jsonStr != null  ||  limit == false) {
                try {
                    JSONObject jsonObj = new JSONObject(jsonStr);

                    // Getting JSON Array node
                    data = jsonObj.getJSONArray(TAG_data);

                    // looping through All data
                    for (int i = 0; i < data.length(); i++) {
                        JSONObject c = data.getJSONObject(i);

                        String bearing = c.getString(TAG_BEARING);
                        String spd = c.getString(TAG_SPEED);
                        // departure node is JSON Object
                        JSONObject dep = c.getJSONObject(TAG_DEP);
                        String dtime = dep.getString(TAG_DEP_TIME);
                        //String dlat = dep.getString(TAG_DEP_LAT);
                        //String dlon = dep.getString(TAG_DEP_LON);
                        dlat = dep.getString(TAG_DEP_LAT);
                        dlon = dep.getString(TAG_DEP_LON);


                        // replace : and last 2 0's from departure time
                        dtime = dtime.replaceAll(":","");
                        //dtime.replaceAll(";","");
                        dtime = dtime.substring(0,dtime.length()-2);

                        // arrival node is JSON Object
                        JSONObject arr = c.getJSONObject(TAG_ARR);

                        String alt = arr.getString(TAG_ARR_LAT);
                        String aln = arr.getString(TAG_ARR_LON);


                        // convert data positions to doubles for Google Maps + stuff

                        double brng = Double.parseDouble(bearing);
                        brng = brng * Math.PI / 180;

                        double speed = Double.parseDouble(spd);
                        //double brng = Double.parseDouble(bearing);
                        double dLatitude = Double.parseDouble(dlat);
                        double dLongitude = Double.parseDouble(dlon);
                        double aLatitude = Double.parseDouble(alt);
                        double aLongitude = Double.parseDouble(aln);
                        double cLatitude = Double.parseDouble(dlat);
                        double cLongitude = Double.parseDouble(dlon);
                        double dtme = Double.parseDouble(dtime);

                        // tmp hashmap for single contact
                        HashMap<String, Double> contact = new HashMap<String, Double>();

                        contact.put("bearing", brng);
                        contact.put("speed", speed);
                        contact.put("time", dtme);
                        contact.put("alat", aLatitude);
                        contact.put("alon", aLongitude);
                        contact.put("dlat", dLatitude);
                        contact.put("dlon", dLongitude);    
                        contact.put("clat", cLatitude);
                        contact.put("clon", cLongitude);

                        // adding contact to contact list
                        contactList.add(contact);

                        if (i== data.length()){
                            wait = false;
                        }
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            } else {
                Log.e("ServiceHandler", "Couldn't get any data from the url");
            }

            return null;
        }
        // spawns planes when json loaded
        @Override
        protected void onPostExecute(Void result) {
            Timer();
            t.start();
            super.onPostExecute(result);
            // Dismiss the progress dialog
            if (pDialog.isShowing())
                pDialog.dismiss();            
            // use plane api for latlon
            mMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();

            //for (int i = 0; i < contactList.size() ; i++)
        }}


}

and here is the error message:

02-26 21:53:42.031: E/AndroidRuntime(14970): FATAL EXCEPTION: Timer-0
02-26 21:53:42.031: E/AndroidRuntime(14970): java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
02-26 21:53:42.031: E/AndroidRuntime(14970):    at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
02-26 21:53:42.031: E/AndroidRuntime(14970):    at java.util.ArrayList.get(ArrayList.java:308)
02-26 21:53:42.031: E/AndroidRuntime(14970):    at com.fly.plane.MyMapActivity$CreateMarker.run(MyMapActivity.java:395)
02-26 21:53:42.031: E/AndroidRuntime(14970):    at java.util.Timer$TimerImpl.run(Timer.java:284)

i understand that the markers.get(i) is causing the problem, but i dont know how to check if the markers array is null without it throwing this error.

Any help would be appreciated.

Phil
  • 83
  • 1
  • 2
  • 15
  • Am i correct, that by `markers.get(i) == null` you are intending to check - does marker with `(final LatLng position = new LatLng(crLat,crLon);)` position is in the `markers` list? – n1k1ch Feb 26 '14 at 22:08
  • It is meant to check if that plane exists so for i = 0 (markers[0] ==null) make new plane with depLat depLon) else { move markers[0].position(crLat,crLon)} – Phil Feb 26 '14 at 22:18
  • Plane (flight) could be unique identified by `"id": "6986",` (take it from JSON from [here](http://edmundgentle.com/snippets/flights/api.php)), correct? – n1k1ch Feb 26 '14 at 22:26
  • yes it can, ID wasn't included when i started this, he must have added it recently. – Phil Feb 26 '14 at 22:29
  • Why don't you want to create some class Flight with fields `bearing`, `speed`, `time`, `aLat`, `dLat`, ... to represent one entity from that JSON list? – n1k1ch Feb 26 '14 at 22:32
  • Then you can try to refactor with using `Set flights` instead of `ArrayList> contactList`. After this it will be easier to create/move markers for each `Flight` (note, that 'equals()' should be properly implemented in `Flight` to use it with `Set` – n1k1ch Feb 26 '14 at 22:34
  • Thanks for that, i haven't used Set before and am unsure if i want to try and refactor my code with that (due to time). the markers array should always contain the same flight once its filled so should do the job if i can get past this error. – Phil Feb 26 '14 at 22:50
  • Do you want to create/move markers at departure locations? – n1k1ch Feb 26 '14 at 23:08
  • They should be created at departure locations, and they should move towards the arrival locations – Phil Feb 26 '14 at 23:13
  • ...move, when current time becomes bigger than arrival time? – n1k1ch Feb 26 '14 at 23:15
  • oh right, i changed them over to test something, forgot to put them back! thanks for that! – Phil Feb 26 '14 at 23:22
  • The refactoring is really needed because of following reasons: 1) `markers` list could be lost between `onDestroy()-onCreate()` and you'll need to persist it (to database, for example) 2) If you want to support your code in future - it will be hard to remember what `ArrayList> contactList` means 3) To clarify create/move marker process. So, 1x time you spend now will save 10x to you in the future – n1k1ch Feb 26 '14 at 23:29
  • i understand that is best practice, but this is not going to be released, its just to showcase a distributed system, and wont be continued after next week. – Phil Feb 26 '14 at 23:38
  • What is the duration of a showcase? Single app launch? – n1k1ch Feb 26 '14 at 23:41
  • the showcase is a distributed system, its more about the server sided things, so the API that was created, the amount of data we got and the manipulation of the data, we have this phone app and also a windows desktop app, the showcase is only for a few mins to get assessed on how big the distibuted system is (its for University) – Phil Feb 26 '14 at 23:45
  • Ok, can `i` from `int i =0; i < 100;i++` be unique identifier of a flight? – n1k1ch Feb 26 '14 at 23:57
  • Yes, it will actually be int i = 0; i < contactList.size(); i++ but i have limited it to 100 at the moment until it is working. – Phil Feb 27 '14 at 10:12

2 Answers2

1

You wrote:

i understand that the markers.get(i) is causing the problem, but i dont know how to check if the markers array is null without it throwing this error.

==> you can check it this way:

if (markers != null && markers.size() > 0) {
      //there are actually markers. Calling markers.get(i) should work! 
      //...as long as i is smaller than markers.size()
} else {
      //sorry, no markers! Don't call markers.get(i) here...
}
donfuxx
  • 11,277
  • 6
  • 44
  • 76
  • Get the same error, also, the else is supposed to move the already existing plane, hence the markers.get(i) in the if statement (if that instance already exists then move it) i don't know how i would move the plane if i couldn't call it from the array in the else statement. – Phil Feb 26 '14 at 22:16
  • @Phil you are checking `if (markers != null && markers.size() > 0)` before using your markers list and your ArrayList throws and `IndexOutOfBoundsException`? Could you please add a breakpoint at the line where the error is thrown and confirm the value of markers? – donfuxx Feb 26 '14 at 22:21
  • I don't know how to use breakpoints, ive added one, but not sure how to check the value at the point. – Phil Feb 26 '14 at 22:34
  • Ok ok, then put `System.out.println("elements in markers arraylist: " + markers.size())` just before the line the error happens. Then search for this output in the logcat. – donfuxx Feb 26 '14 at 22:40
  • 02-26 22:45:09.863: I/System.out(20922): elements in markers arraylist: 0 in logcat – Phil Feb 26 '14 at 22:45
  • so did you put that if statement? `if (markers != null && markers.size() > 0)` ? where? – donfuxx Feb 26 '14 at 22:48
  • put the system out just before the if statement on line 397 and get the message 02-26 22:52:00.684: I/System.out(21903): elements in markers arraylist: 0 – Phil Feb 26 '14 at 22:53
  • You misunderstood: You should place the System.out.println before the line your error happens according the logcat output. – donfuxx Feb 26 '14 at 23:00
  • dont know if i understand, but i have done this: System.out.println("elements in markers arraylist: " + markers.size()); if (markers != null && markers.size() > 0){ System.out.println("elements in markers arraylist: " + markers.size()); and it only prints out the first one, so i assume that is before it breaks, and the second isnt executed as the error crashes it. – Phil Feb 26 '14 at 23:11
  • No, the second System.out is not printed because it is after the if-statement. it assures the following code is only executed if markers.size() > 0. and as you can see in the previous output `markers.size() == 0`. So why are you surprised? just do read my answer again and simply never call get(i) when markers.size() == 0 – donfuxx Feb 27 '14 at 07:08
  • Okay i understand! and your right, i took away the markers.get(i) in the else and the if statement doesnt crash, but the if statement is supposed to work by checking if markers[i] is null, make a new marker else if it exists, move that marker. – Phil Feb 27 '14 at 10:08
1

You can use Map<Integer, Marker> (Integer are keys and Marker are values). Then you can leverage Map.get() which don't throws Exception if key is Integer and not null (your i will not be null in your code).

Declare markers as Map:

Map<Integer, Marker> markers = new HashMap<Integer, Marker>();

Inside CreateMarker.run() after final LatLng position = new LatLng(crLat,crLon); change as follows:

//implicit boxing to use int in Map
Integer ii = Integer.valueOf(i);

//try to get marker by index from map (index is the key)
Marker markerByIndex = markers.get(ii);

//Map.get() returns null if object by specified key is not in map
if (markerByIndex == null){
    //marker doesn't exists - create it, add to Google Map and to Map by key
    timm += 1;
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            final Marker marker =  mMap.addMarker(new MarkerOptions()
                                   .position(new LatLng(depLat, depLon))
                                   .title("Hello world")
                                   .icon(BitmapDescriptorFactory.fromResource(R.drawable.planemarker)));

            //put marker to map using i as a key
            markers.put(ii, marker);
        }
    });
} else {
    //marker exists, mutate it
    markerByIndex.setPosition(position);
    markerByIndex.setVisible(false);

    //...replace the marker in map
    markers.put(ii, markerByIndex);

    //animate the marker
    animateMarker(markerByIndex, position , true, spd);
}
n1k1ch
  • 2,594
  • 3
  • 31
  • 35
  • Thanks for all the help, that solved the IndexOutOfBoundsException error! – Phil Feb 27 '14 at 10:45
  • You are welcome. But you should know that this (MyMapActivity) part of app is fragile and error prone in it's current state (but for fast demo i think it's enough) – n1k1ch Feb 27 '14 at 10:57