ฟังเหตุการณ์การนําทาง

แอปสามารถฟังเหตุการณ์ที่เกิดขึ้นขณะที่ผู้ใช้ไปยังจุดต่างๆ ตามเส้นทาง

ภาพรวม

ใช้อินเทอร์เฟซต่อไปนี้เพื่อรอเหตุการณ์การนําทาง

  • Navigator.ArrivalListener มี onArrival() การเรียกกลับ ซึ่งจะทริกเกอร์เมื่ออุปกรณ์มาถึงปลายทาง
  • RoadSnappedLocationProvider.LocationListener มี onLocationChanged() callback ซึ่งจะทริกเกอร์เมื่อตำแหน่งของอุปกรณ์เปลี่ยนแปลง
  • Navigator.RemainingTimeOrDistanceChangedListener ระบุการเรียกกลับ onRemainingTimeOrDistanceChanged() ซึ่งจะทริกเกอร์เมื่อเวลาหรือระยะทางไปยังปลายทางถัดไปเปลี่ยนแปลงมากกว่าค่าที่ระบุ
  • Navigator.RouteChangedListener มี Callback ของ onRouteChanged() ซึ่งจะทริกเกอร์เมื่อเส้นทางเปลี่ยนแปลง

ดูรหัส

package com.example.navsdkmultidestination;

import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.google.android.gms.maps.GoogleMap.CameraPerspective;
import com.google.android.libraries.navigation.ArrivalEvent;
import com.google.android.libraries.navigation.ListenableResultFuture;
import com.google.android.libraries.navigation.NavigationApi;
import com.google.android.libraries.navigation.Navigator;
import com.google.android.libraries.navigation.RoadSnappedLocationProvider;
import com.google.android.libraries.navigation.SimulationOptions;
import com.google.android.libraries.navigation.SupportNavigationFragment;
import com.google.android.libraries.navigation.TimeAndDistance;
import com.google.android.libraries.navigation.Waypoint;
import java.util.ArrayList;
import java.util.List;

/**
 * An activity that displays a map and a navigation UI, guiding the user from their current location
 * to multiple destinations, also known as waypoints.
 */
public class NavigationActivityMultiDestination extends AppCompatActivity {

  private static final String TAG = NavigationActivityMultiDestination.class.getSimpleName();
  private static final String DISPLAY_BOTH = "both";
  private static final String DISPLAY_TOAST = "toast";
  private static final String DISPLAY_LOG = "log";

  private Navigator mNavigator;
  private RoadSnappedLocationProvider mRoadSnappedLocationProvider;
  private SupportNavigationFragment mNavFragment;
  private final List<Waypoint> mWaypoints = new ArrayList<>();

  private Navigator.ArrivalListener mArrivalListener;
  private Navigator.RouteChangedListener mRouteChangedListener;
  private Navigator.RemainingTimeOrDistanceChangedListener mRemainingTimeOrDistanceChangedListener;
  private RoadSnappedLocationProvider.LocationListener mLocationListener;

  private Bundle mSavedInstanceState;
  private static final String KEY_JOURNEY_IN_PROGRESS = "journey_in_progress";
  private boolean mJourneyInProgress = false;

  // Set fields for requesting location permission.
  private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
  private boolean mLocationPermissionGranted;

  /**
   * Sets up the navigator when the activity is created.
   *
   * @param savedInstanceState The activity state bundle.
   */
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Save the navigator state, used to determine whether a journey is in progress.
    mSavedInstanceState = savedInstanceState;
    if (mSavedInstanceState != null && mSavedInstanceState.containsKey(KEY_JOURNEY_IN_PROGRESS)) {
      mJourneyInProgress = (mSavedInstanceState.getInt(KEY_JOURNEY_IN_PROGRESS) != 0);
    }

    setContentView(R.layout.activity_main);

