webView не отображает веб-сайт в автономном режиме
У меня есть приложение, которое регистрируется в GCM для push-уведомлений. Этот код работает нормально и не является источником моей проблемы. После регистрации приложение просто отображает веб-сайт в WebView. Пока все хорошо, все работает, если сетевой адаптер устройства включен.
Если сетевой адаптер выключен, то веб-просмотр должен загружаться из кеша. Эта часть не работает. Я следовал приведенному ниже руководству и немного взял его части, чтобы сохранить страницы веб-сайта в кэше, сохраненном на SD-карте.
Если я запускаю приложение, отображается веб-сайт. Если я затем выключу сетевой адаптер и зайду на сайт, он не будет отображаться. Я проверяю каталог кеша на sdcard и части сайта записываются в кеш.
Почему сайт не загружается из кэша в автономном режиме?
Можно ли сохранить веб-страницы в кэше до тех пор, пока приложение не будет удалено или Android не примет иное решение?
Учебник покажет вам, как создать каталог на SDCard и записать в него. Каталоги существуют, но веб-просмотр не восстанавливается из этого кэша в автономном режиме.
ниже показано, как я называю основной вид деятельности, который отображает веб-просмотр.
Intent i = new Intent(getApplicationContext(), MainActivity.class);
//i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.putExtra("name", "hardcoded client name");
i.putExtra("email", "hardcoded email");
startActivity(i);
finish();
.
Вот полный MainActivity. Вы можете проигнорировать первую часть, так как это код, который обрабатывает GCM-уведомления, все работает. Мне нужно знать, почему веб-просмотр не будет загружаться из кеша.
import static com.bmi.bmitestapp.CommonUtilities.DISPLAY_MESSAGE_ACTION;
import static com.bmi.bmitestapp.CommonUtilities.EXTRA_MESSAGE;
import static com.bmi.bmitestapp.CommonUtilities.SENDER_ID;
import java.io.File;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.TextView;
import android.widget.Toast;
import android.webkit.*;
import com.google.android.gcm.GCMRegistrar;
public class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getSimpleName();
// label to display gcm messages
TextView lblMessage;
WebView webView;
// Asyntask
AsyncTask<Void, Void, Void> mRegisterTask;
// Alert dialog manager
AlertDialogManager alert = new AlertDialogManager();
// Connection detector
ConnectionDetector cd;
public static String name;
public static String email;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e(TAG, "in onCreate in mainactivity");
cd = new ConnectionDetector(getApplicationContext());
// Check if Internet present
// if (!cd.isConnectingToInternet()) {
// // Internet Connection is not present
// alert.showAlertDialog(MainActivity.this,
// "Internet Connection Error",
// "Please connect to working Internet connection", false);
// // stop executing code by return
// return;
// }
// Getting name, email from intent
Intent i = getIntent();
name = i.getStringExtra("name");
email = i.getStringExtra("email");
// Make sure the device has the proper dependencies.
GCMRegistrar.checkDevice(this);
// Make sure the manifest was properly set - comment out this line
// while developing the app, then uncomment it when it's ready.
GCMRegistrar.checkManifest(this);
lblMessage = (TextView) findViewById(R.id.lblMessage);
registerReceiver(mHandleMessageReceiver, new IntentFilter(
DISPLAY_MESSAGE_ACTION));
// Get GCM registration id
final String regId = GCMRegistrar.getRegistrationId(this);
// Check if regid already presents
if (regId.equals("")) {
// Registration is not present, register now with GCM
GCMRegistrar.register(this, SENDER_ID);
} else {
// Device is already registered on GCM
if (GCMRegistrar.isRegisteredOnServer(this)) {
// Skips registration.
Toast.makeText(getApplicationContext(), "Already registered with GCM", Toast.LENGTH_LONG).show();
} else {
// Try to register again, but not in the UI thread.
// It's also necessary to cancel the thread onDestroy(),
// hence the use of AsyncTask instead of a raw thread.
final Context context = this;
mRegisterTask = new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
// Register on our server
// On server creates a new user
ServerUtilities.register(context, name, email, regId);
return null;
}
@Override
protected void onPostExecute(Void result) {
mRegisterTask = null;
}
};
mRegisterTask.execute(null, null, null);
}
}
webView = (WebView)findViewById(R.id.webView1);
// Initialize the WebView
webView.getSettings().setSupportZoom(true);
webView.getSettings().setBuiltInZoomControls(true);
webView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
webView.setScrollbarFadingEnabled(true);
webView.getSettings().setLoadsImagesAutomatically(true);
webView.getSettings().setDomStorageEnabled(true);
// Set cache size to 8 mb by default. should be more than enough
webView.getSettings().setAppCacheMaxSize(1024*1024*8);
// This next one is crazy. It's the DEFAULT location for your app's cache
// But it didn't work for me without this line.
// UPDATE: no hardcoded path. Thanks to Kevin Hawkins
String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath();
Log.e(TAG, "appCachePath = " + appCachePath);
webView.getSettings().setAppCachePath(appCachePath);
webView.getSettings().setAllowFileAccess(true);
webView.getSettings().setAppCacheEnabled(true);
// Load the URLs inside the WebView, not in the external web browser
webView.setWebViewClient(new WebViewClient());
if (savedInstanceState == null)
{
if(isNetworkAvailable() == true){
Log.e(TAG, "we have a network connection");
webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
webView.loadUrl("http://bmi.cubecore.co.uk");
} else {
Log.e(TAG, "we don't have a network connection");
webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ONLY);
webView.loadUrl("http://bmi.cubecore.co.uk");
}
}
} //end of oncreate
private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null;
}
/**
* Receiving push messages
* */
private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
// Waking up mobile if it is sleeping
WakeLocker.acquire(getApplicationContext());
/**
* Take appropriate action on this message
* depending upon your app requirement
* For now i am just displaying it on the screen
* */
// Showing received message
lblMessage.append(newMessage + "\n");
Toast.makeText(getApplicationContext(), "New Message: " + newMessage, Toast.LENGTH_LONG).show();
// Releasing wake lock
WakeLocker.release();
}
};
@Override
protected void onDestroy() {
super.onDestroy();
// Clear the cache (this clears the WebViews cache for the entire application)
//webView.clearCache(false);
if (mRegisterTask != null) {
mRegisterTask.cancel(true);
}
try {
unregisterReceiver(mHandleMessageReceiver);
GCMRegistrar.onDestroy(this);
} catch (Exception e) {
Log.e("UnRegister Receiver Error", "> " + e.getMessage());
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
@Override
protected void onResume() {
super.onResume();
Log.e(TAG, "in onResume in mainactivity");
}
@Override
public File getCacheDir()
{
// NOTE: this method is used in Android 2.1
Log.e(TAG, "getcachedir");
return getApplicationContext().getCacheDir();
}
@Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
// Save the state of the WebView
webView.saveState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
// Restore the state of the WebView
webView.restoreState(savedInstanceState);
}
}
.
Вот код из учебника выше, который пишет в SDCard.
package com.bmi.bmitestapp;
import java.io.File;
import android.app.Application;
import android.os.Environment;
import android.util.Log;
public class ApplicationExt ex,tends Application
{
private static final String TAG = ApplicationExt.class.getSimpleName();
// NOTE: the content of this path will be deleted
// when the application is uninstalled (Android 2.2 and higher)
protected File extStorageAppBasePath;
protected File extStorageAppCachePath;
@Override
public void onCreate()
{
super.onCreate();
Log.e(TAG, "inside appext");
// Check if the external storage is writeable
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
{
// Retrieve the base path for the application in the external storage
File externalStorageDir = Environment.getExternalStorageDirectory();
if (externalStorageDir != null)
{
// {SD_PATH}/Android/data/com.devahead.androidwebviewcacheonsd
extStorageAppBasePath = new File(externalStorageDir.getAbsolutePath() +
File.separator + "Android" + File.separator + "data" +
File.separator + getPackageName());
}
if (extStorageAppBasePath != null)
{
// {SD_PATH}/Android/data/com.devahead.androidwebviewcacheonsd/cache
extStorageAppCachePath = new File(extStorageAppBasePath.getAbsolutePath() +
File.separator + "cache");
boolean isCachePathAvailable = true;
if (!extStorageAppCachePath.exists())
{
// Create the cache path on the external storage
isCachePathAvailable = extStorageAppCachePath.mkdirs();
}
if (!isCachePathAvailable)
{
// Unable to create the cache path
extStorageAppCachePath = null;
}
}
}
}
@Override
public File getCacheDir()
{
// NOTE: this method is used in Android 2.2 and higher
if (extStorageAppCachePath != null)
{
// Use the external storage for the cache
Log.e(TAG, "extStorageAppCachePath = " + extStorageAppCachePath);
return extStorageAppCachePath;
}
else
{
// /data/data/com.devahead.androidwebviewcacheonsd/cache
return super.getCacheDir();
}
}
}
Я думал, что включу немного регистрации. Это запись из новой установки с включенным сетевым адаптером.
01-29 14:13:10.220: D/dalvikvm(16904): Late-enabling CheckJNI
01-29 14:13:10.470: E/ApplicationExt(16904): inside appext
01-29 14:13:10.720: E/RegisterActivity(16904): in onresume in registeractivity
01-29 14:13:10.880: D/libEGL(16904): loaded /system/lib/egl/libEGL_tegra.so
01-29 14:13:11.000: D/libEGL(16904): loaded /system/lib/egl/libGLESv1_CM_tegra.so
01-29 14:13:11.030: D/libEGL(16904): loaded /system/lib/egl/libGLESv2_tegra.so
01-29 14:13:11.070: D/OpenGLRenderer(16904): Enabling debug mode 0
01-29 14:13:18.390: E/ApplicationExt(16904): extStorageAppCachePath = /mnt/sdcard/Android/data/com.bmi.bmitestapp/cache
01-29 14:13:18.390: D/webview(16904): [InitTabEffectPivot] >> nScreenWidth = 720
01-29 14:13:18.390: D/webview(16904): [InitTabEffectPivot] >> nScreenHeight = 1280
01-29 14:13:18.390: D/SqliteDatabaseCpp(16904): Registering sqlite logging func: /data/data/com.bmi.bmitestapp/databases/webview.db
01-29 14:13:18.390: D/SqliteDatabaseCpp(16904): DB info: open db, path = /data/data/com.bmi.bmitestapp/databases , key = sefraes, flag = 6, cannot stat file, errno = 2, message = No such file or directory
01-29 14:13:18.400: E/MainActivity(16904): in onCreate in mainactivity
01-29 14:13:18.400: D/SqliteDatabaseCpp(16904): DB info: path = /data/data/com.bmi.bmitestapp/databases , key = sefraes, handle: 0x1f9a858, type: w, r/w: (0,1), mode: delete, disk free size: 1276 M
01-29 14:13:18.400: D/GCMRegistrar(16904): resetting backoff for com.bmi.bmitestapp
01-29 14:13:18.420: V/GCMRegistrar(16904): Registering app com.bmi.bmitestapp of senders 598080744593
01-29 14:13:18.430: E/ApplicationExt(16904): extStorageAppCachePath = /mnt/sdcard/Android/data/com.bmi.bmitestapp/cache
01-29 14:13:18.430: E/MainActivity(16904): appCachePath = /mnt/sdcard/Android/data/com.bmi.bmitestapp/cache
01-29 14:13:18.430: E/MainActivity(16904): we have a network connection
01-29 14:13:18.430: E/MainActivity(16904): in onResume in mainactivity
01-29 14:13:18.490: W/webcore(16904): java.lang.Throwable: EventHub.removeMessages(int what = 107) is not supported before the WebViewCore is set up.
01-29 14:13:18.490: W/webcore(16904): at android.webkit.WebViewCore$EventHub.removeMessages(WebViewCore.java:1974)
01-29 14:13:18.490: W/webcore(16904): at android.webkit.WebViewCore$EventHub.access$9100(WebViewCore.java:1008)
01-29 14:13:18.490: W/webcore(16904): at android.webkit.WebViewCore.removeMessages(WebViewCore.java:2215)
01-29 14:13:18.490: W/webcore(16904): at android.webkit.WebView.sendOurVisibleRect(WebView.java:3285)
01-29 14:13:18.490: W/webcore(16904): at android.webkit.ZoomManager.setZoomScale(ZoomManager.java:772)
01-29 14:13:18.490: W/webcore(16904): at android.webkit.ZoomManager.access$1900(ZoomManager.java:59)
01-29 14:13:18.490: W/webcore(16904): at android.webkit.ZoomManager$PostScale.run(ZoomManager.java:1345)
01-29 14:13:18.490: W/webcore(16904): at android.os.Handler.handleCallback(Handler.java:608)
01-29 14:13:18.490: W/webcore(16904): at android.os.Handler.dispatchMessage(Handler.java:92)
01-29 14:13:18.490: W/webcore(16904): at android.os.Looper.loop(Looper.java:156)
01-29 14:13:18.490: W/webcore(16904): at android.app.ActivityThread.main(ActivityThread.java:5045)
01-29 14:13:18.490: W/webcore(16904): at java.lang.reflect.Method.invokeNative(Native Method)
01-29 14:13:18.490: W/webcore(16904): at java.lang.reflect.Method.invoke(Method.java:511)
01-29 14:13:18.490: W/webcore(16904): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
01-29 14:13:18.490: W/webcore(16904): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
01-29 14:13:18.490: W/webcore(16904): at dalvik.system.NativeStart.main(Native Method)
01-29 14:13:18.500: W/webcore(16904): java.lang.Throwable: EventHub.removeMessages(int what = 105) is not supported before the WebViewCore is set up.
01-29 14:13:18.500: W/webcore(16904): at android.webkit.WebViewCore$EventHub.removeMessages(WebViewCore.java:1974)
01-29 14:13:18.500: W/webcore(16904): at android.webkit.WebViewCore$EventHub.access$9100(WebViewCore.java:1008)
01-29 14:13:18.500: W/webcore(16904): at android.webkit.WebViewCore.removeMessages(WebViewCore.java:2215)
01-29 14:13:18.500: W/webcore(16904): at android.webkit.WebView.sendViewSizeZoom(WebView.java:3520)
01-29 14:13:18.500: W/webcore(16904): at android.webkit.ZoomManager.setZoomScale(ZoomManager.java:778)
01-29 14:13:18.500: W/webcore(16904): at android.webkit.ZoomManager.access$1900(ZoomManager.java:59)
01-29 14:13:18.500: W/webcore(16904): at android.webkit.ZoomManager$PostScale.run(ZoomManager.java:1345)
01-29 14:13:18.500: W/webcore(16904): at android.os.Handler.handleCallback(Handler.java:608)
01-29 14:13:18.500: W/webcore(16904): at android.os.Handler.dispatchMessage(Handler.java:92)
01-29 14:13:18.500: W/webcore(16904): at android.os.Looper.loop(Looper.java:156)
01-29 14:13:18.500: W/webcore(16904): at android.app.ActivityThread.main(ActivityThread.java:5045)
01-29 14:13:18.500: W/webcore(16904): at java.lang.reflect.Method.invokeNative(Native Method)
01-29 14:13:18.500: W/webcore(16904): at java.lang.reflect.Method.invoke(Method.java:511)
01-29 14:13:18.500: W/webcore(16904): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
01-29 14:13:18.500: W/webcore(16904): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
01-29 14:13:18.500: W/webcore(16904): at dalvik.system.NativeStart.main(Native Method)
01-29 14:13:18.530: D/OpenGLRenderer(16904): Flushing caches (mode 0)
01-29 14:13:18.570: I/SqliteDatabaseCpp(16904): sqlite returned: error code = 1, msg = no such table: CacheGroups
01-29 14:13:18.570: I/SqliteDatabaseCpp(16904): sqlite returned: error code = 1, msg = no such table: Caches
01-29 14:13:18.570: I/SqliteDatabaseCpp(16904): sqlite returned: error code = 1, msg = no such table: Origins
01-29 14:13:18.570: I/SqliteDatabaseCpp(16904): sqlite returned: error code = 1, msg = no such table: DeletedCacheResources
01-29 14:13:18.850: E/ApplicationExt(16904): extStorageAppCachePath = /mnt/sdcard/Android/data/com.bmi.bmitestapp/cache
01-29 14:13:19.330: I/PRIME(16904): <CallBackProxy> Send to WebViewClient.
01-29 14:13:19.370: V/GCMBroadcastReceiver(16904): onReceive: com.google.android.c2dm.intent.REGISTRATION
01-29 14:13:19.370: V/GCMBroadcastReceiver(16904): GCM IntentService class: com.bmi.bmitestapp.GCMIntentService
01-29 14:13:19.370: V/GCMBaseIntentService(16904): Acquiring wakelock
01-29 14:13:19.460: V/GCMBaseIntentService(16904): Intent service name: GCMIntentService-598080744593-1
01-29 14:13:19.470: E/GCMRegistrar(16904): internal error: retry receiver class not set yet
01-29 14:13:19.480: V/GCMRegistrar(16904): Registering receiver
01-29 14:13:19.480: D/GCMBaseIntentService(16904): handleRegistration: registrationId = APA91bFytZvnkmsEVHSnw5VRxIwfPRmPsSRVrgRNRa5ww3oqCfnLEZMaBBNtQtlZoK4RD4VQXfAfKDsQUa53PwQBH_rwuI_gEEdHQhxadpBVmJ7L3Dxy90Bzryg_aCWx20-cdZ32cbiiaGR3zUMjpqZizYQbnARN4w, error = null, unregistered = null
01-29 14:13:19.480: D/GCMRegistrar(16904): resetting backoff for com.bmi.bmitestapp
01-29 14:13:19.480: V/GCMRegistrar(16904): Saving regId on app version 1
01-29 14:13:19.490: I/GCMIntentService(16904): Device registered: regId = APA91bFytZvnkmsEVHSnw5VRxIwfPRmPsSRVrgRNRa5ww3oqCfnLEZMaBBNtQtlZoK4RD4VQXfAfKDsQUa53PwQBH_rwuI_gEEdHQhxadpBVmJ7L3Dxy90Bzryg_aCWx20-cdZ32cbiiaGR3zUMjpqZizYQbnARN4w
01-29 14:13:19.490: D/NAME(16904): hardcoded client name
01-29 14:13:19.490: I/bmi GCM(16904): registering device (regId = APA91bFytZvnkmsEVHSnw5VRxIwfPRmPsSRVrgRNRa5ww3oqCfnLEZMaBBNtQtlZoK4RD4VQXfAfKDsQUa53PwQBH_rwuI_gEEdHQhxadpBVmJ7L3Dxy90Bzryg_aCWx20-cdZ32cbiiaGR3zUMjpqZizYQbnARN4w)
01-29 14:13:19.490: D/bmi GCM(16904): Attempt #1 to register
01-29 14:13:19.500: V/bmi GCM(16904): Posting 'email=hardcoded email®Id=APA91bFytZvnkmsEVHSnw5VRxIwfPRmPsSRVrgRNRa5ww3oqCfnLEZMaBBNtQtlZoK4RD4VQXfAfKDsQUa53PwQBH_rwuI_gEEdHQhxadpBVmJ7L3Dxy90Bzryg_aCWx20-cdZ32cbiiaGR3zUMjpqZizYQbnARN4w&name=hardcoded client name' to http://mobilewebexpert.co.uk/pushtest/register.php
01-29 14:13:19.500: E/URL(16904): > http://mobilewebexpert.co.uk/pushtest/register.php
01-29 14:13:20.610: V/GCMRegistrar(16904): Setting registeredOnServer status as true until 2013-02-05 14:13:20.617
01-29 14:13:20.620: V/GCMBaseIntentService(16904): Releasing wakelock
01-29 14:13:21.470: D/skia(16904): notifyPluginsOnFrameLoad not postponed
01-29 14:13:21.570: D/SQLiteDatabase(16904): Create pool connection
01-29 14:13:21.570: D/SqliteDatabaseCpp(16904): DB info: open db, path = /data/data/com.bmi.bmitestapp/databases , key = sefraes, flag = 1, file size = 12288
01-29 14:13:21.570: D/SqliteDatabaseCpp(16904): DB info: path = /data/data/com.bmi.bmitestapp/databases , key = sefraes, handle: 0x2797350, type: r, r/w: (1,1), mode: wal, disk free size: 1276 M
.
Это регистрация после того, как я выключил сетевой адаптер.
01-29 14:16:57.080: E/RegisterActivity(16904): in onresume in registeractivity
01-29 14:17:03.490: D/webview(16904): [InitTabEffectPivot] >> nScreenWidth = 720
01-29 14:17:03.490: D/webview(16904): [InitTabEffectPivot] >> nScreenHeight = 1280
01-29 14:17:03.490: E/MainActivity(16904): in onCreate in mainactivity
01-29 14:17:03.490: V/GCMRegistrar(16904): Is registered on server: true
01-29 14:17:03.500: E/ApplicationExt(16904): extStorageAppCachePath = /mnt/sdcard/Android/data/com.bmi.bmitestapp/cache
01-29 14:17:03.500: E/MainActivity(16904): appCachePath = /mnt/sdcard/Android/data/com.bmi.bmitestapp/cache
01-29 14:17:03.500: E/MainActivity(16904): we don't have a network connection
01-29 14:17:03.500: E/MainActivity(16904): in onResume in mainactivity
01-29 14:17:03.500: D/chromium(16904): Unknown chromium error: -400
01-29 14:17:03.540: D/skia(16904): notifyPluginsOnFrameLoad not postponed
01-29 14:17:03.580: D/OpenGLRenderer(16904): Flushing caches (mode 0)
Одна вещь, которую я заметил, это может быть ничто, но регистрация - это деятельность, которая вызывает MainActivity. У RegisterActivity просто есть кнопка, которая запускает Intent for MainActivity. После того, как сетевой адаптер выключен, я должен нажать кнопку на registerAcctivity, которая вызывает OnCreate в MainActivity. Это как новый экземпляр MainActivity? Может ли это повлиять на кеширование веб-просмотра? По сути, onDestroy основной деятельности должен был быть вызван по пути.
Еще одна вещь привлекла мое внимание.
01-29 14:17:03.580: D/OpenGLRenderer(16904): Flushing caches (mode 0)