何时加载home page
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;
}
HomeProvider
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;
}
}
pipes[0]即为shouldInterceptRequest中的ins。
WebResourceResponse
先来看WebResourceResponse。
WebResourceResponse位于framework中,它继承了StreamLoader ,具体就不在分析了,在这里它的作用就是把文件作为一个流读出来模拟HTTP协议。
RequestHandler
数据是由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);
}
writeTemplatedIndex()中首先从database中读取数据,
Template t = Template.getCachedTemplate(mContext, R.raw.most_visited);
是从文件中读出HTML文件并进行解析writeValue则将从数据库中读出的数据加入解析后的数据中。
最后t.write(mOutput)则将数据写入pipes[1]中。