    // Initialize the Navigation SDK.
    initializeNavigationSdk();
  }

  /** Releases navigation listeners when the activity is destroyed. */
  @Override
  protected void onDestroy() {
    super.onDestroy();

    if ((mJourneyInProgress) && (this.isFinishing())) {
      mNavigator.removeArrivalListener(mArrivalListener);
      mNavigator.removeRouteChangedListener(mRouteChangedListener);
      mNavigator.removeRemainingTimeOrDistanceChangedListener(
          mRemainingTimeOrDistanceChangedListener);
      if (mRoadSnappedLocationProvider != null) {
        mRoadSnappedLocationProvider.removeLocationListener(mLocationListener);
      }
      displayMessage("OnDestroy: Released navigation listeners.", DISPLAY_LOG);
    }
  }

  /** Saves the state of the app when the activity is paused. */
  @Override
  protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    if (mJourneyInProgress) {
      outState.putInt(KEY_JOURNEY_IN_PROGRESS, 1);
    } else {
      outState.putInt(KEY_JOURNEY_IN_PROGRESS, 0);
    }
  }

  /**
   * Starts the Navigation SDK and sets the camera to follow the device's location. Calls the
   * navigateToPlaces() method when the navigator is ready.
   */
  private void initializeNavigationSdk() {
    /*
     * Request location permission, so that we can get the location of the
     * device. The result of the permission request is handled by a callback,
     * onRequestPermissionsResult.
     */
    if (ContextCompat.checkSelfPermission(
            this.getApplicationContext(), android.Manifest.permission.ACCESS_FINE_LOCATION)
        == PackageManager.PERMISSION_GRANTED) {
      mLocationPermissionGranted = true;
    } else {
      ActivityCompat.requestPermissions(
          this,
          new String[] {android.Manifest.permission.ACCESS_FINE_LOCATION},
          PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
    }

    if (!mLocationPermissionGranted) {
      displayMessage(
          "Error loading Navigation SDK: " + "The user has not granted location permission.",
          DISPLAY_BOTH);
      return;
    }

    // Get a navigator.
    NavigationApi.getNavigator(
        this,
        new NavigationApi.NavigatorListener() {
          /** Sets up the navigation UI when the navigator is ready for use. */
          @Override
          public void onNavigatorReady(Navigator navigator) {
            displayMessage("Navigator ready.", DISPLAY_BOTH);
            mNavigator = navigator;

            mNavFragment =
                (SupportNavigationFragment)
                    getSupportFragmentManager().findFragmentById(R.id.navigation_fragment);

            // Set the camera to follow the device location with 'TILTED' driving view.
            mNavFragment.getMapAsync(
                googleMap -> googleMap.followMyLocation(CameraPerspective.TILTED));

            // Navigate to the specified places.
            navigateToPlaces();
          }

          /**
           * Handles errors from the Navigation SDK.
           *
           * @param errorCode The error code returned by the navigator.
           */
          @Override
          public void onError(@NavigationApi.ErrorCode int errorCode) {
            switch (errorCode) {
              case NavigationApi.ErrorCode.NOT_AUTHORIZED:
                displayMessage(
                    "Error loading Navigation SDK: Your API key is "
                        + "invalid or not authorized to use the Navigation SDK.",
                    DISPLAY_BOTH);
                break;
              case NavigationApi.ErrorCode.TERMS_NOT_ACCEPTED:
                displayMessage(
                    "Error loading Navigation SDK: User did not accept "
                        + "the Navigation Terms of Use.",
                    DISPLAY_BOTH);
                break;
              case NavigationApi.ErrorCode.NETWORK_ERROR:
                displayMessage("Error loading Navigation SDK: Network error.", DISPLAY_BOTH);
                break;
              case NavigationApi.ErrorCode.LOCATION_PERMISSION_MISSING:
                displayMessage(
                    "Error loading Navigation SDK: Location permission " + "is missing.",
                    DISPLAY_BOTH);
                break;
              default:
                displayMessage("Error loading Navigation SDK: " + errorCode, DISPLAY_BOTH);
            }
          }
        });
  }

  /** Requests directions from the user's current location to a list of waypoints. */
  private void navigateToPlaces() {

    // Set up a waypoint for each place that we want to go to.
    createWaypoint("ChIJq6qq6jauEmsRJAf7FjrKnXI", "Sydney Star");
    createWaypoint("ChIJ3S-JXmauEmsRUcIaWtf4MzE", "Sydney Opera House");
    createWaypoint("ChIJLwgLFGmuEmsRzpDhHQuyyoU", "Sydney Conservatorium of Music");

    // If this journey is already in progress, no need to restart navigation.
    // This can happen when the user rotates the device, or sends the app to the background.
    if (mSavedInstanceState != null
        && mSavedInstanceState.containsKey(KEY_JOURNEY_IN_PROGRESS)
        && mSavedInstanceState.getInt(KEY_JOURNEY_IN_PROGRESS) == 1) {
      return;
    }

    // Create a future to await the result of the asynchronous navigator task.
    ListenableResultFuture<Navigator.RouteStatus> pendingRoute =
        mNavigator.setDestinations(mWaypoints);

    // Define the action to perform when the SDK has determined the route.
    pendingRoute.setOnResultListener(
        new ListenableResultFuture.OnResultListener<Navigator.RouteStatus>() {
          @Override
          public void onResult(Navigator.RouteStatus code) {
            switch (code) {
              case OK:
                mJourneyInProgress = true;
                // Hide the toolbar to maximize the navigation UI.
                if (getActionBar() != null) {
                  getActionBar().hide();
                }

                // Register some listeners for navigation events.
                registerNavigationListeners();

                // Display the time and distance to each waypoint.
                displayTimesAndDistances();

                // Enable voice audio guidance (through the device speaker).
                mNavigator.setAudioGuidance(Navigator.AudioGuidance.VOICE_ALERTS_AND_GUIDANCE);

                // Simulate vehicle progress along the route for demo/debug builds.
                if (BuildConfig.DEBUG) {
                  mNavigator
                      .getSimulator()
                      .simulateLocationsAlongExistingRoute(
                          new SimulationOptions().speedMultiplier(5));
                }

                // Start turn-by-turn guidance along the current route.
                mNavigator.startGuidance();
                break;
              // Handle error conditions returned by the navigator.
              case NO_ROUTE_FOUND:
                displayMessage("Error starting navigation: No route found.", DISPLAY_BOTH);
                break;
              case NETWORK_ERROR:
                displayMessage("Error starting navigation: Network error.", DISPLAY_BOTH);
                break;
              case ROUTE_CANCELED:
                displayMessage("Error starting navigation: Route canceled.", DISPLAY_BOTH);
                break;
              default:
                displayMessage("Error starting navigation: " + String.valueOf(code), DISPLAY_BOTH);
            }
          }
        });
  }

  /**
   * Creates a waypoint from a given place ID and title.
   *
   * @param placeId The ID of the place to be converted to a waypoint.
   * @param title A descriptive title for the waypoint.
   */
  private void createWaypoint(String placeId, String title) {
    try {
      mWaypoints.add(Waypoint.builder().setPlaceIdString(placeId).setTitle(title).build());
    } catch (Waypoint.UnsupportedPlaceIdException e) {
      displayMessage(
          "Error starting navigation: Place ID is not supported: " + placeId, DISPLAY_BOTH);
    }
  }

  /** Displays the calculated travel time and distance to each waypoint. */
  private void displayTimesAndDistances() {
    List<TimeAndDistance> timesAndDistances = mNavigator.getTimeAndDistanceList();
    int leg = 1;
    String message = "You're on your way!";
    for (TimeAndDistance timeAndDistance : timesAndDistances) {
      message =
          message
              + "\nRoute leg: "
              + leg++
              + ": Travel time (seconds): "
              + timeAndDistance.getSeconds()
              + ". Distance (meters): "
              + timeAndDistance.getMeters();
    }
    displayMessage(message, DISPLAY_BOTH);
  }

  /**
   * Registers some event listeners to show a message and take other necessary steps when specific
   * navigation events occur.
   */
  private void registerNavigationListeners() {
    mArrivalListener =
        new Navigator.ArrivalListener() {
          @Override
          public void onArrival(ArrivalEvent arrivalEvent) {
            displayMessage(
                "onArrival: You've arrived at a waypoint: "
                    + mNavigator.getCurrentRouteSegment().getDestinationWaypoint().getTitle(),
                DISPLAY_BOTH);
            // Start turn-by-turn guidance for the next leg of the route.
            if (arrivalEvent.isFinalDestination()) {
              displayMessage("onArrival: You've arrived at the final destination.", DISPLAY_BOTH);
            } else {
              mNavigator.continueToNextDestination();
              mNavigator.startGuidance();
            }
          }
        };
    // Listens for arrival at a waypoint.
    mNavigator.addArrivalListener(mArrivalListener);

    mRouteChangedListener =
        new Navigator.RouteChangedListener() {
          @Override
          public void onRouteChanged() {
            displayMessage(
                "onRouteChanged: The driver's route has changed. Current waypoint: "
                    + mNavigator.getCurrentRouteSegment().getDestinationWaypoint().getTitle(),
                DISPLAY_LOG);
          }
        };
    // Listens for changes in the route.
    mNavigator.addRouteChangedListener(mRouteChangedListener);

    // Listens for road-snapped location updates.
    mRoadSnappedLocationProvider = NavigationApi.getRoadSnappedLocationProvider(getApplication());
    mLocationListener =
        new RoadSnappedLocationProvider.LocationListener() {
          @Override
          public void onLocationChanged(Location location) {
            displayMessage(
                "onLocationUpdated: Navigation engine has provided a new"
                    + " road-snapped location: "
                    + location.toString(),
                DISPLAY_LOG);
          }

          @Override
          public void onRawLocationUpdate(Location location) {
            displayMessage(
                "onLocationUpdated: Navigation engine has provided a new"
                    + " raw location: "
                    + location.toString(),
                DISPLAY_LOG);
          }
        };
    if (mRoadSnappedLocationProvider != null) {
      mRoadSnappedLocationProvider.addLocationListener(mLocationListener);
    } else {
      displayMessage("ERROR: Failed to get a location provider", DISPLAY_LOG);
    }

    mRemainingTimeOrDistanceChangedListener =
        new Navigator.RemainingTimeOrDistanceChangedListener() {
          @Override
          public void onRemainingTimeOrDistanceChanged() {
            displayMessage(
                "onRemainingTimeOrDistanceChanged: Time or distance estimate" + " has changed.",
                DISPLAY_LOG);
          }
        };
    // Listens for changes in time or distance.
    mNavigator.addRemainingTimeOrDistanceChangedListener(
        60, 100, mRemainingTimeOrDistanceChangedListener);
  }

  /** Handles the result of the request for location permissions. */
  @Override
  public void onRequestPermissionsResult(
      int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    mLocationPermissionGranted = false;
    switch (requestCode) {
      case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION:
        {
          // If request is canceled, the result arrays are empty.
          if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            mLocationPermissionGranted = true;
          }
        }
    }
  }

  /**
   * Shows a message on screen and in the log. Used when something goes wrong.
   *
   * @param errorMessage The message to display.
   */
  private void displayMessage(String errorMessage, String displayMedium) {
    if (displayMedium.equals(DISPLAY_BOTH) || displayMedium.equals(DISPLAY_TOAST)) {
      Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show();
    }

    if (displayMedium.equals(DISPLAY_BOTH) || displayMedium.equals(DISPLAY_LOG)) {
      Log.d(TAG, errorMessage);
    }
  }
}

