WebViewCompat.navigate adalah alternatif yang ditingkatkan untuk
WebView.loadUrl yang memberikan kontrol terperinci atas pemuatan halaman web,
pengelolaan histori, dan pelacakan siklus proses navigasi di WebView.
Sebelumnya, memulai navigasi halaman menggunakan loadUrl memiliki batasan yang signifikan:
- Tidak ada penggantian entri histori: Anda tidak dapat mengganti entri histori saat ini, sehingga tidak mungkin menavigasi ke halaman baru tanpa menambahkan entri ke tumpukan kembali.
- Callback yang terpisah: Tidak ada mekanisme langsung untuk mengorelasikan panggilan
loadUrltertentu dengan peristiwa callback berikutnya diWebViewClient. - Header tambahan tidak disimpan: Header kustom yang diteruskan ke
loadUrltidak disimpan sebagai bagian dari statusWebView, sehingga akan hilang saat memulihkan status.
API WebViewCompat.navigate mengatasi masalah ini dengan memperkenalkan fitur berikut:
- Penggantian entri histori navigasi: Memungkinkan Anda mengganti halaman saat ini di tumpukan histori
WebView. - Pelacakan callback yang dikorelasikan: Menampilkan objek
Navigationyang berfungsi sebagai ID unik di semua tahap siklus proses navigasi. - Dukungan header status tersimpan: Header tambahan disimpan dengan andal dalam paket status
WebViewsehingga dapat digunakan kembali saat memulihkan status.
Kemampuan dan batasan utama
Sebelum mengadopsi WebViewCompat.navigate, pertimbangkan aturan dan batasan operasional berikut:
Keamanan thread: Anda harus memanggil
WebViewCompat.navigatedi thread UI (utama).Pembatalan dan prioritas: Navigasi yang sedang berlangsung tidak dapat dibatalkan secara eksplisit. Namun, memulai panggilan
navigatebaru diWebViewyang sama akan menggantikan navigasi aktif.Dukungan skema URI: Skema URI standar (seperti
https:danhttp:) dan kustom didukung. Skemajavascript:tidak didukung.Batas ukuran URL: Panjang string URL maksimum yang didukung adalah 2 MB.
Pemeriksaan fitur: Selalu periksa ketersediaan fitur menggunakan
WebViewFeature.isFeatureSupportedsebelum memanggil API untuk mempertahankan kompatibilitas di berbagai versi WebView APK.
Memulai navigasi dan melacak siklus proses
Untuk mengonfigurasi navigasi dan melacak siklus prosesnya, lakukan hal berikut:
- Daftarkan implementasi
NavigationListenermenggunakanWebViewCompat.addNavigationListenerselamaWebViewpenyiapan untuk menerima callback siklus proses terstruktur. Daftarkan pemroses sekali (bukan pada setiap panggilan navigasi) untuk mencegah kebocoran memori dan eksekusi callback duplikat. - Buat instance
NavigationParametersmenggunakanNavigationParameters.Builderuntuk menentukan perilaku opsional, seperti penggantian histori atau header HTTP kustom. - Panggil
WebViewCompat.navigate, lalu teruskan instanceWebView, URL tujuan, dan parameter.
WebViewCompat.navigate menampilkan objek Navigation yang mengidentifikasi permintaan secara unik. Dalam callback NavigationListener, bandingkan
objek ini dengan parameter Navigation yang masuk untuk melacak navigasi tertentu.
Contoh penerapan
Contoh berikut menunjukkan cara mengonfigurasi parameter navigasi, memanggil WebViewCompat.navigate, dan memproses peristiwa siklus proses navigasi:
Kotlin
class WebNavigationManager(private val webView: WebView) {
// Track the navigation instance returned by the API
private var currentNavigation: Navigation? = null
init {
// 1. Define listener to observe navigation lifecycle events
val listener = object : NavigationListener {
override fun onNavigationStarted(navigation: Navigation) {
if (navigation == currentNavigation) {
// Navigation started
}
}
override fun onNavigationRedirected(navigation: Navigation) {
if (navigation == currentNavigation) {
// Navigation encountered a redirect
}
}
override fun onNavigationCompleted(navigation: Navigation) {
if (navigation == currentNavigation) {
if (navigation.didCommit()) {
// Navigation committed successfully
} else if (navigation.didCommitErrorPage()) {
// Navigation committed an error page
val statusCode = navigation.statusCode
val error = navigation.webResourceError
}
}
}
override fun onFirstContentfulPaintMillis(page: Page, durationMillis: Long) {
// Match page with current navigation
if (page == currentNavigation?.page) {
// Page rendering started (First Contentful Paint achieved)
}
}
}
// 2. Register listener on the main thread
WebViewCompat.addNavigationListener(webView, listener)
}
@UiThread
fun navigateToPage(url: String) {
// Check feature availability
if (!WebViewFeature.isFeatureSupported(WebViewFeature.WEBVIEW_NAVIGATE_EXPERIMENTAL_V1)) {
// Fall back to standard loadUrl if navigate API is unavailable
webView.loadUrl(url)
return
}
// 3. Configure navigation parameters
val params = NavigationParameters.Builder()
.setShouldReplaceCurrentEntry(true)
.addAdditionalHeaders(
mapOf("X-Test-Navigate-Header" to "TestValue")
)
.build()
// 4. Initiate navigation on the UI thread
currentNavigation = WebViewCompat.navigate(webView, url, params)
}
}
Java
public class WebNavigationManager {
private Navigation mCurrentNavigation;
private final WebView mWebView;
public WebNavigationManager(@NonNull WebView webView) {
mWebView = webView;
setupListener();
}
private void setupListener() {
// 1. Define listener to observe navigation lifecycle events
NavigationListener listener = new NavigationListener() {
@Override
public void onNavigationStarted(@NonNull Navigation navigation) {
if (navigation.equals(mCurrentNavigation)) {
// Navigation started
}
}
@Override
public void onNavigationRedirected(@NonNull Navigation navigation) {
if (navigation.equals(mCurrentNavigation)) {
// Navigation encountered a redirect
}
}
@Override
public void onNavigationCompleted(@NonNull Navigation navigation) {
if (navigation.equals(mCurrentNavigation)) {
if (navigation.didCommit()) {
// Navigation committed successfully
} else if (navigation.didCommitErrorPage()) {
// Navigation committed an error page
int statusCode = navigation.getStatusCode();
WebResourceErrorCompat error = navigation.getWebResourceError();
}
}
}
@Override
public void onFirstContentfulPaintMillis(@NonNull Page page, long durationMillis) {
if (mCurrentNavigation != null && page.equals(mCurrentNavigation.getPage())) {
// Page rendering started (First Contentful Paint achieved)
}
}
};
// 2. Register listener on the main thread
WebViewCompat.addNavigationListener(mWebView, listener);
}
@UiThread
public void navigateToPage(@NonNull String url) {
// Check feature availability
if (!WebViewFeature.isFeatureSupported(WebViewFeature.WEBVIEW_NAVIGATE_EXPERIMENTAL_V1)) {
// Fall back to standard loadUrl if navigate API is unavailable
mWebView.loadUrl(url);
return;
}
// 3. Configure navigation parameters
NavigationParameters params = new NavigationParameters.Builder()
.setShouldReplaceCurrentEntry(true)
.addAdditionalHeaders(Collections.singletonMap(
"X-Test-Navigate-Header", "TestValue"
))
.build();
// 4. Initiate navigation on the UI thread
mCurrentNavigation = WebViewCompat.navigate(mWebView, url, params);
}
}
Mode kegagalan dan penanganan error
API WebViewCompat.navigate menyediakan mekanisme berbeda untuk menangani error konfigurasi dan kegagalan navigasi runtime:
Pengecualian argumen tidak valid
Meneruskan argumen yang tidak valid akan memicu IllegalArgumentException sinkron.
Penyebab umumnya mencakup hal berikut:
- Meneruskan
nulluntuk parameter non-null yang diperlukan (webView,url, atauparams). - Menyediakan skema URL yang tidak didukung, seperti
javascript:. - Meneruskan kunci atau nilai header HTTP yang salah format dan tidak sesuai dengan spesifikasi RFC 2616.
Error proses navigasi
Jika terjadi kegagalan selama permintaan jaringan atau pemuatan halaman (seperti kode status HTTP 404
kode status, kegagalan resolusi DNS, atau error SSL), WebViewCompat.navigate
akan tetap menampilkan objek Navigation yang valid.
Saat navigasi selesai, periksa metode berikut pada Navigation
instance di dalam onNavigationCompleted callback untuk mendiagnosis
kegagalan:
getStatusCode: Menampilkan kode status respons HTTP (misalnya,404atau500).getWebResourceError: Menampilkan objekWebResourceErrorCompatyang menjelaskan error jaringan, seperti waktu tunggu koneksi atau kegagalan pencarian host.didCommitErrorPage: Menunjukkan apakahWebViewmelakukan dan menampilkan halaman error kepada pengguna.didCommit: Menunjukkan apakah navigasi berhasil dilakukan ke halaman target tanpa dibatalkan.
Pengelolaan paket status tersimpan
Saat Anda meneruskan header tambahan dengan NavigationParameters, WebView akan menyimpan header ini dalam paket status tersimpannya sehingga dapat digunakan kembali saat memulihkan status. Namun, kumpulan header yang besar dapat meningkatkan ukuran Bundle status tersimpan secara signifikan.
Jika Anda perlu membatasi ukuran paket untuk mencegah TransactionTooLargeException
selama penyimpanan status Android, gunakan WebViewCompat.saveState. Metode ini memungkinkan Anda menetapkan batas ukuran paket maksimum dalam byte dan secara opsional mengecualikan item histori maju:
Kotlin
// Save state with a maximum bundle size limit (for example, 64 KB)
val maxSizeBytes = 64 * 1024
val includeForwardState = false
val outState = Bundle()
WebViewCompat.saveState(webView, outState, maxSizeBytes, includeForwardState)
Java
// Save state with a maximum bundle size limit (for example, 64 KB)
int maxSizeBytes = 64 * 1024;
boolean includeForwardState = false;
Bundle outState = new Bundle();
WebViewCompat.saveState(webView, outState, maxSizeBytes, includeForwardState);
Paket yang dihasilkan tetap kompatibel dengan metode standar
WebView.restoreState.
Rekomendasi migrasi dan penerapan
Untuk memastikan performa dan stabilitas yang optimal saat menavigasi di WebView, ikuti rekomendasi berikut:
Bermigrasi dari
loadUrlkenavigate: Migrasikan semua panggilan lamaWebView.loadUrlkeWebViewCompat.navigate. Hal ini memastikan pengelolaan histori yang seragam dan memastikan header selalu disimpan sebagai bagian dari status tersimpan.Selalu verifikasi dukungan fitur: Sebelum memanggil API, konfirmasi dukungan runtime dengan
WebViewFeature.isFeatureSupporteduntuk melindungi dari versi WebView yang lebih lama.Korelasikan instance navigasi: Gunakan objek
Navigationyang ditampilkan untuk membedakan navigasi serentak atau memfilter callback saat mengelola beberapa instanceWebView.Daftarkan pemroses sekali selama inisialisasi: Karena
WebViewCompat.addNavigationListenermenambahkan pemroses, bukan mengganti yang ada, daftarkanNavigationListenerAnda sekali selamaWebViewpenyiapan untuk menghindari kebocoran memori dan eksekusi callback duplikat di seluruh navigasi berikutnya.Pantau ukuran status tersimpan: Saat meneruskan payload header yang besar, gunakan
WebViewCompat.saveStatedengan batas ukuran eksplisit untuk menghindari penyimpanan data status yang berlebihan.
Referensi lainnya
Untuk mempelajari lebih lanjut kemampuan web dan pengoptimalan performa yang disematkan, lihat panduan berikut:
- Menyederhanakan penerapan WebView dengan Jetpack Webkit
- Pemuatan spekulatif di WebView
- Mengoptimalkan startup WebView
- Menangani penghentian proses perender WebView