Search code examples
javaandroid-studiogoogle-mapswhile-loopwait

How to loop a function and wait a second between every loop in google maps project in android studio?


I want to create a program that mark a place on the google map and every second from when I push the "Start" button the marker would jump a km to a random direction until I push the "Stop" button.

I want the marker to jump, wait a second, jump, wait a second and so on... Until I push the "Stop" button.

When I am using the "while" loop the program stuck even before the showing of the "Stop" button. But if I don't use the loop it's working good. Can you help me please?

This is my code:

import androidx.annotation.DrawableRes;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity;

import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.view.View;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.widget.Button;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.Projection;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptor;
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 java.util.Random;

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {

    private GoogleMap mMap;
    private double currLat = 32.671677;
    private double currLng = 35.195678;
    private Marker _marker;
    private boolean _stopBWasNotPressed = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    // Setting the icon instead of the default marker.
    private BitmapDescriptor bitmapDescriptorFromVector(Context context, @DrawableRes int vectorDrawableResourceId) {
        Drawable background = ContextCompat.getDrawable(context, R.drawable.car_icon);
        background.setBounds(0, 0, background.getIntrinsicWidth(), background.getIntrinsicHeight());
        Drawable vectorDrawable = ContextCompat.getDrawable(context, vectorDrawableResourceId);
        vectorDrawable.setBounds(40, 20, vectorDrawable.getIntrinsicWidth() + 40, vectorDrawable.getIntrinsicHeight() + 20);
        Bitmap bitmap = Bitmap.createBitmap(background.getIntrinsicWidth(), background.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        background.draw(canvas);
        vectorDrawable.draw(canvas);
        return BitmapDescriptorFactory.fromBitmap(bitmap);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;

        // Hide the Stop button.
        Button stopB = (Button) findViewById(R.id.stopB);
        stopB.setVisibility(View.GONE);
        // Hide the Reset button.
        Button resetB = (Button) findViewById(R.id.resetB);
        resetB.setVisibility(View.GONE);
        // Add a marker in my home and move the camera.
        LatLng home = new LatLng(currLat, currLng);
        _marker = mMap.addMarker(new MarkerOptions().position(home).icon(bitmapDescriptorFromVector(this, R.drawable.car_icon)));
        mMap.moveCamera(CameraUpdateFactory.newLatLng(home));

        // Show the Start button.
        Button startB = (Button) findViewById(R.id.startB);
        startB.setVisibility(View.VISIBLE);
        startB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Hide the Start button.
                Button startB = (Button) findViewById(R.id.startB);
                startB.setVisibility(View.GONE);
                // Show the Stop button.
                final Button stopB = (Button) findViewById(R.id.stopB);
                stopB.setVisibility(View.VISIBLE);

                while (_stopBWasNotPressed) {
                    // Making the program wait a second until it moving the marker again.
                    new Handler().postDelayed(new Runnable() {
                        public void run() {
                            startMoving();
                        }
                    }, 1000);   // 1 second.
                }
            }
        });
    }

    // This func generates a random number to use as a direction.
    public int generateRandomDirection(){
        final int min = 1;
        final int max = 4;
        final int random = new Random().nextInt((max - min) + 1) + min;
        return random;
    }

    // This func makes the new location and sends it to the animateMarker func.
    public void startMoving(){
        int directionNumber = generateRandomDirection();
        final LatLng toPos;
        switch(directionNumber) {
            case 1:
                toPos = new LatLng((currLat + 0.01), currLng); // North.
                _marker.setPosition(toPos);
                break;
            case 2:
                toPos = new LatLng((currLat - 0.01), currLng); // South.
                _marker.setPosition(toPos);
                break;
            case 3:
                toPos = new LatLng(currLat, (currLng + 0.01)); // East.
                _marker.setPosition(toPos);
                break;
            default:
                toPos = new LatLng(currLat, (currLng - 0.01)); // West.
                _marker.setPosition(toPos);
                break;
        }
    }

    public void stopButtonClick(View view) {
        _stopBWasNotPressed = false; // Stops the while loop.
        // Hide the Stop button.
        Button stopB = (Button) findViewById(R.id.stopB);
        stopB.setVisibility(View.GONE);
        // Show the Reset button.
        final Button resetB = (Button) findViewById(R.id.resetB);
        resetB.setVisibility(View.VISIBLE);
        resetB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                _marker.setVisible(false);
                currLat = 32.671677;
                currLng = 35.195678;
                onMapReady(mMap);
            }
        });
    }
}

Solution

  • I searched a bit and I found that I can't use the while loop and the delay function together so I changed it to this:

    final Handler handler = new Handler();
                    Runnable runnable = new Runnable() {
                        @Override
                        public void run() {
                            while (_stopBWasNotPressed) {
                                try {
                                    Thread.sleep(1000); // Making the program wait a second until it continues.
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                                handler.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        startMoving();
                                    }
                                });
                            }
                        }
                    };
    
                    Thread myThread = new Thread(runnable); // Creating a thread for the marker movement.
                    myThread.start();