ตรวจหาการมาถึงจุดหมาย

โดยจุดหมายในที่นี้หมายถึงจุดหมายสุดท้ายหรือจุดแวะพัก หากต้องการตรวจหาการมาถึง ให้โทรหา Navigator.addArrivalListener() ซึ่งจะลงทะเบียนเพื่อรับการโทรกลับเมื่ออุปกรณ์ไปถึงปลายทาง

เมื่อถึงจุดหมาย Navigation SDK สำหรับ Android จะเรียกใช้การเรียกกลับ onArrival() และหยุดการแนะนำเส้นทางแบบเลี้ยวต่อเลี้ยว คุณต้องเรียกใช้ Navigator.continueToNextDestination() อย่างชัดเจนเพื่อไปยังจุดถัดไป และ Navigator.startGuidance() เพื่อนำทางแบบเลี้ยวต่อเลี้ยวต่อ

เมื่อคุณเรียกใช้ continueToNextDestination() โปรแกรมนำทางจะทิ้งข้อมูลทั้งหมดเกี่ยวกับปลายทางก่อนหน้า หากต้องการวิเคราะห์ข้อมูลเกี่ยวกับส่วนของเส้นทางก่อนหน้า คุณต้องดึงข้อมูลจากโปรแกรมนำทางก่อนเรียกใช้ continueToNextDestination()

