[JAVA] Programming from 51 years old Make FusedLocationProviderClient resident in Foreground Service

Make FusedLocationProviderClient resident in Foreground Serivice

I refer to androidDeveloper and googleApi. I also refer to nyan </ font>'s site. Thank you very much.
The sample code below shows that the build version of android is api26 or higher.

Confirmation of Manifest gradle

Manifest


    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

builed.gradle


dependencies {
    ...
    implementation 'com.google.android.gms:play-services-location:17.0.0'

** After this, be sure to synchronize gradle! ** </ font>

Crash Code without Notification

Notification makes the code longer, so first of all, it is a code to check the operation simply. When it starts, it starts to acquire location information, and the service and location information acquisition are discarded by pressing a button. Crash after 5 seconds

MainActivity


public class MainActivity extends AppCompatActivity {

    static MainActivity activity;
    static TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        activity = MainActivity.this;
        textView = findViewById(R.id.textView);
        Button button = findViewById(R.id.button);

        final Intent intent = new Intent(this,MyService.class);
        startForegroundService(intent);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopService(intent);
            }
        });
    }
}

MyService


public class MyService extends Service {

    MainActivity activity;
    TextView textView;
    FusedLocationProviderClient fusedLocationClient;
    LocationCallback myCallback;

    @Override
    public void onCreate() {
        super.onCreate();
        activity = MainActivity.activity;
        textView = MainActivity.textView;
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(activity);
    }

    @Override
    public int onStartCommand(Intent intent,int flags,int startId){
        //If true, set Notification here and startForeground
        //But it's hard to see, so I'll omit it this time.
        myCallback = new myCallback(); // LocationCallback()instance
        myCheckPermission();           // ActivityCompat.checkSelfPermission()
        myGetLocation();               // FusedLocationProviderClient.requestLocationUpdates(); 
        return START_STICKY;
    }

    //Permisson ACCESS set in Manifest_FINE_LOCATION
    //Since it is a user dangerous, permission for permission is required!
    public void myCheckPermission(){
        if(ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},100);
            // requestPermissions()The contents confirmed in
            //If true, onRequestPermissionsResult()It is processed by, but it is omitted
        }else{
            return;
        }
    }

    public void myGetLocation(){
        //Set the behavior of fusedLocationProviderClient
        LocationRequest locationRequest = LocationRequest.create();
            locationRequest.setInterval(1000*3);
            locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        //Then! Get location information! The acquired information is Callback()Handle with a function!
        fusedLocationClient.requestLocationUpdates(locationRequest,myCallback,null);
    }

    //In MainActivity, if you press the stop button, Service will be destroyed.
    //At that time, onDestroy is called
    // onDestroy()I will destroy the usedLocationProviderClient!
    @Override
    public void onDestroy() {
        super.onDestroy();
        fusedLocationClient.removeLocationUpdates(myCallback);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    // LocationCallback()is.
    //It is this class that handles the acquired location information!
    class myCallback extends LocationCallback{
          @Override
          public void onLocationResult(LocationResult locationResult){
              super.onLocationResult(locationResult);
              //There is location information in locationResult, so let's use it!
              double latitude = locationResult.getLastLocation().getLatitude();
              String strLatitude = String.valueOf(latitude);
              textView.setText(strLatitude);
        }
    }
}

Code to make it resident and get latitude / longitude altitude

Click the Start button to make location information acquisition and display resident. Use the Stop button to cancel the service and location information acquisition. Let's go!

MainActivity


public class MainActivity extends AppCompatActivity {

    //Make UI parts referenced from Service static
    static MainActivity activity;
    static TextView textAlutitude;
    static TextView textLatitude;
    static TextView textLongitude;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Get the object!
        activity = MainActivity.this;
        textAlutitude = findViewById(R.id.textAltitude);
        textLatitude = findViewById(R.id.textLatitude);
        textLongitude = findViewById(R.id.textLongitude);
        Button btnStart= findViewById(R.id.btnStart);
        Button btnStop = findViewById(R.id.btnStop);


