I tried sirFunkenstine solution that works fine. Only the client for whom I am creating this application did not like the performance. And I had to admit that it was not so smooth.
It seemed that adding and removing preinstalled webviews was where the problem is. The user interface was frozen for a split second each time the application added / removed a new WebView for the next line.
Decision
So I thought it would be better to adjust the content and height of the WebView instead of adding / removing. Thus, we only have the number of WebViews that are currently visible in memory. And we can use ListView / Adapter reuse functions.
So, I added a single WebView behind the ListView, which constantly calculates the height of the WebView for the following items. You can get the height using the WebView method getContentHeight. You will need to do this in the onPageFinished method so that you have the final height. This caused another problem, so the method returns zero when the content is loaded using the loadDataWithBaseURL or loadData methods. It seems that the value is being set in the end, but not at the time that onPageFinished is called. To overcome this, you can add a thread that constantly checks to see if getContentHeight has lost more than zero. If it is not equal to zero, the value is set and you can load the next one.
This whole solution is a bit hacky, but it gave me a nice and smooth ListView, including WebViews with different heights.
Code example:
1: The queue at the position of the lines you want to preload:
private SparseArray<Integer> mWebViewHeights = new SparseArray<Integer>(); private LinkedBlockingQueue mQueue; { mQueue = new LinkedBlockingQueue(); try { mQueue.put(position); } catch (InterruptedException e) { e.printStackTrace(); } }
2: Run Runnable to constantly load new items from the queue and check / add height to the array:
Handler h; Runnable rowHeightCalculator = new Runnable() { h = new Handler(); rowHeightCalculator.run(); }
3: Download the new HTML content and check the height:
Handler h; Runnable rowHeightCalculator = new Runnable() { int mCurrentIndex = -1; boolean mLoading = false; // Read the webview height this way, cause oncomplete only returns 0 for local HTML data @Override public void run() { if(Thread.interrupted()) return; if (mCurrentIndex == -1 && mQueue.size() > 0) { try { mCurrentIndex = (Integer)mQueue.take(); String html = mItems.get(mCurrentIndex).getPart().getText(); mDummyWebView.clearView(); mDummyWebView.loadDataWithBaseURL("file:///android_asset/reader/", "THE HTML HERE", "text/html", "UTF-8", null); mLoading = true; } } catch (InterruptedException e) { e.printStackTrace(); } } if(mDummyWebView.getContentHeight() != 0 && mCurrentIndex >= 0) { int contentHeight = mDummyWebView.getContentHeight(); mWebViewHeights.append(mCurrentIndex, contentHeight); mCurrentIndex = -1; mLoading = false; } // Reload view if we loaded 20 items if ((mQueue.size() == 0 && (mItemsCount - mQueue.size()) < 20) || (mItemsCount - mQueue.size()) == 20) { notifyDataSetChanged(); } if (mQueue.size() > 0 || mLoading) { h.postDelayed(this, 1); } } };