คุณต้องเรียกใช้ removeArrivalListener(listener) เมื่อไม่ต้องการตัวฟังอีกต่อไปเพื่อหลีกเลี่ยงปัญหาหน่วยความจำรั่ว

mNavigator.addArrivalListener(new Navigator.ArrivalListener() {
    @Override
    public void onArrival(ArrivalEvent arrivalEvent) {
        displayMessage("onArrival: You've arrived at a waypoint: "
                +   mNavigator.getCurrentRouteSegment().getDestinationWaypoint().getTitle(),
                DISPLAY_BOTH);
        // Start turn-by-turn guidance for the next leg of the route.
        if (arrivalEvent.isFinalDestination()) {
            displayMessage("onArrival: You've arrived at the final destination.",
                    DISPLAY_BOTH);
        } else {
            mNavigator.continueToNextDestination();
            mNavigator.startGuidance();
        }
    }
});

รับการอัปเดตตำแหน่ง

รับ RoadSnappedLocationProvider จาก NavigationApi แล้วโทรไปที่ RoadSnappedLocationProvider.addLocationListener() เพื่อลงทะเบียนรับการโทรกลับเมื่อตำแหน่งหรือทิศทางของอุปกรณ์เปลี่ยนแปลง โปรดทราบว่าตำแหน่งนี้มีการจับคู่กับถนน จึงอาจแตกต่างจากตำแหน่งที่ผู้ให้บริการตำแหน่งแบบรวมแสดงใน API ตำแหน่งของบริการ Google Play

