I have almost 30 webview in a Tablayout. Everything works fine but my app consumes a lot of memory and will just close because of memory issue. This is what I get in log
04-05 21:00:09.458 19720-19801/com.example.choman.webview A/chromium: [FATAL:memory.cc(19)] Out of memory. size=16777216
This is my java file. Basically all the remaining 29 fragments contain the same code with just a change in the url. I am not sure how to handle this.
public class stackOverflow extends Fragment {
private WebView webView;
private ProgressBar progressBar1;
private SwipeRefreshLayout mSwipeRefreshLayout1;
public stackOverflow() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_tab1, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
progressBar1 = (ProgressBar) view.findViewById(R.id.progressBar1);
webView = (WebView) view.findViewById(R.id.website_detail_1);
webView.setWebViewClient(new MyAppWebViewClient());
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDomStorageEnabled(true);
webView.loadUrl("http://www.stackoverflow.com");
WebSettings webSettings = webView.getSettings();
webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
webView.getSettings().setAppCacheEnabled(true);
webSettings.setDomStorageEnabled(true);
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
mSwipeRefreshLayout1 = (SwipeRefreshLayout) view.findViewById(R.id.swipe1);
mSwipeRefreshLayout1.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
webView.loadUrl("http://www.stackoverflow.com");
}
});
if (mSwipeRefreshLayout1.isRefreshing()) {
mSwipeRefreshLayout1.setRefreshing(false);
}
webView.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
webView.goBack();
return true;
}
return false;
}
});
}
public class MyAppWebViewClient extends WebViewClient {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
//view.findViewById(R.id.progressBar1).setVisibility(View.GONE);
Log.i("pageFinished", "yesss");
//progressBar.setVisibility(View.INVISIBLE);
progressBar1.setVisibility(View.GONE);
if (mSwipeRefreshLayout1.isRefreshing()) {
mSwipeRefreshLayout1.setRefreshing(false);
}
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
}
Mainactivity
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
public WebView view;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.addTab(tabLayout.newTab().setText("WebView1").setTag("WebView1"));
//all the way down to .....
tabLayout.addTab(tabLayout.newTab().setText("WebView30").setTag("WebView30"));
final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
viewPager.setOffscreenPageLimit(6);
final PagerAdapter adapter = new TabPagerAdapter(getSupportFragmentManager(), tabLayout
.getTabCount());
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(
tabLayout));
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
// int id = item.getItemId();
// //noinspection SimplifiableIfStatement
// if (id == R.id.action_settings) {
// return true;
// }
return super.onOptionsItemSelected(item);
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.WebView1) {
viewPager.setCurrentItem(0);
//all the way down to..30
if (id == R.id.WebView30) {
viewPager.setCurrentItem(30);
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
}
This is the code for TabPagerAdapter
public class TabPagerAdapter extends FragmentStatePagerAdapter
{
int tabCount;
public TabPagerAdapter(FragmentManager fm, int numberOfTabs)
{
super(fm);
this.tabCount = numberOfTabs;
}
@Override
public Fragment getItem(int position)
{
switch (position)
{
case 0:
//
WebViewFragment1 tab1 = new WebViewFragment1();
return tab1;
//all the way to tab 29
webViewFragment30 tab30 = new WebViewFragment30();
return tab30
default:
return null;
}
}
@Override
public int getCount()
{
return tabCount;
}
}
Use ViewPager
. ViewPager
will hold maximum 3 fragments in memory at any time(without changing the default offscreen page limit). The 3 fragments are the current visible fragment, left and right side fragments to the current fragment.
If you want tabs, you could create a custom View which looks like the system Tabs and add it above the ViewPager. Use PageTransformer
with ViewPager
to track the ViewPager
swipe and scroll the custom Tab accordingly. Then listen to the clicks of Tabs and scroll the ViewPager
based on the Tab pressed.
Update:
I totally forgot that we could attach a TabLayout
with a ViewPager
instead of creating custom Tabs.
tabLayout.setUpWithViewPager(viewpager)
will work.
Thanks to @choman
viewPager.setOffscreenPageLimit(6);
This line is causing the issue. This line tells the view pager to keep (6+6+1 = 13) pages in memory which should be costly in your case since each page has 6.5 Mb of contents. You need to change it to viewPager.setOffscreenPageLimit(1)
to fix the OutOfMemory issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With