Кэширование страницы в WebView
Как известно при повороте экрана, Activity и WebView пересоздаётся, и заново загружается первая страница. Так как это отнимает время, я решил кешировать страницу, чтобы при повороте экрана, он уже загружал исходную страницу с кэша. Читал немало зарубежных статей, и почти всегда по-разному происходить реализация, так как у меня с переводом проблемы, мне немного сложно с них брать информацию. Помогите, как можно реализовать кэширование в WebView ?
3 ответа 3
Я бы видел 2 способа реализации вашего вопроса:
- Традиционный: в рамках стандартного кэша WebView . Механизм реализации кэша многократно описан и известен. Небольшое уточнение будет только касаться загрузки HTML из кэша. Тут к сожалению прямого доступа к файлам в кэше нет (вроде бы), есть только способ управления загрузкой из кэша. В принципе можно попробовать детектировать поворот экрана и после поворота экрана при загрузке страницы применить нечтно вроде: webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK) — это попытка загрузить сначала кэш и только потом загружать из сети
- Самопальный: надо прочитать страницу в виде HTML кода. Например, так. Далее при повороте экрана «запихнуть» полученный String HTML’а в Bundle savedStateInstance и соответственно вытащить HTML его в Activity.onCreate(Bundle savedStateInstance) и заслать в WebView
ИМХО, мне кажется второй способ будет самый кучерявый.
Источник
Android WebView not loading second page from cache
I have an Android app that simply houses a website. I would like the app to cache the pages of the website for offline use.
I’m doing a simple test to see if the cache is working but unfortunately it is failing to load a page i have previously loaded in online mode, when offline. To make things clearer i load the following 2 pages when in online mode.
I am hoping that the «why-bmi.php» page is loaded into the cache as well as the subsequent page http://www.bmimobile.co.uk/. The latter page has a link on it which refers to the first page. If i then come out of the app and turn the network adapter off then go back into the app the «http://www.bmimobile.co.uk/» page DOES display but when i click the «why-bmi» link that page DOES NOT display. I short toast message displays saying «error loading page».
Can anyone tell me why the webview is not caching loaded page for later offline use?
Here’s the main activity and i’ve extended the Application object defining the appcachepath.
Thanks in advance
.This is the logging when the app is first loaded in online mode
This is the logging when i’ve come out of the app turned off the network adapter then gone back into app in offline mode.
[edit1] Actually on closer inspection of the logging, it seems to have changed when loaded in online mode. below is the logcat in omline mode. There seems to be a problem with the cache storage.
[notes] if i click on the why-bmi button when in online mode then come out of the app, turn the adapter off then click the why-bmi button again then it shows the «error loading page» message.
If i however change to the following urls, my SO page is displayed. If i click the link to my bounty page(this page), then go offline, the SO page is display as you would expect but if you click the bounty link in offline mode then it DOES display. so there are differences between the SO site and the bmi site.
Источник
Preloading/Precaching webpage(the dirty way) for Android webview
We have seen a number of apps implementing custom webview in their native apps to load some data in the form of webpages. But in some cases when they require offline support they have a number of challenges as it is just a webpage loaded in a webview and not a native component so preloading of data or storing it for offline use isn’t possible.
So today we will see how we can preload/precache a webpage in Android for faster and offline loading in webview.
Note: This is a demo I have implemented for one of my use case and not sure if it works for all the use cases or not.
In this demo we will be following these steps:
- Get HTML from a URL and save it into local file.
- Load content of that file into our webview.
So let’s get started.
First, we will add webkit and coroutines dependency into your apps build.gradle .
Now inside our activity class, we will create a method named loadAndSaveDataFromUrlToFile which will load data(HTML) from the server and save it to a text file in our device memory.
After this, we will create a method named saveUrlDataToFile which will start a coroutine to load the webpage and store in local storage using our previously created method loadAndSaveDataFromUrlToFile .
That’s the part for loading and saving the webpage to our device memory. Now we will see how to load this page to our webview while maintaining its assets, CSS and js to be loaded.
Now let’s create a new activity in which we will create a webview which will be used to load this cached webpage.
Now we will change some settings of our webview to enable support for javascript, domstorage, database etc.
Now we will attach webclient to our webview so if we require to handle any events like onPageLoaded, onFailed etc, we can do that with the help of our webclient.
The final step is to load our previously created file which contains all our HTML cached and load it to the webview for this we will create a method named loadUrlIntoWebView .
We have created a coroutine for this task as it is a heavy operation and should not be performed on the mainthread. Once we get our data from the file we convert it to string from bytes then load it to our webview back on the mainthread.
I only focused on main methods and code rather than a full-fledged tutorial and haven’t tied to any architecture to keep it simple. While working for production-ready apps one must keep all logics separated by ViewModel.
Note: we are using loadDataWithBaseURL not loadData as it provides an option to define base URL and history URL along with an encoding type of the cached content we are loading. So it can load all the assets otherwise our webview will not be able to load some assets.
You can download the source code from the URL below:
Источник
Однопоточность в Android WebView
Предыстория
При разработке мобильного приложения для крупной международной компании возникла необходимость отобразить Web страничку в WebView. Страница на Java Script и содержит DOM контент порядка 10-15 Мб. В связи с большим размером страница загружается порядка 30 — 50 секунд, в зависимости от интернет соединения. Такие результаты не радовали, поэтому возникла необходимость тщательного исследования данной проблемы.
Кэширование в WebView
Единственным найденным решением было использование кэширования для загружаемого контента:
Скорость загрузки увеличилась вдвое. Однако, для поддержания актуальности контента, WebView проверяет каждый файл в отдельности на его валидность. Хоть скорость и выросла, время загрузки данной страницы внутри WebView по сравнению с мобильным браузером Chrome уступало в несколько раз.
Однопоточность WebView
После тщательного исследования пришел к выводу, что WebView использует всего один поток для загрузки данных. Это верно как для WebView построенном на собственном WebKit (SDK =19). Chrome в отличии от WebView использует много потоков (число зависит от процессора) и не использует в себе WebView. Поэтому сравнивать WebView с Chrome тоже самое, что сравнивать запорожец с Lamborghini, нет смысла. Разработчики нативного компонента Cromium для WebView не предполагают внедрение многопоточности и считают, что один поток гарантирует стабильную работу.
Не будем забывать, что платформа ориентированна на использование в таких целях сторонних приложений, которые пользователь сам выбрал за какие то свои качества.
Но в рамках моего проекта это не устраивало заказчика. Поэтому было принято решение оставить WebView со всеми его недостатками. Предварительно мне пришлось доказать, что другие крупные проекты так же не будут оперативно работать с исходной страницей:
1. Twitter отказался открывать страницу и сразу предложил использовать браузер.
2. Facebook предложил использовать браузер, но все равно открыл страницу в WebView с такой же скоростью, что и мое решение.
К счастью этого было достаточно и на меня прекратилось давление.
Вывод
Не стоит использовать WebView для отображения больших и сложных страниц. Рекомендованное использование WebView:
1. Для авторизации на каких либо сервисах.
2. Для отображения простых страниц.
3. Для выравнивания текста по ширине (Стандартное TextView не имеет данной функции, но это уже совсем другая история).
Не будем забывать, что в Android используется система Intent, благодаря который мы можем использовать сторонние браузеры, скорость которых заметно выше.
Источник
Оптимизация производительности WebView в Android
В этом материале мы поговорим о том как можно улучшить быстродействие (роизводительность) вашего приложения, игры, которая написана на HTML+CSS+JS и с помощью метода WebView запилена в Андроид.
Любая игра да и современное приложение тоже как известно требуют довольно гладких плавных анимаций (скроллы, появление списка со стороны и тд). Но вот по поводу анимаций в HTML на андроид возникало и возникает по сей день множество споров и неотвеченных вопросов в интернете. Сегодня мы постараемся немного помочь советами как оптимизировать ваше приложение или игру на Андроид написанную на HTML.
1. Используйте CSS анимацию. О том почему и зачем вы прочитаете здесь, где был обзор HTML технологий доставки анимации клиенту.
2. Проверьте валидность вёрстки и убедитесь что все тэги закрыты и всё стоит по своим местам.
3. Оптимизируйте Javascript код в вашем приложении/игре. Если у вас всё завязано на нём, тогда его оптимизация даст вам хороший прирост производительности. Вы можете найти в интернете статьи ою этом. Пока предлагаю только на английском ( раз и два ). Найдёте хорошие на русском — в комменты!
4. Попытаемся на нативном уровне Андроида что-нибудь придумать:
4.1. Там где вы объявляете Webview можно добавить
Сами Андроид Девелоперы первый параметр не считают очень успешным появился и кажется действует только в API 19 (Могу ошибаться).
4.2. В манифест в ваше активити можно добавить опцию:
Эта опция призвана делать добро оптимизиции и хардверно ускорять работу что должно плавно сказываться на анимации. Должно. На самом деле этот параметр очень неоднозначен у некоторых он даёт прирост производительности, а у некоторых наоборот всё портит. С техничекого плана данная опция принудительно впускает в процесс обработки всего что происходит на экране мощи видеокарты. Не всегда удаётся как хочется. Именно поэтому нашлись умники, которые копнули это поглубже и как оказалось GPU акселлерация не способна улучшить CSS/JS, поэтому в файл с основной Активити добавляют:
if (Build.VERSION.SDK_INT >= 11) <
webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
>
Он вроде как бы отключает на самом WebView акселлерацию и говорят конечной производительность идёт в плюс.
Некоторые предлагают использовать:
Но по сути этот та же акселлерация. От которой как мы уже поняли в WebView лучше избавиться.
4.3. Попробуйте добавить следующий CSS-код слоям, спискам и пр, что участвует в анимации:
-webkit-transform: translate3d(0,0,0);
-webkit-backface-visibility: hidden;
-webkit-perspective: 1000;
-webkit-transform-style: flat;
Некоторым это помогает сделать анимацию более гладкой. В основном бывает достаточно использовать:
transform: translate3d(0,0,0);
-webkit-transform: translate3d(0,0,0);
Уверенно включит 3D акселерацию следующий код:
-webkit-transform: translate3d(0,0,0);
-webkit-transform: tranlsateZ(0);
-webkit-transform: scale3d(1,1,1);
-webkit-transform: scale3dZ(1);
Но самое главное не злоупотребите этим. Как оно помогает так оно и может навредить. Добавляйте это свойство только в элементы, которые анимируются.
4.4. Если у вас многое завязано на плавности скролла, то некоторые предлагают использовать вместо стандартного класса WebView этот:
import android.content.Context;
import android.view.MotionEvent;
import android.webkit.WebView;
public class MyWebView extends WebView<
public MyWebView(Context context) <
super(context);
// TODO Auto-generated constructor stub
>
private long lastMoveEventTime = -1;
private int eventTimeInterval = 40;
@Override
public boolean onTouchEvent(MotionEvent ev) <
long eventTime = ev.getEventTime();
int action = ev.getAction();
switch (action) <
case MotionEvent.ACTION_MOVE: <
if ((eventTime — lastMoveEventTime) > eventTimeInterval) <
lastMoveEventTime = eventTime;
return super.onTouchEvent(ev);
>
break;
>
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP: <
return super.onTouchEvent(ev);
>
>
return true;
>
>
Код рассчитан на заимодействие одним пальцем, для двух и больше (мультитач) придётся немного допилить.
5. Не используйте ни в коем случае событие onclick на странице, поскольку это даёт тормоза длинной порядка 300ms. А это разве есть хорошо?
Вместо этого используйте ontouchstart (на элемент нажали, выполняется событие,палец убрали), а если нужно чтобы был именно клик по элементу (на элемент нажали, палец убрали, выполняется событие) тогда напишите по быстрому комбо-обработчик ontouchstart+ontouchend.
6. Не используйте большое DOM древо в коде. Оптимально будет если глубина вложений не будет длиннее 3. Например body > div > ul > li (body естественно не считается в этом числе).
7. Люди советуют в построении HTML страницы приложения и игры использовать там где возможно абсолютные позиции, а также пиксели вместо процентов. Это каким-то образом напрямую связано с обработкой контента CPU и GPU.
8. Могут появляться тормоза если вы не отключили стандартное действие на touch событие. При чём на девайсах от Samsung может вообще останавливаться вся анимация на странице после свайпа или длительного удержания.
Чтобы отключить это, используйте jQuery (можно маленькую min библиотеку) в которых есть event.preventDefault() и event.stopPropagation() которые как раз и предотвращают стандартные обработки событий. Вместо них советовали использовать return false, но что-то не удалось. Итак, вот что нужно добавить в JS код вашего приложения или игры:
document.addEventListener(‘touchstart’, function(event) <
event.preventDefault();
event.stopPropagation();
/* Здесь ваш код обработки события*/
>, false);
document.addEventListener(‘touchmove’, function(event) <
event.preventDefault();
event.stopPropagation();
/* Здесь ваш код обработки события*/
>, false);
document.addEventListener(‘touchend’, function(event) <
event.preventDefault();
event.stopPropagation();
/* Здесь ваш код обработки события*/
>, false);
9. Старайтесь не использовать большие изображения подгоняя их потом под все размеры. Сделайте лучше для каждого разрешения свой размер. Для этого можно воспользоваться CSS Media Queries. Помните что
На этом пожалуй всё. Если у вас есть чем дополнить статью — пишите в комментарии. Если вы согласны со способом (или он вам помог) описанным в коментариях — голосуйте.
Источник