Navigation SDK จะอัปเดตตำแหน่งให้บ่อยที่สุด เมื่อการอัปเดตตำแหน่งพร้อมใช้งาน Navigation SDK จะเรียกใช้การเรียกกลับ onLocationChanged()

การอัปเดตตำแหน่งที่จับคู่กับถนนจะไม่ขึ้นอยู่กับการนำทาง และสามารถทำงานต่อไปได้แม้ว่าการนำทางจะหยุดแล้วก็ตาม การสมัครรับการอัปเดตตำแหน่งอาจทำให้แบตเตอรี่หมด หน่วยความจำรั่ว หรือมีการรวบรวมข้อมูลตำแหน่งของอุปกรณ์โดยไม่ตั้งใจหากคุณปล่อยให้การอัปเดตตำแหน่งทำงานอยู่เบื้องหลัง โทรไปที่ RoadSnappedLocationProvider.removeLocationListener เมื่อไม่ต้องการฟังเสียงอีกต่อไป

mRoadSnappedLocationProvider =
        NavigationApi.getRoadSnappedLocationProvider(getApplication());
if (mRoadSnappedLocationProvider != null) {
    mRoadSnappedLocationProvider.addLocationListener(
            new RoadSnappedLocationProvider.LocationListener() {
                @Override
                public void onLocationChanged(Location location) {
                    displayMessage("onLocationUpdated: Navigation engine has provided a new"
                                    +   " road-snapped location: "
                                    +   location.toString(),
                            DISPLAY_LOG);
                }
            });
} else {
    displayMessage("ERROR: Failed to get a location provider", DISPLAY_LOG);
}

รับข้อมูลอัปเดตเวลาและระยะทาง

Call Navigator.addRemainingTimeOrDistanceChangedListener() เพื่อลงทะเบียนรับการโทรกลับเมื่อเวลาที่เหลือ (วินาที) หรือระยะทาง (เมตร) เปลี่ยนแปลงมากกว่าเกณฑ์ที่กำหนด

เมื่อการเปลี่ยนแปลงเวลาหรือระยะทางเกินกว่าจำนวนที่ระบุไว้ Navigation SDK จะเรียกใช้การเรียกคืน onRemainingTimeOrDistanceChanged()

