浏览器探究——下载

当前我的机器还是无网络状态,以下讨论可能有错误

长按一个链接,会调用到BrowserActivity.onContextItemSelected,进而调用Controller. onContextItemSelected。在处理该菜单项时,会调用当前WebView的requestFocusNodeHref。

/**

* Request the anchor orimage element URL at the last tapped point.

* If hrefMsg is null,this method returns immediately and does not

* dispatch hrefMsg to itstarget. If the tapped point hits an image,

* an anchor, or an imagein an anchor, the message associates

* strings in named keysin its data. The value paired with the key

* may be an empty string.

*

* @param hrefMsg Thismessage will be dispatched with the result of the

* request. The message datacontains three keys:

* - "url" returns theanchor's href attribute.

* - "title" returns theanchor's text.

* - "src" returns theimage's src attribute.

*/

这里有个要注意的,Controller运行在主线程中,并且Controller有个Handler。现在Controller想去WebViewCoreThread线程中获取一些数据,它是怎么做的呢?首先在Controller处利用Controller的Handler创建一个Message,然后把这个Message(假定为Message1)作为一个数据参数,向WebViewCore发送Message(假定为Message2),即Message1是Message2的一个数据参数。WebViewCore自然可以接收到Message2并处理他,把处理后的数据放入到Message1中,然后发送出去,由于Message1是利用Controller的Handler创建的,自然Controller的Handler会在主线程中接收到这个Message1,然后就可以从Message1中获取到他最初所期望获取的数据了。

看下实际的情况,Controller在调用WebView.requestFocusNodeHref之前就利用自己的Handler创建了一个Message(Message1),该参数的what值为FOCUS_NODE_HREF并设置了一些参数信息,这个Message作为WebView.requestFocusNodeHref的参数。

WebView.requestFocusNodeHref会计算当前按下的坐标位置,然后将这些信息作为参数发送REQUEST_CURSOR_HREF消息给WebViewCoreThread线程,当然刚刚创建的Message(Message1)也作为一个参数。WebViewCoreThread线程通过三个JNI函数nativeRetrieveHref,nativeRetrieveAnchorText,nativeRetrieveImageSource获取到坐标所指向的链接的url,title,src,这个所谓的src应该是个图标吧。然后把这些信息存入Message1中再返还给主线程。

此时主线程接收到回传的Message1,Controller的Handler被调用并处理FOCUS_NODE_HREF消息。这个流程很有用,不仅仅保存链接使用了这个流程,还有些其他的涉及到获取链接的功能也走这个流程,比如拷贝链接。

在接收到消息和解出数据后,调用DownloadHandler.onDownloadStartNoStream这个静态函数。

/**

* Notify the host application a download should be done, even if there

* is a streaming viewer available for thise type.

* @param activity Activity requesting the download.

* @param url The full url to the content that should be downloaded

* @param userAgent User agent of the downloading application.

* @param contentDisposition Content-disposition http header, if present.

* @param mimetype The mimetype of the content reported by the server

* @param privateBrowsing If the request is coming from a privatebrowsing tab.

*/

这个函数是个重要的函数,负责下载资源的处理。

该函数主要做以下处理:

1.通过url等信息获取文件名。

2.判断SD卡是否存在。

3.如果当前不知道mimeType则进行获取。

4.利用DownloadManager.Request和DownloadManager进行资源的下载。

5.显示通知信息。

这里主要看下1和3项。

其中2项采用标准判断SD卡方式,如果不存在SD卡则提示用户,并直接返回不进行下载。

4项采用DownloadManager标准的设置参数和开始下载的方式。此处需要注意的是这里会开启一个新线程来执行DownloadManager.enqueue操作。

5项目只是简单的使用Toast显示了下载通知。

1项通过静态函数URLUtil.guessFileName获取文件名

/**

* Guesses canonical filename that a download would have, using

* the URL and contentDisposition. File extension, if not defined,

* is added based on the mimetype

* @param url Url to the content

* @param contentDisposition Content-Disposition HTTP header or null

* @param mimeType Mime-type of the content or null

*

* @return suggested filename

*/

该函数通过一些分析规则和匹配规则来从url,contentDisposition,mimeType中获取到一个文件名。

3项当当前的mimeType为null是会通过FetchUrlMimeType类来获取资源实际的mimeType。

FetchUrlMimeType

/**

*This class is used to pull down the http headers of a given URL so that

* wecan analyse the mimetype and make any correction needed before we give

*the URL to the download manager.

*This operation is needed when the user long-clicks on a link or image and

* wedon't know the mimetype. If the user just clicks on the link, we will

* dothe same steps of correcting the mimetype down in

*android.os.webkit.LoadListener rather than handling it here.

*

*/

class FetchUrlMimeType extends Thread

可见FetchUrlMimeType是一个线程类,会在一个单独的线程中执行他的处理操作。这个类的处理其实就是发送一个http请求给这个资源,通过http response的头信息来获取资源实际的mimeType。http请求的处理是通过AndroidHttpClient类,HttpHost类,HttpHead类,ConnRouteParams类,HttpResponse类,Header类,这些类完成的,以上都是net或apache-http模块提供的。

如果成功的获取到实际的mimeType,会再次调用URLUtil.guessFileName获取一个文件名。

以上内容做完后,再使用DownloadManager进行下载的操作,注意这里不需要再创建一个新线程执行DownloadManager.enqueue了,因为FetchUrlMimeType本身就是个线程类,现在已经是在一个单独的线程中了。

更多相关文章

  1. C语言函数的递归(上)
  2. Android题目笔记(二)
  3. 线程和线程池
  4. Service Manager进程从睡眠中被唤醒,返回BR_TRANSACTION,执行真正
  5. android 源码分析
  6. Flutter Row、Column 参数详解
  7. Android(安卓)IntentService使用全面介绍及源码解析
  8. 有关String类的笔试常考题
  9. Android(安卓)重读官方文档 4 SharedPreferences

随机推荐

  1. Android(安卓)IO流使用详解-SDcard
  2. android(基于回调)的事件处理
  3. Android工程师成长路线全攻略
  4. Android(安卓)调用系统相机以及相册源码
  5. cocos2d-x C++通知Android更新UI
  6. 一个Android开发者自学Python的心路历程
  7. 在Android(安卓)JNI环境下使用C++ Lambda
  8. Android日志系统Logcat源代码简要分析
  9. Android(安卓)自定义AlertDialog提交表单
  10. Android开发中Handler的经典总结