        //Start Foraground Service with Start button
        //Stop Foreground Service with Stop button
        //Foreground Service Stop My Service.onDestroy()Also destroys FusedLocationProviderClient
        final Intent intent = new Intent(activity,MyService.class);
        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startForegroundService(intent);
            }
        });

        btnStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopService(intent);
            }
        });

    }
}

MyService


public class MyService extends Service {

    //Make objects global
    MainActivity activity;
    TextView textAltitude;
    TextView textLatitude;
    TextView textLongitude;
    FusedLocationProviderClient fusedLocationClient;
    LocationRequest locationRequest;
    LocationCallback locationCallback;

    @Override
    public void onCreate() {
        super.onCreate();

        //Get the object!
        activity = MainActivity.activity;
        textAltitude = MainActivity.textAlutitude;
        textLatitude = MainActivity.textLatitude;
        textLongitude = MainActivity.textLongitude;
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

        //When setting the location request
        //Set to get detailed location information every 5 seconds
        locationRequest = LocationRequest.create();
            locationRequest.setInterval(1000*5);
            locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }

    public int onStartCommand(Intent intent, int flags, int startId){
        //I want to make it resident, so I will notify you

        //Set notification content, importance, and channel
        Notification notification;
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this,"id");
        Intent pIntent = new Intent(this,MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,0,pIntent,0);
        notification = builder.setSmallIcon(R.drawable.notification_icon)
                              .setContentTitle("NotificationTitle")
                              .setContentText("NotificationText")
                              .setContentIntent(pendingIntent)
                              .build();
        int importance = NotificationManager.IMPORTANCE_LOW;
        NotificationChannel channel = new NotificationChannel("id","name",importance);
        NotificationManager manager = getSystemService(NotificationManager.class);
        manager.createNotificationChannel(channel);

        //StartForeground within 5 seconds!!hurry up!
        startForeground(1,notification);


        // LocationCallback()Is requestLocation,Update,Since it is used in remove, create it here
        locationCallback = new LocationCallback(){
            @Override
            public void onLocationResult(LocationResult locationResult){
                super.onLocationResult(locationResult);
                String alti = String.valueOf(locationResult.getLastLocation().getAltitude());
                String lati = String.valueOf(locationResult.getLastLocation().getLatitude());
                String longi = String.valueOf(locationResult.getLastLocation().getLongitude());
                textAltitude.setText(alti);
                textLatitude.setText(lati);
                textLongitude.setText(longi);
            }
        };

        checkLocationPermission();
        return START_STICKY;
    }

    //Get location information
    private void locationUpdate(){
        fusedLocationClient.requestLocationUpdates(locationRequest,locationCallback,null);
    }

    // permission ACCESS_FINE_LOCATION is a user-dangerous setting, so check your permissions
    public void checkLocationPermission(){
        if(ActivityCompat.checkSelfPermission(activity,Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
            // ACCESS_FINE_Confirm with user in dialog without LOCATION permission
            ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},100);
        }else{
            locationUpdate();
        }
    }

    // checkLocationPermission()Process the content confirmed to the user with requestPermissions of
    public void onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults){
        if(requestCode == 100){
            if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
                //If you get permission
                locationUpdate();
            }else{
                //If you don't get permission
                textAltitude.setText("No permission");
            }
        }
    }

    //FusedLocationProviderClient is also destroyed when the Service is destroyed
    @Override
    public void onDestroy() {
        super.onDestroy();
        fusedLocationClient.removeLocationUpdates(locationCallback);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

This time too, I spent a lot of time. Obtaining location information residently was too high a hurdle for me. It takes about 2 weeks to make this code. It was finally possible after repeating back and forth.

This time is also the turtle's walk.

I felt that I could move forward if I kept struggling with the turtle's walk and without giving up. Even if you think it's impossible, you can move forward. I'm still lacking in ability, but it's interesting. very fun!

Recommended Posts