Tab.java中实现了WebViewClient的shouldInterceptRequest接口,该函数为回调函数,最终由native代码调用。调用过程为
shouldInterceptRequest() CallbackProxy.java <- shouldInterceptRequest() BrowserFrame.java <- shouldInterceptRequest() WebCoreFrameBridge.cpp
Tab.java
public WebResourceResponse shouldInterceptRequest(WebView view, String url) { WebResourceResponse res = HomeProvider.shouldInterceptRequest( mContext, url); return res; }
home page中的数据是从数据库中读取的,HomeProvider提供了数据。
HomeProvider.java
public static WebResourceResponse shouldInterceptRequest(Context context, String url) { try { boolean useMostVisited = BrowserSettings.getInstance().useMostVisitedHomepage(); if (useMostVisited && url.startsWith("content://")) { Uri uri = Uri.parse(url); if (AUTHORITY.equals(uri.getAuthority())) { InputStream ins = context.getContentResolver() .openInputStream(uri); return new WebResourceResponse("text/html", "utf-8", ins); } } } catch (Exception e) {} return null; }本文只分析当主页为Most Visited时的实现。
public ParcelFileDescriptor openFile(Uri uri, String mode) { try { ParcelFileDescriptor[] pipes = ParcelFileDescriptor.createPipe(); final ParcelFileDescriptor write = pipes[1]; AssetFileDescriptor afd = new AssetFileDescriptor(write, 0, -1); new RequestHandler(getContext(), uri, afd.createOutputStream()).start(); return pipes[0]; } catch (IOException e) { Log.e(TAG, "Failed to handle request: " + uri, e); return null; } }
先来看WebResourceResponse。
WebResourceResponse位于framework中,它继承了StreamLoader ,具体就不在分析了,在这里它的作用就是把文件作为一个流读出来模拟HTTP协议。
数据是由RequestHandler写入HomeProvider读出的。
public class RequestHandler extends Thread { private static final String TAG = "RequestHandler"; private static final int INDEX = 1; private static final int RESOURCE = 2; private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); Uri mUri; Context mContext; OutputStream mOutput; static { sUriMatcher.addURI(HomeProvider.AUTHORITY, "/", INDEX); sUriMatcher.addURI(HomeProvider.AUTHORITY, "res/*/*", RESOURCE); } public RequestHandler(Context context, Uri uri, OutputStream out) { mUri = uri; mContext = context.getApplicationContext(); mOutput = out; } @Override public void run() { super.run(); try { doHandleRequest(); } catch (Exception e) { Log.e(TAG, "Failed to handle request: " + mUri, e); } finally { cleanup(); } } void doHandleRequest() throws IOException { int match = sUriMatcher.match(mUri); switch (match) { case INDEX: writeTemplatedIndex(); break; case RESOURCE: writeResource(getUriResourcePath()); break; } }
访问主页时执行writeTemplatedIndex()
void writeTemplatedIndex() throws IOException { Template t = Template.getCachedTemplate(mContext, R.raw.most_visited); Cursor cursor = mContext.getContentResolver().query(Browser.BOOKMARKS_URI, new String[] { "DISTINCT url", "title", "thumbnail" }, "(visits > 0 OR bookmark = 1) AND url NOT LIKE 'content:%' AND thumbnail IS NOT NULL", null, "visits DESC LIMIT 12"); t.assignLoop("most_visited", new Template.CursorListEntityWrapper(cursor) { @Override public void writeValue(OutputStream stream, String key) throws IOException { Cursor cursor = getCursor(); if (key.equals("url")) { stream.write(htmlEncode(cursor.getString(0))); } else if (key.equals("title")) { stream.write(htmlEncode(cursor.getString(1))); } else if (key.equals("thumbnail")) { stream.write("data:image/png;base64,".getBytes()); byte[] thumb = cursor.getBlob(2); stream.write(Base64.encode(thumb, Base64.DEFAULT)); } } }); t.write(mOutput); }
Template t = Template.getCachedTemplate(mContext, R.raw.most_visited);
最后t.write(mOutput)则将数据写入pipes[1]中。