หากต้องการดูเวลาและระยะทางที่เหลือ ให้โทรไปที่ Navigator.getTimeAndDistanceList() โปรดทราบว่าเวลาและระยะทางในรายการจะรวมกัน โดยจะแสดงเวลาและระยะทางจากตำแหน่งปัจจุบันไปยังจุดสังเกตแต่ละจุด ไม่ใช่จากจุดสังเกตหนึ่งไปยังอีกจุดหนึ่ง ตอนนี้ออบเจ็กต์ TimeAndDistance จะแสดงผล delaySeverity ด้วย ซึ่งจะเป็นค่าหนัก ปานกลาง เบา หรือไม่ทราบ ซึ่งสอดคล้องกับสีที่คุณเห็นใน ETA ใน UI ของ Maps (มาก = สีแดง ปานกลาง = สีเหลือง น้อย = สีเขียว) ซึ่งมีประโยชน์ในกรณีที่คุณต้องสร้างส่วนท้ายเวลาถึงโดยประมาณของคุณเอง

คุณต้องเรียกใช้ Navigator.removeRemainingTimeOrDistanceChangedListener(listener) เมื่อไม่ต้องการตัวฟังอีกต่อไปเพื่อหลีกเลี่ยงปัญหาหน่วยความจำรั่ว

ตัวอย่างด้านล่างจะขอการติดต่อกลับหากเวลาที่เหลือเปลี่ยนแปลงมากกว่า 60 วินาทีหรือระยะทางที่เหลือเปลี่ยนแปลงมากกว่า 100 เมตร

mNavigator.addRemainingTimeOrDistanceChangedListener(60, 100,
        new Navigator.RemainingTimeOrDistanceChangedListener() {
            @Override
            public void onRemainingTimeOrDistanceChanged() {
                displayMessage("onRemainingTimeOrDistanceChanged: Time or distance estimate"
                        +   " has changed.",
                        DISPLAY_LOG);
            }
        });

คุณสามารถแสดงข้อมูลเวลาและระยะทางที่เหลือได้โดยใช้จอแสดงผลในตัวโดยใช้เมธอด setEtaCardEnabled() และส่งพารามิเตอร์ที่มีค่า TRUE หากต้องการซ่อนการแสดงเวลาและระยะทาง ให้ตั้งค่านี้เป็น FALSE

นอกจากนี้ คุณยังแสดงเวลาถึงจุดหมายโดยประมาณสำหรับจุดแวะพักหลายจุดได้โดยใช้เมธอด getTimeAndDistanceList()

รับข้อมูลอัปเดตเส้นทาง

โทรหา Navigator.addRouteChangedListener() เพื่อลงทะเบียนรับการติดต่อกลับเมื่อเส้นทางเปลี่ยนแปลง

เมื่อเส้นทางเปลี่ยนแปลง Navigation SDK จะเรียกใช้การเรียกกลับ onRouteChanged() คุณสามารถโทรไปที่ Navigator.getRouteSegments และ Navigator.getCurrentRouteSegment() เพื่อค้นหาเส้นทางใหม่

คุณต้องเรียกใช้ removeRouteChangedListener(listener) เมื่อไม่ต้องการตัวฟังอีกต่อไปเพื่อหลีกเลี่ยงปัญหาหน่วยความจำรั่ว

mNavigator.addRouteChangedListener(new Navigator.RouteChangedListener() {
    @Override
    public void onRouteChanged() {
        displayMessage("onRouteChanged: The driver's route has changed. Current waypoint: "
                +   mNavigator.getCurrentRouteSegment().getDestinationWaypoint().getTitle(),
                DISPLAY_LOG);
    }
});

ตรวจหาเมื่อโหมดกลางคืนเปลี่ยนแปลง

โทรไปที่ NavigationView.addOnNightModeChangedListener หรือ SupportNavigationFragment.addOnNightModeChangedListener เพื่อลงทะเบียนรับการติดต่อกลับเมื่อมีการเปลี่ยนแปลงโหมดกลางคืน

ตัวอย่างต่อไปนี้แสดงการฟังการเปลี่ยนแปลงโหมดกลางคืนในฟрагเมนต์การนำทาง

mNavFragment.addOnNightModeChangedListener(new NavigationView.OnNightModeChangedListener() {
    @Override
    public void onNightModeChanged(NightModeChangedEvent nightModeChangedEvent) {
        displayMessage("Night mode is active: " + nightModeChangedEvent.inNightMode(),
        DISPLAY_LOG);
    }
});

นอกจากนี้ คุณยังตั้งค่าโหมดกลางคืนแบบเป็นโปรแกรมได้ด้วย ดูข้อมูลเพิ่มเติมได้ที่ตั้งค่าโหมดกลางคืน