Android爬坑之旅之WebView

不知不觉,Hybird App已经成了目前比较主流的一种开发方式。

对于用户体验要求较高或者与硬件交互较多的功能我们一般都会采用Native原生的方式来实现。 而用户交互少,偏展示类,活动类的功能我们则通常采用H5的方式来实现, 例如新闻类的app,详情展示页一般就是H5的页面

  • 一方面图文排版上web有着先天的优势,同时纯展示类的页面在目前的移动设备上,性能体验已经很难让用户分辨是网页还是原生了;
  • 另一方面,H5的页面跨平台,方便在原生客户端上实现分享功能,拥有较强的传播性,我们平时常见的活动页面也拥有这样的优势,所以你看到的活动页面也基本都是H5,只需轻轻一点就能分享到各个平台;
  • 同时,H5的页面开发降低了开发成本,一套代码,web,android,ios都能访问。(然而实际开发过程中,H5的适配也都是各种泪)

既然Hybird App有这么多优势,那在Android中我们通过什么样的方式在原生项目中嵌入H5页面呢?

那就不得不提到我们的WebVew了,作为官方唯一用来显示web的组件, 展示网页这样的任务也只能交给它了。

A View that displays web pages. This class is the basis upon which you can roll your own web browser or simply display some online content within your Activity. It uses the WebKit rendering engine to display web pages and includes methods to navigate forward and backward through a history, zoom in and out, perform text searches and more.

引用官方文档的一句话: WebView是一个用来在Activity中显示我们网页的视图组件,它通过webkit渲染引擎渲染和显示我们的web页面,并且包含了web的历史导航操法,页面放大缩小,文本搜索等方法。

我们首先来看一下WebView的基本用法:

#WebView的基本用法


关于WebView的基本用法,大部分人也是轻车熟路, 本来也是写了一部分,无意中发现有位博主的博客对WebView的介绍实在太过详细,像我这样的懒人,有更好的文章是不会自己去写的, 所以删了自己写的,将大牛博主的博客分享出来,感兴趣同学的可以一起看一看:

Android WebView 开发详解(一)  Android WebView 开发详解(二) Android WebView 开发详解(三)

了解完WebView的基本用法,那就来总结下最近项目中遇到的关于WebView的坑

#项目中使用WebView遇到的问题


###WebView界面的原生标题设置

如图所示, 一般情况下,我们WebView所在界面由顶部带标题的原生导航栏WebView的内容部分组成, 而WebView中的界面可能在点击后还会再跳其他Web页面(如图点击请假会在当前WebView跳转请假的Web页面)。

由于点击内容的不确定性,所以通常情况下,最简单的做法就是捕获h5页面的 标签来进行标题设置。

对于捕获 </a> 标签内容的方式,WebView也很好地提供了支持,我们可以通过继承WebChromeClient的onReceivedTitle来进行获取:</p> <pre><code lang="bash" class="hljs bash"> private class WebViewChromeClient extends WebChromeClient { @Override public void onReceivedTitle(WebView view, String title) { super.onReceivedTitle(view, title); mTitleText.setTitle(String.valueOf(view.getTitle())); } } </code></pre><p>然而这样的方式在实际使用中有一个问题:</p> <p>当通过 <a href="https://developer.android.google.cn/reference/android/webkit/WebView.html#goBack()" target="_blank">webView.goBack()</a> 方式返回上一级Web页面的时候不会触发这个方法,因此会导致标题无法跟随历史记录返回上一级页面。</p> <p>所以在项目中, 我们可以通过重写 <a href="https://developer.android.google.cn/reference/android/webkit/WebViewClient.html" target="_blank">WebViewClient</a> 的 [onPageFinished](https://developer.android.google.cn/reference/android/webkit/WebViewClient.html#onPageFinished(android.webkit.WebView, java.lang.String)) 方法,在 [onPageFinished](https://developer.android.google.cn/reference/android/webkit/WebViewClient.html#onPageFinished(android.webkit.WebView, java.lang.String)) 中对界面标题进行设置。 因为不管是历史记录的返回还是点击跳转都会触发页面加载, 当页面加载完成时(不包括js动态创建以及img图片加载完毕)都会触发 [onPageFinished](https://developer.android.google.cn/reference/android/webkit/WebViewClient.html#onPageFinished(android.webkit.WebView, java.lang.String)) 这个方法, 此时我们去获取 <a href="" target="_blank"><title></a> 的标题内容不会有任何问题,可以确保在页面返回时能够获取到正确的标题。</p> <pre><code lang="bash" class="hljs bash"> mWebView.setWebViewClient(new <span class="hljs-function"><span class="hljs-title">WebViewClient</span></span>(){ //Web页面每次加载并完成时会触发该方法 @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); mToolbar.setTitle(String.valueOf(view.getTitle())); Log.i (LOG_TAG, <span class="hljs-string">"onPageFinished"</span>); } }); </code></pre><p><strong>注: 这种做法有一个缺陷,就是返回上一个界面的时候,等页面加载完成的时候标题才会显示出来,为了更好地优化,我们可以创建一个集合用来保存我们的标题,加载url的时候把标题添加进集合,当返回上一级页面的时候,从集合中取出标题进行显示,同时从集合中移除标题。</strong></p> <hr> <p>###WebView中的Web页面存在<input type='file'>标签时无法打开文件选择器</p> <p>在我们的手机浏览器中,当web页面中有 <a href="" target="_blank"><input type='file'></a> 按钮标签的时候点击会自动打开系统的文件选择器, 然而这个功能在主流系统的WebView中没有被默认实现, 因此,为了让 <a href="" target="_blank"><input type='file'></a> 点击时能够打开系统的文件选择器, 我们必须通过重写 <a href="https://developer.android.google.cn/reference/android/webkit/WebChromeClient.html" target="_blank">WebChromeClient</a> 来实现点击<a href="" target="_blank"><input type='file'></a> 打开系统文件选择器。 代码如下:</p> <pre><code lang="bash" class="hljs bash">public class MainActivity extends AppCompatActivity { /** Android 5.0以下版本的文件选择回调 */ protected ValueCallback<Uri> mFileUploadCallbackFirst; /** Android 5.0及以上版本的文件选择回调 */ protected ValueCallback<Uri[]> mFileUploadCallbackSecond; protected static final int REQUEST_CODE_FILE_PICKER = 51426; protected String mUploadableFileTypes = <span class="hljs-string">"image/*"</span>; private WebView mWebView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); <span class="hljs-built_in">set</span>ContentView(R.layout.activity_main); initWebView(); } private void <span class="hljs-function"><span class="hljs-title">initWebView</span></span>() { mWebView = (WebView) findViewById(R.id.my_webview); mWebView.loadUrl(<span class="hljs-string">"file:///android_asset/index.html"</span>); mWebView.setWebChromeClient(new OpenFileChromeClient()); } private class OpenFileChromeClient extends WebChromeClient { // Android 2.2 (API level 8)到Android 2.3 (API level 10)版本选择文件时会触发该隐藏方法 @SuppressWarnings(<span class="hljs-string">"unused"</span>) public void openFileChooser(ValueCallback<Uri> uploadMsg) { openFileChooser(uploadMsg, null); } // Android 3.0 (API level 11)到 Android 4.0 (API level 15))版本选择文件时会触发,该方法为隐藏方法 public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) { openFileChooser(uploadMsg, acceptType, null); } // Android 4.1 (API level 16) -- Android 4.3 (API level 18)版本选择文件时会触发,该方法为隐藏方法 @SuppressWarnings(<span class="hljs-string">"unused"</span>) public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) { openFileInput(uploadMsg, null, <span class="hljs-literal">false</span>); } // Android 5.0 (API level 21)以上版本会触发该方法,该方法为公开方法 @SuppressWarnings(<span class="hljs-string">"all"</span>) public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { <span class="hljs-keyword">if</span> (Build.VERSION.SDK_INT >= 21) { final boolean allowMultiple = fileChooserParams.getMode() == FileChooserParams.MODE_OPEN_MULTIPLE;//是否支持多选 openFileInput(null, filePathCallback, allowMultiple); <span class="hljs-built_in">return</span> <span class="hljs-literal">true</span>; } <span class="hljs-keyword">else</span> { <span class="hljs-built_in">return</span> <span class="hljs-literal">false</span>; } } } @SuppressLint(<span class="hljs-string">"NewApi"</span>) protected void openFileInput(final ValueCallback<Uri> fileUploadCallbackFirst, final ValueCallback<Uri[]> fileUploadCallbackSecond, final boolean allowMultiple) { //Android 5.0以下版本 <span class="hljs-keyword">if</span> (mFileUploadCallbackFirst != null) { mFileUploadCallbackFirst.onReceiveValue(null); } mFileUploadCallbackFirst = fileUploadCallbackFirst; //Android 5.0及以上版本 <span class="hljs-keyword">if</span> (mFileUploadCallbackSecond != null) { mFileUploadCallbackSecond.onReceiveValue(null); } mFileUploadCallbackSecond = fileUploadCallbackSecond; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); <span class="hljs-keyword">if</span> (allowMultiple) { <span class="hljs-keyword">if</span> (Build.VERSION.SDK_INT >= 18) { i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, <span class="hljs-literal">true</span>); } } i.setType(mUploadableFileTypes); startActivityForResult(Intent.createChooser(i, <span class="hljs-string">"选择文件"</span>), REQUEST_CODE_FILE_PICKER); } public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) { <span class="hljs-keyword">if</span> (requestCode == REQUEST_CODE_FILE_PICKER) { <span class="hljs-keyword">if</span> (resultCode == Activity.RESULT_OK) { <span class="hljs-keyword">if</span> (intent != null) { //Android 5.0以下版本 <span class="hljs-keyword">if</span> (mFileUploadCallbackFirst != null) { mFileUploadCallbackFirst.onReceiveValue(intent.getData()); mFileUploadCallbackFirst = null; } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (mFileUploadCallbackSecond != null) {//Android 5.0及以上版本 Uri[] dataUris = null; try { <span class="hljs-keyword">if</span> (intent.getDataString() != null) { dataUris = new Uri[] { Uri.parse(intent.getDataString()) }; } <span class="hljs-keyword">else</span> { <span class="hljs-keyword">if</span> (Build.VERSION.SDK_INT >= 16) { <span class="hljs-keyword">if</span> (intent.getClipData() != null) { final int numSelectedFiles = intent.getClipData().getItemCount(); dataUris = new Uri[numSelectedFiles]; <span class="hljs-keyword">for</span> (int i = 0; i < numSelectedFiles; i++) { dataUris[i] = intent.getClipData().getItemAt(i).getUri(); } } } } } catch (Exception ignored) { } mFileUploadCallbackSecond.onReceiveValue(dataUris); mFileUploadCallbackSecond = null; } } } <span class="hljs-keyword">else</span> { //这里mFileUploadCallbackFirst跟mFileUploadCallbackSecond在不同系统版本下分别持有了 //WebView对象,在用户取消文件选择器的情况下,需给onReceiveValue传null返回值 //否则WebView在未收到返回值的情况下,无法进行任何操作,文件选择器会失效 <span class="hljs-keyword">if</span> (mFileUploadCallbackFirst != null) { mFileUploadCallbackFirst.onReceiveValue(null); mFileUploadCallbackFirst = null; } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (mFileUploadCallbackSecond != null) { mFileUploadCallbackSecond.onReceiveValue(null); mFileUploadCallbackSecond = null; } } } } } </code></pre><p><strong>注:当用户点击input file弹出文件选择器后,点击取消或者返回按钮没有执行选择时,必须在onActivityResult里给valueCallback的onReceiveValue传null,因为valueCallback持有的是WebView,在onReceiveValue没有回传值的情况下,WebView无法进行下一步操作,会导致取消选择文件后,点击input file不会再响应:</strong></p> <pre><code lang="bash" class="hljs bash"> <span class="hljs-keyword">if</span> (mFileUploadCallbackFirst != null) { mFileUploadCallbackFirst.onReceiveValue(null); mFileUploadCallbackFirst = null; } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (mFileUploadCallbackSecond != null) { mFileUploadCallbackSecond.onReceiveValue(null); mFileUploadCallbackSecond = null; } </code></pre><p>示例demo地址: https://github.com/cjpx00008/FileChooser4WebViewDemo</p> <hr> <p>###WebView中的web页面调用系统选择器或者相机导致app进入后台被系统释放</p> <p>众所周知,WebView基于webkit内核来渲染web页面,因此使用起来相当于一个小型浏览器,即使页面内容不复杂,只要使用WebView也会占用大量的内存。</p> <p>而Android的内存回收机制,在系统内存不足的情况下会优先释放内存占用较大的app从而回收内存资源,此时正在使用WebView的运行在后台的app肯定是首当其冲被回收的。</p> <p>因此,当WebView通过input file调用系统文件选择器,或者通过文件选择器调用了相机时,我们的app就进入了后台,在部分低端Android设备(尤其红米这类手机,默认的神隐模式会在app进入后台的时候较大概率的释放app)或者系统内存资源不足的情况下,我们的app就会优先被释放掉,导致文件选择完毕后,回到上一界面时,app的界面重新走了onCreate,web页面也因此重建了。</p> <p>对于部分需要填写大量表单的web页面来说,用户填写的数据会随着界面的销毁重建而丢失,而选择的文件也因为页面的重建而无法回传给input file,这对于用户的体验来说肯定是不友好的。</p> <p>也许你会说,重写onSaveInstance保存数据就是啦。 这也是我一开始考虑的, 我们的WebView也提供了 <a href="https://developer.android.google.cn/reference/android/webkit/WebView.html#saveState(android.os.Bundle)" target="_blank">saveState</a> 以及 <a href="https://developer.android.google.cn/reference/android/webkit/WebView.html#restoreState(android.os.Bundle)" target="_blank">restoreState</a> 来保存状态。</p> <p>然而悲催的是,这两个方法并不会保存web页面内的数据,它只保存了WebView加载的页面,前进后退的历史状态等数据。</p> <p>引用官方文档的描述:</p> <blockquote> <p>Saves the state of this WebView used in <a href="https://developer.android.google.cn/reference/android/app/Activity.html#onSaveInstanceState(android.os.Bundle)" target="_blank">onSaveInstanceState(Bundle)</a> . Please note that this method no longer stores the display data for this WebView. The previous behavior could potentially leak files if <a href="https://developer.android.google.cn/reference/android/webkit/WebView.html#restoreState(android.os.Bundle)" target="_blank">restoreState(Bundle)</a>  was never called.</p> </blockquote> <p><strong>Please note that this method no longer stores the display data for this WebView</strong></p> <p>WebView的saveState并不会保存界面的数据。</p> <p>所以,对于表单数据的恢复,我们只能自己想办法了,我们这里采用了两套方案:</p> <ol> <li>通过WebView与JS交互,在onSaveInstance的时候触发界面保存数据,保存数据的方式也大体分为两种, 一种使用H5自带的localStorage来进行数据存储,页面销毁重建的时候H5页面判断本地localStorage数据是否有值,有就将值重新填充到页面表单,提交数据后清除本地localStorage的数据。 这种方式需要给WebView开启对localStorage的支持。</li> </ol> <pre><code lang="bash" class="hljs bash">WebSettings settings = mWebView.getSettings(); settings.setDomStorageEnabled(<span class="hljs-literal">true</span>); </code></pre><p>另一种则提供JS接口将数据传递给原生,通过原生代码将数据保存到本地,在页面重建渲染完成时,web页面通过JS接口调用原生方法拉取数据判断是否有值,有则填充表单,无则不做操作,提交数据后调用JS接口调用原生方法清空本地数据。</p> <ol start="2"> <li>由web端自己处理,在表单页面文本输入失去焦点时自动保存数据,页面销毁重建时,自己拉取数据进行判断。 这种方式对原生的依赖较低,个人更倾向这种方式,当然最终由于项目的特殊情况,我们还是采用了第一种方式。</li> </ol> <p>以上是表单数据的恢复方案,</p> <p>而对于从系统文件选择器选择的文件web页面是无法直接接收并处理了,这里我们提供了一个JS接口在web页面加载完成时,进行触发,并将数据传递给web页面。</p> <p>说到这里,不得不提另外一个问题</p> <hr> <p>###WebView调用服务端页面如何访问本地文件</p> <p>上面我们提到了通过JS接口将选择的文件数据传递给web页面,</p> <p>然而由于安全原因,WebView限制了远程url页面访问本地文件, 如果我们加载的url是服务端的页面,那我们没有任何办法直接通过文件地址来访问客户端本地的文件</p> <p>我们知道,WebView用来加载网页的方式主要有三种:</p> <pre><code lang="bash" class="hljs bash">loadUrl(String url) loadUrl(String url, Map<String, String> additionalHttpHeaders) </code></pre><pre><code lang="bash" class="hljs bash">loadData(String data, String mimeType, String encoding) </code></pre><pre><code lang="bash" class="hljs bash">loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String <span class="hljs-built_in">history</span>Url) </code></pre><p>[loadData()](https://developer.android.google.cn/reference/android/webkit/WebView.html#loadData(java.lang.String, java.lang.String, java.lang.String)) 和 [loadDataWithBaseURL()](https://developer.android.google.cn/reference/android/webkit/WebView.html#loadDataWithBaseURL(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)) 都是直接将数据加载进WebView中,相当于显示的一个本地Web</p> <p>loadUrl也可以通过访问本地的文件地址(例如本地asset目录下的存放了index.html页面,可以通过<code>loadUrl("file:///android_asset/index.html")</code>来显示web页面)</p> <p>对于这样的三种加载本地内容的方式,我们可以使用多种方式来传递路径供web页面传递,这里以图片为例(相册目录下test/IMG_20170105_093405.jpg):</p> <ol> <li>直接通过文件的绝对地址来提供给页面显示:</li> </ol> <pre><code lang="bash" class="hljs bash"><img src = <span class="hljs-string">'file:///storage/emulated/0/dcim/test/IMG_20170105_093405.jpg'</span> /> </code></pre><ol start="2"> <li>通过媒体库查询出来的content uri地址展示</li> </ol> <pre><code lang="bash" class="hljs bash"><img src = <span class="hljs-string">'content://media/external/images/media/102610'</span> /> </code></pre><ol start="3"> <li>通过FileProvider转换的content uri地址展示</li> </ol> <pre><code lang="bash" class="hljs bash"><img src = <span class="hljs-string">'content://com.test.myfileprovider/dcim/test/IMG_20170105_093405.jpg'</span>/> </code></pre><p>可当你使用loadUrl(String url)加载服务端的http地址时,以上三种方法将均无法使用,经过各种尝试,目前找到两种方案来提供给web端进行图片显示:</p> <ol> <li> <p>由原生代码处理,将文件流转换为Base64之后通过JS接口回传给web;</p> </li> <li> <p>重写WebViewClient里的shouldInterceptRequest方法,每当页面发生资源请求的时候就会触发这个方法,我们可以过滤请求,判断请求是否为本地文件,通过拦截请求转换为二进制流回传回去, 示例代码如下:</p> </li> </ol> <pre><code lang="bash" class="hljs bash">mWebView.setWebViewClient(new <span class="hljs-function"><span class="hljs-title">WebViewClient</span></span>(){ @Override public WebResourceResponse shouldInterceptRequest(WebView view, String url) { <span class="hljs-keyword">if</span> (url.startsWith(<span class="hljs-string">"http://"</span>)&&url.endWith(<span class="hljs-string">".jpg"</span>) { <span class="hljs-built_in">return</span> getWebResourceResponse(<span class="hljs-string">"/storage/emulated/0/dcim/trinaic/IMG_20170105_093405.jpg"</span>, <span class="hljs-string">"image/jpeg"</span>, <span class="hljs-string">".jpg"</span>); } <span class="hljs-built_in">return</span> super.shouldInterceptRequest(view, url); } } private WebResourceResponse getWebResourceResponse(String url, String mime, String style) { WebResourceResponse response = null; try { response = new WebResourceResponse(mime, <span class="hljs-string">"UTF-8"</span>, new FileInputStream(new File(url))); } catch (FileNotFoundException e) { e.printStackTrace(); } <span class="hljs-built_in">return</span> response; } </code></pre><hr> <p>###WebView JS注入漏洞</p> <p>要想让原生跟JS进行交互,按照官方提供的方法就得使用addJavaScriptInterface</p> <pre><code lang="bash" class="hljs bash">class JsObject { @JavascriptInterface public String <span class="hljs-function"><span class="hljs-title">toString</span></span>() { <span class="hljs-built_in">return</span> <span class="hljs-string">"injectedObject"</span>; } } webView.addJavascriptInterface(new JsObject(), <span class="hljs-string">"injectedObject"</span>); webView.loadData(<span class="hljs-string">""</span>, <span class="hljs-string">"text/html"</span>, null); webView.loadUrl(<span class="hljs-string">"javascript:alert(injectedObject.toString())"</span>); </code></pre><blockquote> <p>Injects the supplied Java object into this WebView. The object is injected into the JavaScript context of the main frame, using the supplied name. This allows the Java object's methods to be accessed from JavaScript. For applications targeted to API level <a href="https://developer.android.google.cn/reference/android/os/Build.VERSION_CODES.html#JELLY_BEAN_MR1" target="_blank">JELLY_BEAN_MR1</a>  and above, only public methods that are annotated with <a href="https://developer.android.google.cn/reference/android/webkit/JavascriptInterface.html" target="_blank">JavascriptInterface</a>  can be accessed from JavaScript. For applications targeted to API level <a href="https://developer.android.google.cn/reference/android/os/Build.VERSION_CODES.html#JELLY_BEAN" target="_blank">JELLY_BEAN</a>  or below, all public methods (including the inherited ones) can be accessed, see the important security note below for implications.</p> </blockquote> <p>引用官方api的说明,在Android 4.2以下,会有被注入的风险,4.2以上版本可以通过<code>@JavascriptInterface</code>的注解来处理这个问题。 具体的注入方式,我找了篇博客,如果有不清楚的同学可以了解下: <a href="http://blog.csdn.net/leehong2005/article/details/11808557/" target="_blank">Android WebView的Js对象注入漏洞解决方案</a></p> <p>在之前乌云平台报出的漏洞中, android/webkit/webview中默认内置的一个searchBoxJavaBridge_ 接口同时存在远程代码执行漏洞</p> <p>在于android/webkit/AccessibilityInjector.java中,调用了此组件的应用在开启辅助功能选项中第三方服务的安卓系统中会造成远程代码执行漏洞。这两个接口分别是"accessibility" 和"accessibilityTraversal" ,此漏洞原理与searchBoxJavaBridge_接口远程代码执行相似,均为未移除不安全的默认接口,不过此漏洞需要用户启动系统设置中的第三方辅助服务,利用条件较复杂。</p> <p>因此,一般情况下我们通过removeJavaScripteInterface来移除这几个接口</p> <pre><code lang="bash" class="hljs bash"> <span class="hljs-keyword">if</span> (Build.VERSION.SDK_INT < 17) { mAdvanceWebView.removeJavascriptInterface(<span class="hljs-string">"searchBoxJavaBridge_"</span>); mAdvanceWebView.removeJavascriptInterface(<span class="hljs-string">"accessibility"</span>); mAdvanceWebView.removeJavascriptInterface(<span class="hljs-string">"accessibilityTraversal"</span>); } </code></pre><p>除此之外也有通过onJsPrompt的方式来实现WebView原生跟JS交互功能的,github上的开源项目JSBridge就是采用这种方法: https://github.com/lzyzsd/JsBridge</p> <p>之前拜读过大名鼎鼎的cordova的源码,它内部的原生JS交互也是采用onJsPrompt的方式,不过在此基础上做了更强大的封装。</p> <hr> <p>###WebView后台耗电问题</p> <p>当我们的WebView的web页面在解析或者播放视频再或者有js定时器在执行的时, 如果我们把应用退到后台,不做任何处理的情况下,以上的操作还会在后台继续执行,导致WebView在后台持续耗电,因此一般我们会做以下处理</p> <pre><code lang="bash" class="hljs bash"> @Override protected void <span class="hljs-function"><span class="hljs-title">onPause</span></span>() { super.onPause(); mWebView.onPause();//暂停部分可安全处理的操作,如动画,定位,视频播放等 mWebView.pauseTimers();//暂停所有WebView的页面布局、解析以及JavaScript的定时器操作 } @Override protected void <span class="hljs-function"><span class="hljs-title">onResume</span></span>() { super.onResume(); mWebView.onResume(); mWebView.resumeTimers(); } </code></pre><hr> <p>对于WebView的使用,在处理问题的过程中发现一个不错的开源库: https://github.com/delight-im/Android-AdvancedWebView</p> <p>基本上上面我提到的或者没提到的问题它都做了一定的封装处理,并且考虑了一些版本适配的问题,可以直接拿来使用,也可以拿来参考学习。</p> <p>如果你觉得问题还是太多的话也可以考虑使用<a href="http://x5.tencent.com/" target="_blank">腾讯浏览服务</a>,基于QQ浏览器X5内核,适配了Android全部主流平台,可以在所有Android手机上使用Blink的技术能力,具有更好的H5/CSS3支持和性能,目前微信、qq都在使用它。</p> <p>唯一的缺陷就是它不提供打包内核版的SDK,第一次使用时,它会自动到腾讯服务端去下载内核,下载完毕后会弹窗提示用户是否重启app,重启之后就能正常使用x5浏览服务了,如果你不介意这样的用户体验,可以考虑直接使用腾讯浏览服务。</p> <hr> <p>(补充) ###WebView混淆问题</p> <p>如果app打包混淆之后发现提供给web页面的JS接口失效了,记得检查是否添加了JavaScriptInterface的混淆配置:</p> <pre><code lang="bash" class="hljs bash">-keepclassmembers class * { @android.webkit.JavascriptInterface <methods>; } </code></pre><p>###红米WebView内部Web页面的div自身滚动条问题 红米上WebView内部的Web页面的div由于内容高度大于div,产生了基于div的滚动条(WebView滚动条已禁用的情况下),通过设置div的css样式来禁用div滚动条</p> <pre><code lang="bash" class="hljs bash">Html dom元素ID或class:: -webkit-scrollbar {display:none} </code></pre><p>###WebView内部web页面px跟dp的关系 经测试发现,WebView内部web页面的px值会在内部自动转换为dp,且1px=1dp,跟ppi值无关,这点跟原生开发中的1dp = 设备ppi/160 * px换算关系nveou</p> </p> </div> </div> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1290061306619043840"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(Android爬坑之旅之WebView)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1903783717093044224.htm" title="Android端ReactNative环境搭建——上" target="_blank">Android端ReactNative环境搭建——上</a> <span class="text-muted">hzulwy</span> <a class="tag" taget="_blank" href="/search/reactnative/1.htm">reactnative</a><a class="tag" taget="_blank" href="/search/react/1.htm">react</a><a class="tag" taget="_blank" href="/search/native/1.htm">native</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a> <div>前言最近一年,因为公司业务需要,部门引入了rn这门跨段技术来开发业务需求。从去年部门大佬调研rn这个框架到现在已有超过一年的时间了。而我从当时毕业不到1年的小白成长到现在负责维护项目的Android端代码的主力。同时,自己对rn相关的技术有了不少理解。因此,想要分享一些知识点,希望可以帮助到大家。我会以一个专栏的方式述说在这一年当中使用rn开发需求遇到的困难。大家可以借鉴参考下,共同进步!!!使用</div> </li> <li><a href="/article/1903780435507343360.htm" title="React Native 迁移的阵痛" target="_blank">React Native 迁移的阵痛</a> <span class="text-muted">Ethan. L</span> <a class="tag" taget="_blank" href="/search/ReactNative/1.htm">ReactNative</a><a class="tag" taget="_blank" href="/search/%26amp%3B/1.htm">&</a><a class="tag" taget="_blank" href="/search/JS/1.htm">JS</a><a class="tag" taget="_blank" href="/search/react/1.htm">react</a><a class="tag" taget="_blank" href="/search/native/1.htm">native</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/ios/1.htm">ios</a> <div>背景由于我们的移动应用程序已经存在多年,经历了许多开发者的更替,因此变得越来越臃肿和难以维护。此外,我们团队中的Android开发人员一直很短缺,这导致我们在两个平台上的开发进度和质量存在巨大差异。因此,我们决定采用ReactNative技术,将原生工程迁移到该平台上,以提高应用程序的可维护性和整体性能。我在《ReactNative技术选型分析》中,阐述了对现有原生工程集成ReactNative的</div> </li> <li><a href="/article/1903780309283958784.htm" title="Android React Native应用逆向分析初探" target="_blank">Android React Native应用逆向分析初探</a> <span class="text-muted">byc6352</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div>随着移动互联网时代的到来,用户在移动设备上花费的时间越来越多,不仅是因为移动设备方便携带,而且还因为层出不穷的大量应用提供为用户使用,以往在电脑上才能做的事情,现在仅靠一部手机就可以解决了。当前的移动设备厂商很多,但是被广泛使用的主流系统却只有两个,Android和iOS,因此现在大多数应用都会有两个版本,Android版本和iOS版本。然而这两种应用的开发方式却完全不同,移动客户端开发人员不得不</div> </li> <li><a href="/article/1903779801542488064.htm" title="【005安卓开发方案调研】之Flutter+Dart技术开发安卓" target="_blank">【005安卓开发方案调研】之Flutter+Dart技术开发安卓</a> <span class="text-muted">ThinkPet</span> <a class="tag" taget="_blank" href="/search/%E7%A7%BB%E5%8A%A8app%E5%BC%80%E5%8F%91/1.htm">移动app开发</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/flutter/1.htm">flutter</a><a class="tag" taget="_blank" href="/search/dart/1.htm">dart</a><a class="tag" taget="_blank" href="/search/%E8%B7%A8%E5%B9%B3%E5%8F%B0/1.htm">跨平台</a> <div>基于2025年国内移动开发环境现状,结合多份行业分析报告和技术文档,对Flutter+Dart开发安卓应用的技术成熟度和生态适配性分析如下:一、技术成熟度评估1.跨平台能力达到生产级标准Flutter的Skia自渲染引擎和Dart的AOT/JIT双编译模式,实现了90%以上的原生性能表现,在电商、社交、工具类应用中已无明显性能瓶颈。实测数据显示,列表滚动帧率稳定在55-60FPS,与原生开发差距小</div> </li> <li><a href="/article/1903746371584847872.htm" title="ZYNQ学习笔记_GPIO之输入输出" target="_blank">ZYNQ学习笔记_GPIO之输入输出</a> <span class="text-muted">凌星星星星星</span> <a class="tag" taget="_blank" href="/search/ZYNQ%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/1.htm">ZYNQ学习笔记</a><a class="tag" taget="_blank" href="/search/gpio/1.htm">gpio</a><a class="tag" taget="_blank" href="/search/mio/1.htm">mio</a><a class="tag" taget="_blank" href="/search/fpga/1.htm">fpga</a><a class="tag" taget="_blank" href="/search/%E5%B5%8C%E5%85%A5%E5%BC%8F/1.htm">嵌入式</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E7%89%87%E6%9C%BA/1.htm">单片机</a> <div>ZYNQ学习笔记_GPIO之输入输出GPIO介绍MIO介绍EMIO介绍控制GPIO接口的寄存器原理_输入输出部分GPIO介绍GPIO的英文全称为General-purposeinput/output,即一种通用外设,可以通过MIO(MultiuseI/O)模块对器件的引脚做观测(input)和控制(output)。ZYNQ的PS端上的GPIO也可以通过EMIO(ExtraMIO)模块对PL端的IP</div> </li> <li><a href="/article/1903743725616558080.htm" title="zynq设计学习笔记2——GPIO之MIO控制LED实验" target="_blank">zynq设计学习笔记2——GPIO之MIO控制LED实验</a> <span class="text-muted">墨漓_lyl</span> <a class="tag" taget="_blank" href="/search/FPGA%E4%B9%8Bzynq%E8%AE%BE%E8%AE%A1%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/1.htm">FPGA之zynq设计学习笔记</a><a class="tag" taget="_blank" href="/search/%E5%B5%8C%E5%85%A5%E5%BC%8F/1.htm">嵌入式</a><a class="tag" taget="_blank" href="/search/fpga/1.htm">fpga</a> <div>vivado软件操作步骤与学习笔记1——helloworld差不多,这里不再过多赘述,不同点是在zynq的设置中添加上GPIO的设置即可。进入SDK软件后,程序如下:#include"stdio.h"#include"xparameters.h"#include"xgpiops.h"#include"sleep.h"#defineGPIO_DEVICE_IDXPAR_XGPIOPS_0_DEVIC</div> </li> <li><a href="/article/1903725060045205504.htm" title="LLM之向量数据库Chroma milvus FAISS" target="_blank">LLM之向量数据库Chroma milvus FAISS</a> <span class="text-muted">maxmaxma</span> <a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/milvus/1.htm">milvus</a><a class="tag" taget="_blank" href="/search/faiss/1.htm">faiss</a> <div>以下是Chroma、Milvus和FAISS的核心区别,从功能定位、架构设计、性能及应用场景等维度进行对比:一、功能定位Chroma轻量级向量数据库:专注于快速构建中小型语义搜索原型,提供简单易用的API,适合快速集成到现有应用中。特点:支持近似最近邻搜索(ANN)、实时性能优化,但对大规模数据处理能力有限。Milvus分布式向量数据库:专为超大规模向量数据设计,支持云原生架构和高可用性,适合企业</div> </li> <li><a href="/article/1903720643657003008.htm" title="uni-app 与webView 互相传值" target="_blank">uni-app 与webView 互相传值</a> <span class="text-muted">九亿少女无法触及的梦ى</span> <a class="tag" taget="_blank" href="/search/uni-app/1.htm">uni-app</a> <div>uni-app向webView传值在uni-app传值有多种实现方式,主要推荐evalJS,次要webSorcket重点:1.webView要找到正确的children!如果页面中只有一个webView标签则直接可以currentWebview.children()[0]2.H5页面中的监听function必须写在全局,不要写在任何load事件中!//index.vueletcurrentWebv</div> </li> <li><a href="/article/1903708645221265408.htm" title="Android Compose 框架按钮与交互组件模块源码深度剖析(二)" target="_blank">Android Compose 框架按钮与交互组件模块源码深度剖析(二)</a> <span class="text-muted">&有梦想的咸鱼&</span> <a class="tag" taget="_blank" href="/search/Androiod/1.htm">Androiod</a><a class="tag" taget="_blank" href="/search/Compose%E5%8E%9F%E7%90%86/1.htm">Compose原理</a><a class="tag" taget="_blank" href="/search/Android%E5%BC%80%E5%8F%91%E5%A4%A7%E5%85%A8/1.htm">Android开发大全</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div>一、引言在现代Android应用开发中,用户交互体验至关重要。AndroidCompose作为Google推出的声明式UI工具包,为开发者提供了简洁、高效且灵活的方式来构建用户界面。其中,按钮与交互组件模块是用户与应用进行交互的重要组成部分。本文将深入剖析AndroidCompose框架中按钮与交互组件模块的源码,从基础概念到具体实现,逐步揭示其工作原理和设计思路。二、AndroidCompose</div> </li> <li><a href="/article/1903703569668829184.htm" title="鸿蒙相机开发实战:从设备适配到性能调优 —— 我的 ArkTS 录像功能落地手记(API 15)" target="_blank">鸿蒙相机开发实战:从设备适配到性能调优 —— 我的 ArkTS 录像功能落地手记(API 15)</a> <span class="text-muted"></span> <a class="tag" taget="_blank" href="/search/harmonyos/1.htm">harmonyos</a> <div>引言:为什么我要写这份开发指南?作为一名老技术,最近特别喜欢研究鸿蒙相机功能,而且目前已经更新到API15了,那么咱们更要好好研究一下。而且从手持云台到车载记录仪,每个项目都面临独特挑战:车载场景的高温稳定性、可穿戴设备的低功耗限制、多设备分辨率适配的玄学……这些痛点促使我重新梳理HarmonyOS相机开发的技术脉络——这正是本文的起源。比如之前在一款运动相机项目中,我们最初直接复用Android</div> </li> <li><a href="/article/1903691499472744448.htm" title="反激式开关电源芯片是什么?如何对反激开关电源mos管选型?" target="_blank">反激式开关电源芯片是什么?如何对反激开关电源mos管选型?</a> <span class="text-muted">TaidL</span> <a class="tag" taget="_blank" href="/search/%E7%94%B5%E6%BA%90IC/1.htm">电源IC</a><a class="tag" taget="_blank" href="/search/MOS%E7%AE%A1/1.htm">MOS管</a> <div>1.反激式开关电源芯片--简介反激式开关电源是指使用反激高频变压器隔离输入输出回路的开关电源。“反激”指的是在开关管接通的情况下,当输入为高电平时输出线路中串联的电感为放电状态;相反,在开关管断开的情况下,当输入为高电平时输出线路中的串联的电感为充电状态。与之相对的是“正激”式开关电源,当输入为高电平时输出线路中串联的电感为充电状态,相反当输入为高电平时输出线路中的串联的电感为放电状态,以此驱动负</div> </li> <li><a href="/article/1903676627628388352.htm" title="uniapp 和 webview 之间的通信" target="_blank">uniapp 和 webview 之间的通信</a> <span class="text-muted">DT——</span> <a class="tag" taget="_blank" href="/search/%E5%85%B6%E4%BB%96/1.htm">其他</a><a class="tag" taget="_blank" href="/search/uni-app/1.htm">uni-app</a> <div>1.背景应用使用了uniapp开发跨端应用,在uniapp中内嵌webview页面实现页面热更新效果,不需要用户单独重新安装软件即可实现页面的版本更新。2.webview通知uniapp在开发过程中我们难会遇到需要uniapp和webview来实现数据通信的场景,接下来介绍一种可行的uniapp和webview的数据通信方案。在webview中我们可以使用当前webview实例的postMessa</div> </li> <li><a href="/article/1903674484943024128.htm" title="PX4飞控之位置控制(1)整体架构" target="_blank">PX4飞控之位置控制(1)整体架构</a> <span class="text-muted">Felix_ZL</span> <a class="tag" taget="_blank" href="/search/px4%E9%A3%9E%E6%8E%A7/1.htm">px4飞控</a><a class="tag" taget="_blank" href="/search/PX4/1.htm">PX4</a><a class="tag" taget="_blank" href="/search/%E4%BD%8D%E7%BD%AE%E6%8E%A7%E5%88%B6/1.htm">位置控制</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a> <div>位置控制是无人机飞控的核心算法之一,一方面根据commander中的flag标志位和Navigator中提供的航点信息进行控制(自主模式下),另一方面得到期望姿态角(setpoint)的四元数信息,给到姿态控制模块进行姿态控制。本文重点PX4飞控的位置控制的代码整体架构(mc_pos_control),具体的控制算法将在后续文章中陆续奉上。位置控制模块的主函数:task_main()1.订阅结构体</div> </li> <li><a href="/article/1903666041070874624.htm" title="Ubuntu18.04之网络配置+域名配置+软件源配置+ssh免密登陆" target="_blank">Ubuntu18.04之网络配置+域名配置+软件源配置+ssh免密登陆</a> <span class="text-muted">那记忆微凉</span> <a class="tag" taget="_blank" href="/search/Linux/1.htm">Linux</a> <div>网络配置ubuntu18.04网络配置较之前版本有较大改动,它弃用了/etc/networks/interface配置,真正的网络配置是在/etc/netplan/xxx.yaml中生效查看当前系统网口连结状态,使用ipa查看对应网口,如果状态不是down而是up,则选择改网口进行配置编辑/etc/netplan/xxx.yaml#注意,如果每个配置后面有内容,则:号后面需加一个空格,再加入自己的</div> </li> <li><a href="/article/1903638681202257920.htm" title="360 最新Android面试题及参考答案" target="_blank">360 最新Android面试题及参考答案</a> <span class="text-muted">大模型大数据攻城狮</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/%E5%AE%89%E5%8D%93%E9%9D%A2%E7%BB%8F/1.htm">安卓面经</a><a class="tag" taget="_blank" href="/search/%E5%AE%89%E5%8D%93%E9%9D%A2%E8%AF%95/1.htm">安卓面试</a><a class="tag" taget="_blank" href="/search/dex%E7%BB%93%E6%9E%84/1.htm">dex结构</a><a class="tag" taget="_blank" href="/search/hook%E6%8A%80%E6%9C%AF/1.htm">hook技术</a><a class="tag" taget="_blank" href="/search/Binder/1.htm">Binder</a><a class="tag" taget="_blank" href="/search/aosp/1.htm">aosp</a> <div>一个activity只能有一个进程么【对进程的理解】在Android中,一个Activity并不只能有一个进程。进程是操作系统进行资源分配和调度的一个独立单位。从原理上来说,Android系统允许开发者通过在AndroidManifest.xml文件中的标签设置android:process属性,来指定Activity运行在不同的进程中。例如,如果有一个对性能要求很高的多媒体播放Activity,</div> </li> <li><a href="/article/1903638428969398272.htm" title="下载安装新版Android studio4.1.3无法启动的问题" target="_blank">下载安装新版Android studio4.1.3无法启动的问题</a> <span class="text-muted">kaolagirl</span> <a class="tag" taget="_blank" href="/search/Android/1.htm">Android</a><a class="tag" taget="_blank" href="/search/studio/1.htm">studio</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>我原来的AndroidStudio是2.3.3版本的,想更新成最新版,然后就把之前的卸载了,安装一路顺畅,没什么问题,就在我启动的时候进度条到80%就不动了,真的搞了一整天,然后突然看到【yijiaodingqiankun】博主的文章,让我解决了,真的太感谢了!启动不起来的原因是因为,新版的AndroidStudio更换了某些配置的文件夹,和之前的有冲突,还有就是之前的配置文件和新版有冲突,也可能</div> </li> <li><a href="/article/1903629479746531328.htm" title="安卓编译安装python_一文了解如何在安卓系统上安装Pydroid 3并进行编码" target="_blank">安卓编译安装python_一文了解如何在安卓系统上安装Pydroid 3并进行编码</a> <span class="text-muted">weixin_39916681</span> <a class="tag" taget="_blank" href="/search/%E5%AE%89%E5%8D%93%E7%BC%96%E8%AF%91%E5%AE%89%E8%A3%85python/1.htm">安卓编译安装python</a> <div>由于Pydroid3集成开发环境(IDE),因此可以用Python进行可移植的编码。Pydroid是Python3的极简解释器,可让您执行较小的项目并在Android设备上进行最少的编码。如果您还想在没有PC的任何地方学习Python编程,同时在Android上为Python复制PC平台,那么Pydroid3是一个不错的应用程序。无论您是Python编程的新手还是专家,让我们看看使用Pydroid</div> </li> <li><a href="/article/1903627714351394816.htm" title="一文读懂Python之random模块(31)" target="_blank">一文读懂Python之random模块(31)</a> <span class="text-muted">跟着杰哥学Python</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>random模块是Python的内置标准库,用于生成各类随机数,可以用作生成网站初始登录密码和随机验证码。一、random模块简介random模块可以生成随机数,包括随机整数、浮点数、随机元素等。二、random模块相关概念随机数:是指在一定范围内随机产生的数,每个数被选中的概率相等。随机数最重要的特性是其后产生的数与前面的数毫无关系,即随机性、不可预测性和不可重现性。三、random模块常用方法</div> </li> <li><a href="/article/1903609931832029184.htm" title="停止过度提示:为什么简短的 AI 提示比长prompt更胜一筹" target="_blank">停止过度提示:为什么简短的 AI 提示比长prompt更胜一筹</a> <span class="text-muted">大模型之路</span> <a class="tag" taget="_blank" href="/search/prompt/1.htm">prompt</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/prompt/1.htm">prompt</a><a class="tag" taget="_blank" href="/search/%E6%8F%90%E7%A4%BA%E8%AF%8D/1.htm">提示词</a> <div>当下如何与AI高效互动成为众多用户关注的焦点,而提示词(prompt)的运用则是其中的关键。提示词作为与AI沟通的桥梁,其长度和内容的详略在很大程度上影响着AI的回应效果以及用户体验。近年来,“过度提示”现象逐渐引发热议,与之相对的,短提示词的优势开始受到更多关注。本文将深入探讨为何短AI提示词比长提示词更具优势。长提示词的困境信息过载与AI处理难题在与AI交互的过程中,许多人试图通过提供详尽的长</div> </li> <li><a href="/article/1903601226226921472.htm" title="matlab两矩阵相似性,两个矩阵同时相似对角化MATLAB程序.docx" target="_blank">matlab两矩阵相似性,两个矩阵同时相似对角化MATLAB程序.docx</a> <span class="text-muted">weixin_39870664</span> <a class="tag" taget="_blank" href="/search/matlab%E4%B8%A4%E7%9F%A9%E9%98%B5%E7%9B%B8%E4%BC%BC%E6%80%A7/1.htm">matlab两矩阵相似性</a> <div>两个矩阵同时相似对角化MATLAB程序摘要:使用Matlab语言设计出实现两个复矩阵同时相似对角化的计算机程序。关键词:同时相似对角化;Matlab;程序矩阵对角化是重要的数学方法,但因其计算过程繁琐,人们往往望之生畏,尤其是多个矩阵同时对角化问题,因此本文设计出判断及计算两个复矩阵能否同时相似对角化的Matlab程序,用此能够方便地解决两个复矩阵同时相似对角化问题。1.理论基础定义[1]:设A、</div> </li> <li><a href="/article/1903598074987606016.htm" title="Android Compose 框架基本状态管理(mutableStateOf、State 接口)深入剖析(十四)" target="_blank">Android Compose 框架基本状态管理(mutableStateOf、State 接口)深入剖析(十四)</a> <span class="text-muted">&有梦想的咸鱼&</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div>AndroidCompose框架基本状态管理(mutableStateOf、State接口)深入剖析一、引言在Android开发的历史长河中,UI开发模式经历了从传统的XML布局到动态视图操作,再到如今声明式UI框架的转变。AndroidCompose作为Google推出的新一代声明式UI工具包,为开发者带来了全新的UI开发体验。其中,状态管理是Compose框架的核心概念之一,它决定了UI如何根</div> </li> <li><a href="/article/1903592898197254144.htm" title="【004安卓开发方案调研】之Ionic+Vue+Capacitor开发安卓" target="_blank">【004安卓开发方案调研】之Ionic+Vue+Capacitor开发安卓</a> <span class="text-muted">ThinkPet</span> <a class="tag" taget="_blank" href="/search/%E7%A7%BB%E5%8A%A8app%E5%BC%80%E5%8F%91/1.htm">移动app开发</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/ionic/1.htm">ionic</a><a class="tag" taget="_blank" href="/search/Capacitor/1.htm">Capacitor</a><a class="tag" taget="_blank" href="/search/Vue/1.htm">Vue</a> <div>基于Ionic+Vue+CapacitorPlugins的国内安卓开发生态和技术现状,结合跨平台框架特性与国内实际环境,以下是综合分析:一、技术成熟度评估1.核心优势跨平台开发效率Ionic提供预制的UI组件库(如卡片、列表、表单),结合Vue的响应式数据绑定,可快速构建80%以上的基础功能界面,开发效率比原生开发提升约40%。典型场景:企业内部工具App、电商商品详情页、新闻资讯类应用。Capa</div> </li> <li><a href="/article/1903592896473395200.htm" title="【001安卓开发方案调研】之Java+Gradle+XML 原生安卓开发" target="_blank">【001安卓开发方案调研】之Java+Gradle+XML 原生安卓开发</a> <span class="text-muted">ThinkPet</span> <a class="tag" taget="_blank" href="/search/%E7%A7%BB%E5%8A%A8app%E5%BC%80%E5%8F%91/1.htm">移动app开发</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/xml/1.htm">xml</a> <div>基于2025年国内安卓开发领域的最新动态,结合Java+Gradle+XML技术组合的生态发展,以下是综合分析:一、技术成熟度评估1.核心架构稳定性Java语言基础作为安卓开发官方支持语言,Java在国内拥有超过15年的技术积累,字节码编译机制与安卓ART虚拟机的深度适配,使其在内存管理、多线程处理等场景表现稳定。主流应用如微信、支付宝均保留Java核心模块。Gradle构建体系Gradle8.5</div> </li> <li><a href="/article/1903571693150990336.htm" title="Nginx核心知识100讲" target="_blank">Nginx核心知识100讲</a> <span class="text-muted">janthinasnail</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a> <div>详见:作者网站:http://www.taohui.pub/视频原网站:https://time.geekbang.org/course/intro/138?device=geekTime.android视频地址:https://www.bilibili.com/video/BV1w7411v74u文档地址:https://github.com/russelltao/geektime-nginx</div> </li> <li><a href="/article/1903544435199766528.htm" title="学习记录之游标翻页实现" target="_blank">学习记录之游标翻页实现</a> <span class="text-muted">sjsjsbbsbsn</span> <a class="tag" taget="_blank" href="/search/Java%E5%AD%A6%E4%B9%A0%E4%B9%8B%E8%B7%AF/1.htm">Java学习之路</a><a class="tag" taget="_blank" href="/search/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98%E6%8A%80%E5%B7%A7/1.htm">项目实战技巧</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/redis/1.htm">redis</a> <div>游标翻页本方案参考mallchat实现一.深翻页问题普通翻页前端一般会有个分页条。能够指定一页的条数,以及任意选择查看第几页,假设我们想查询第11页的内容传递过来的参数为:pageNo=11,pageSize=10对应的sql查询为:select*fromtablelimit100,10其中100代表需要跳过的条数,10代表跳过指定条数后,往后需要再取的条数。假设翻页到1w条,那我们要先扫描到这1</div> </li> <li><a href="/article/1903539133096194048.htm" title="Ubuntu和Windows系统之Mamba_ssm安装" target="_blank">Ubuntu和Windows系统之Mamba_ssm安装</a> <span class="text-muted">Netceor</span> <a class="tag" taget="_blank" href="/search/Python/1.htm">Python</a><a class="tag" taget="_blank" href="/search/ubuntu/1.htm">ubuntu</a><a class="tag" taget="_blank" href="/search/windows/1.htm">windows</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a> <div>Mamba的论文:https://arxiv.org/abs/2312.00752Mamba的github:https://github.com/state-spaces/mamba一、Ubuntu安装直接新建一个环境是最好的,不然很容易产生各种冲突#创建环境和相关包condacreate-nmambapython=3.10.13condaactivatemambacondainstallcuda</div> </li> <li><a href="/article/1903536228926550016.htm" title="分页优化之——游标分页" target="_blank">分页优化之——游标分页</a> <span class="text-muted">PhilipJ0303</span> <a class="tag" taget="_blank" href="/search/Java%E9%9D%A2%E8%AF%95/1.htm">Java面试</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93%E4%BC%98%E5%8C%96/1.htm">数据库优化</a><a class="tag" taget="_blank" href="/search/%E6%B8%B8%E6%A0%87%E5%88%86%E9%A1%B5/1.htm">游标分页</a><a class="tag" taget="_blank" href="/search/%E5%88%86%E9%A1%B5%E6%9F%A5%E8%AF%A2/1.htm">分页查询</a> <div>游标分页(Cursor-basedPagination)是一种高效的分页方式,特别适用于大数据集和无限滚动的场景。与传统的基于页码的分页(如page=1&size=10)不同,游标分页通过一个唯一的游标(通常是时间戳或唯一ID)来标记分页的位置,避免了传统分页在数据变动时的重复或遗漏问题。以下是游标分页在前后端的实现方式:1.游标分页的核心概念游标(Cursor):游标是一个唯一标识符,通常是数据</div> </li> <li><a href="/article/1903522233301659648.htm" title="DS/ML:数据科学技术之数据科学生命周期(四大层次+机器学习六大阶段+数据挖掘【5+6+6+4+4+1】步骤)的全流程最强学习路线讲解之详细攻略" target="_blank">DS/ML:数据科学技术之数据科学生命周期(四大层次+机器学习六大阶段+数据挖掘【5+6+6+4+4+1】步骤)的全流程最强学习路线讲解之详细攻略</a> <span class="text-muted">一个处女座的程序猿</span> <a class="tag" taget="_blank" href="/search/%E8%B5%84%E6%B7%B1%E6%96%87%E7%AB%A0%28%E5%89%8D%E6%B2%BF%2F%E7%BB%8F%E9%AA%8C%2F%E5%88%9B%E6%96%B0%29/1.htm">资深文章(前沿/经验/创新)</a><a class="tag" taget="_blank" href="/search/DataScience/1.htm">DataScience</a><a class="tag" taget="_blank" href="/search/ML/1.htm">ML</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%A7%91%E5%AD%A6/1.htm">数据科学</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%A7%91%E5%AD%A6%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/1.htm">数据科学的生命周期</a><a class="tag" taget="_blank" href="/search/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/1.htm">机器学习</a> <div>DS/ML:数据科学技术之数据科学生命周期(四大层次+机器学习六大阶段+数据挖掘【5+6+6+4+4+1】步骤)的全流程最强学习路线讲解之详细攻略导读:本文章是博主在数据科学和机器学习领域,先后实战过几百个应用案例之后的精心总结,应该是完全覆盖了数据科学的整个生命周期及其各个阶段的要点。其中机器学习领域六大阶段更是在整个数据科学生命周期中扮演着极其重要的角色。同时,因为涉及到博主出书中出版社要求在</div> </li> <li><a href="/article/1903521853067030528.htm" title="JVM常用概念之编译器黑洞" target="_blank">JVM常用概念之编译器黑洞</a> <span class="text-muted">剑海风云</span> <a class="tag" taget="_blank" href="/search/JDK%EF%BC%88Java/1.htm">JDK(Java</a><a class="tag" taget="_blank" href="/search/Development/1.htm">Development</a><a class="tag" taget="_blank" href="/search/Kit%EF%BC%89/1.htm">Kit)</a><a class="tag" taget="_blank" href="/search/jvm/1.htm">jvm</a><a class="tag" taget="_blank" href="/search/%E7%BC%96%E8%AF%91%E5%99%A8/1.htm">编译器</a><a class="tag" taget="_blank" href="/search/%E7%BC%96%E8%AF%91%E5%99%A8%E9%BB%91%E6%B4%9E/1.htm">编译器黑洞</a> <div>问题JMH如何避免微小基准测试中的不会运行的代码的消除工作?是否有隐式或显式编译器支持?基础知识优化编译器擅长优化简单的东西。例如,如果存在任何人都无法观察到的计算,则可以将其视为“不会运行的代码”并将其删除。这通常是一件好事,直到你运行基准测试。在那里,你想要计算,但你不需要结果。本质上,你观察基准测试所占用的“资源”,但没有简单的方法可以与编译器争论这一点。比如下面的测试用例,该方法中只涉及到</div> </li> <li><a href="/article/1903518698015092736.htm" title="人工智能 - 通用 AI Agent 之 LangManus、Manus、OpenManus 和 OWL 技术选型" target="_blank">人工智能 - 通用 AI Agent 之 LangManus、Manus、OpenManus 和 OWL 技术选型</a> <span class="text-muted">天机️灵韵</span> <a class="tag" taget="_blank" href="/search/%E5%85%B7%E8%BA%AB%E6%99%BA%E8%83%BD/1.htm">具身智能</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E5%85%B7%E8%BA%AB%E6%99%BA%E8%83%BD/1.htm">具身智能</a><a class="tag" taget="_blank" href="/search/%E6%99%BA%E8%83%BD%E4%BD%93/1.htm">智能体</a> <div>一、核心项目概览1.Manus(闭源通用AIAgent)定位:全球首个全流程自动化通用AIAgent,GAIA基准测试SOTA水平。核心能力:全流程自动化:从任务规划(如撰写报告)到执行(代码生成、表格制作)的端到端处理。智能纠错机制:基于沙箱环境的实时错误反思与调整(类似CodeAct技术)。云端依赖:需联网运行,集成浏览器操作、信息检索等工具。局限性:闭源且采用邀请制,二手市场邀请码溢价至数万</div> </li> <li><a href="/article/87.htm" title="面向对象面向过程" target="_blank">面向对象面向过程</a> <span class="text-muted">3213213333332132</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>面向对象:把要完成的一件事,通过对象间的协作实现。 面向过程:把要完成的一件事,通过循序依次调用各个模块实现。 我把大象装进冰箱这件事为例,用面向对象和面向过程实现,都是用java代码完成。 1、面向对象 package bigDemo.ObjectOriented; /** * 大象类 * * @Description * @author FuJian</div> </li> <li><a href="/article/214.htm" title="Java Hotspot: Remove the Permanent Generation" target="_blank">Java Hotspot: Remove the Permanent Generation</a> <span class="text-muted">bookjovi</span> <a class="tag" taget="_blank" href="/search/HotSpot/1.htm">HotSpot</a> <div>  openjdk上关于hotspot将移除永久带的描述非常详细,http://openjdk.java.net/jeps/122   JEP 122: Remove the Permanent Generation Author Jon Masamitsu Organization Oracle Created 2010/8/15 Updated 2011/</div> </li> <li><a href="/article/341.htm" title="正则表达式向前查找向后查找,环绕或零宽断言" target="_blank">正则表达式向前查找向后查找,环绕或零宽断言</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1.htm">正则表达式</a> <div>向前查找和向后查找 1. 向前查找:根据要匹配的字符序列后面存在一个特定的字符序列(肯定式向前查找)或不存在一个特定的序列(否定式向前查找)来决定是否匹配。.NET将向前查找称之为零宽度向前查找断言。     对于向前查找,出现在指定项之后的字符序列不会被正则表达式引擎返回。 2. 向后查找:一个要匹配的字符序列前面有或者没有指定的</div> </li> <li><a href="/article/468.htm" title="BaseDao" target="_blank">BaseDao</a> <span class="text-muted">171815164</span> <a class="tag" taget="_blank" href="/search/seda/1.htm">seda</a> <div> import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.PreparedStatement; import java.sql.ResultSet; public class BaseDao { public Conn</div> </li> <li><a href="/article/595.htm" title="Ant标签详解--Java命令" target="_blank">Ant标签详解--Java命令</a> <span class="text-muted">g21121</span> <a class="tag" taget="_blank" href="/search/Java%E5%91%BD%E4%BB%A4/1.htm">Java命令</a> <div>        这一篇主要介绍与java相关标签的使用         终于开始重头戏了,Java部分是我们关注的重点也是项目中用处最多的部分。           1</div> </li> <li><a href="/article/722.htm" title="[简单]代码片段_电梯数字排列" target="_blank">[简单]代码片段_电梯数字排列</a> <span class="text-muted">53873039oycg</span> <a class="tag" taget="_blank" href="/search/%E4%BB%A3%E7%A0%81/1.htm">代码</a> <div>       今天看电梯数字排列是9 18 26这样呈倒N排列的,写了个类似的打印例子,如下:       import java.util.Arrays; public class 电梯数字排列_S3_Test { public static void main(S</div> </li> <li><a href="/article/849.htm" title="Hessian原理" target="_blank">Hessian原理</a> <span class="text-muted">云端月影</span> <a class="tag" taget="_blank" href="/search/hessian%E5%8E%9F%E7%90%86/1.htm">hessian原理</a> <div>Hessian 原理分析 一.      远程通讯协议的基本原理 网络通信需要做的就是将流从一台计算机传输到另外一台计算机,基于传输协议和网络 IO 来实现,其中传输协议比较出名的有 http 、 tcp 、 udp 等等, http 、 tcp 、 udp 都是在基于 Socket 概念上为某类应用场景而扩展出的传输协</div> </li> <li><a href="/article/976.htm" title="区分Activity的四种加载模式----以及Intent的setFlags" target="_blank">区分Activity的四种加载模式----以及Intent的setFlags</a> <span class="text-muted">aijuans</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div>  在多Activity开发中,有可能是自己应用之间的Activity跳转,或者夹带其他应用的可复用Activity。可能会希望跳转到原来某个Activity实例,而不是产生大量重复的Activity。 这需要为Activity配置特定的加载模式,而不是使用默认的加载模式。 加载模式分类及在哪里配置 Activity有四种加载模式: standard singleTop</div> </li> <li><a href="/article/1103.htm" title="hibernate几个核心API及其查询分析" target="_blank">hibernate几个核心API及其查询分析</a> <span class="text-muted">antonyup_2006</span> <a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a><a class="tag" taget="_blank" href="/search/Hibernate/1.htm">Hibernate</a><a class="tag" taget="_blank" href="/search/xml/1.htm">xml</a><a class="tag" taget="_blank" href="/search/%E9%85%8D%E7%BD%AE%E7%AE%A1%E7%90%86/1.htm">配置管理</a> <div>(一)  org.hibernate.cfg.Configuration类         读取配置文件并创建唯一的SessionFactory对象.(一般,程序初始化hibernate时创建.)         Configuration co</div> </li> <li><a href="/article/1230.htm" title="PL/SQL的流程控制" target="_blank">PL/SQL的流程控制</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/PL%2FSQL%E7%BC%96%E7%A8%8B/1.htm">PL/SQL编程</a><a class="tag" taget="_blank" href="/search/%E5%BE%AA%E7%8E%AF%E6%8E%A7%E5%88%B6/1.htm">循环控制</a> <div>PL/SQL也是一门高级语言,所以流程控制是必须要有的,oracle数据库的pl/sql比sqlserver数据库要难,很多pl/sql中有的sqlserver里面没有   流程控制; 分支语句 if 条件 then 结果 else 结果 end if ; 条件语句 case when 条件 then 结果; 循环语句 loop </div> </li> <li><a href="/article/1357.htm" title="强大的Mockito测试框架" target="_blank">强大的Mockito测试框架</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/mockito/1.htm">mockito</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/1.htm">单元测试</a> <div>一.自动生成Mock类        在需要Mock的属性上标记@Mock注解,然后@RunWith中配置Mockito的TestRunner或者在setUp()方法中显示调用MockitoAnnotations.initMocks(this);生成Mock类即可。二.自动注入Mock类到被测试类  &nbs</div> </li> <li><a href="/article/1484.htm" title="精通Oracle10编程SQL(11)开发子程序" target="_blank">精通Oracle10编程SQL(11)开发子程序</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/plsql/1.htm">plsql</a> <div>/* *开发子程序 */ --子程序目是指被命名的PL/SQL块,这种块可以带有参数,可以在不同应用程序中多次调用 --PL/SQL有两种类型的子程序:过程和函数 --开发过程 --建立过程:不带任何参数 CREATE OR REPLACE PROCEDURE out_time IS BEGIN DBMS_OUTPUT.put_line(systimestamp); E</div> </li> <li><a href="/article/1611.htm" title="【EhCache一】EhCache版Hello World" target="_blank">【EhCache一】EhCache版Hello World</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/Hello+world/1.htm">Hello world</a> <div>本篇是EhCache系列的第一篇,总体介绍使用EhCache缓存进行CRUD的API的基本使用,更细节的内容包括EhCache源代码和设计、实现原理在接下来的文章中进行介绍   环境准备 1.新建Maven项目   2.添加EhCache的Maven依赖 <dependency> <groupId>ne</div> </li> <li><a href="/article/1738.htm" title="学习EJB3基础知识笔记" target="_blank">学习EJB3基础知识笔记</a> <span class="text-muted">白糖_</span> <a class="tag" taget="_blank" href="/search/bean/1.htm">bean</a><a class="tag" taget="_blank" href="/search/Hibernate/1.htm">Hibernate</a><a class="tag" taget="_blank" href="/search/jboss/1.htm">jboss</a><a class="tag" taget="_blank" href="/search/webservice/1.htm">webservice</a><a class="tag" taget="_blank" href="/search/ejb/1.htm">ejb</a> <div>最近项目进入系统测试阶段,全赖袁大虾领导有力,保持一周零bug记录,这也让自己腾出不少时间补充知识。花了两天时间把“传智播客EJB3.0”看完了,EJB基本的知识也有些了解,在这记录下EJB的部分知识,以供自己以后复习使用。   EJB是sun的服务器端组件模型,最大的用处是部署分布式应用程序。EJB (Enterprise JavaBean)是J2EE的一部分,定义了一个用于开发基</div> </li> <li><a href="/article/1865.htm" title="angular.bootstrap" target="_blank">angular.bootstrap</a> <span class="text-muted">boyitech</span> <a class="tag" taget="_blank" href="/search/AngularJS/1.htm">AngularJS</a><a class="tag" taget="_blank" href="/search/AngularJS+API/1.htm">AngularJS API</a><a class="tag" taget="_blank" href="/search/angular%E4%B8%AD%E6%96%87api/1.htm">angular中文api</a> <div>angular.bootstrap 描述:     手动初始化angular。     这个函数会自动检测创建的module有没有被加载多次,如果有则会在浏览器的控制台打出警告日志,并且不会再次加载。这样可以避免在程序运行过程中许多奇怪的问题发生。   使用方法:     angular .</div> </li> <li><a href="/article/1992.htm" title="java-谷歌面试题-给定一个固定长度的数组,将递增整数序列写入这个数组。当写到数组尾部时,返回数组开始重新写,并覆盖先前写过的数" target="_blank">java-谷歌面试题-给定一个固定长度的数组,将递增整数序列写入这个数组。当写到数组尾部时,返回数组开始重新写,并覆盖先前写过的数</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div> public class SearchInShiftedArray { /** * 题目:给定一个固定长度的数组,将递增整数序列写入这个数组。当写到数组尾部时,返回数组开始重新写,并覆盖先前写过的数。 * 请在这个特殊数组中找出给定的整数。 * 解答: * 其实就是“旋转数组”。旋转数组的最小元素见http://bylijinnan.iteye.com/bl</div> </li> <li><a href="/article/2119.htm" title="天使还是魔鬼?都是我们制造" target="_blank">天使还是魔鬼?都是我们制造</a> <span class="text-muted">ducklsl</span> <a class="tag" taget="_blank" href="/search/%E7%94%9F%E6%B4%BB/1.htm">生活</a><a class="tag" taget="_blank" href="/search/%E6%95%99%E8%82%B2/1.htm">教育</a><a class="tag" taget="_blank" href="/search/%E6%83%85%E6%84%9F/1.htm">情感</a> <div>----------------------------剧透请原谅,有兴趣的朋友可以自己看看电影,互相讨论哦!!!     从厦门回来的动车上,无意中瞟到了书中推荐的几部关于儿童的电影。当然,这几部电影可能会另大家失望,并不是类似小鬼当家的电影,而是关于“坏小孩”的电影!     自己挑了两部先看了看,但是发现看完之后,心里久久不能平</div> </li> <li><a href="/article/2246.htm" title="[机器智能与生物]研究生物智能的问题" target="_blank">[机器智能与生物]研究生物智能的问题</a> <span class="text-muted">comsci</span> <a class="tag" taget="_blank" href="/search/%E7%94%9F%E7%89%A9/1.htm">生物</a> <div>       我想,人的神经网络和苍蝇的神经网络,并没有本质的区别...就是大规模拓扑系统和中小规模拓扑分析的区别....       但是,如果去研究活体人类的神经网络和脑系统,可能会受到一些法律和道德方面的限制,而且研究结果也不一定可靠,那么希望从事生物神经网络研究的朋友,不如把</div> </li> <li><a href="/article/2373.htm" title="获取Android Device的信息" target="_blank">获取Android Device的信息</a> <span class="text-muted">dai_lm</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div> String phoneInfo = "PRODUCT: " + android.os.Build.PRODUCT; phoneInfo += ", CPU_ABI: " + android.os.Build.CPU_ABI; phoneInfo += ", TAGS: " + android.os.Build.TAGS; ph</div> </li> <li><a href="/article/2500.htm" title="最佳字符串匹配算法(Damerau-Levenshtein距离算法)的Java实现" target="_blank">最佳字符串匹配算法(Damerau-Levenshtein距离算法)的Java实现</a> <span class="text-muted">datamachine</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%8C%B9%E9%85%8D/1.htm">字符串匹配</a> <div>原文:http://www.javacodegeeks.com/2013/11/java-implementation-of-optimal-string-alignment.html------------------------------------------------------------------------------------------------------------</div> </li> <li><a href="/article/2627.htm" title="小学5年级英语单词背诵第一课" target="_blank">小学5年级英语单词背诵第一课</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/english/1.htm">english</a><a class="tag" taget="_blank" href="/search/word/1.htm">word</a> <div>long 长的 show 给...看,出示 mouth 口,嘴 write 写   use 用,使用 take 拿,带来 hand 手 clever 聪明的   often 经常 wash 洗 slow 慢的 house 房子   water 水 clean 清洁的 supper 晚餐 out 在外   face 脸,</div> </li> <li><a href="/article/2754.htm" title="macvim的使用实战" target="_blank">macvim的使用实战</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/mac/1.htm">mac</a><a class="tag" taget="_blank" href="/search/vim/1.htm">vim</a> <div>macvim用的是mac里面的vim, 只不过是一个GUI的APP, 相当于一个壳   1. 下载macvim https://code.google.com/p/macvim/   2. 了解macvim :h               vim的使用帮助信息 :h macvim  </div> </li> <li><a href="/article/2881.htm" title="java二分法查找" target="_blank">java二分法查找</a> <span class="text-muted">蕃薯耀</span> <a class="tag" taget="_blank" href="/search/java%E4%BA%8C%E5%88%86%E6%B3%95%E6%9F%A5%E6%89%BE/1.htm">java二分法查找</a><a class="tag" taget="_blank" href="/search/%E4%BA%8C%E5%88%86%E6%B3%95/1.htm">二分法</a><a class="tag" taget="_blank" href="/search/java%E4%BA%8C%E5%88%86%E6%B3%95/1.htm">java二分法</a> <div>java二分法查找 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 蕃薯耀 2015年6月23日 11:40:03 星期二 http:/</div> </li> <li><a href="/article/3008.htm" title="Spring Cache注解+Memcached" target="_blank">Spring Cache注解+Memcached</a> <span class="text-muted">hanqunfeng</span> <a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/memcached/1.htm">memcached</a> <div>Spring3.1 Cache注解  依赖jar包: <!-- simple-spring-memcached --> <dependency> <groupId>com.google.code.simple-spring-memcached</groupId> <artifactId>simple-s</div> </li> <li><a href="/article/3135.htm" title="apache commons io包快速入门" target="_blank">apache commons io包快速入门</a> <span class="text-muted">jackyrong</span> <a class="tag" taget="_blank" href="/search/apache+commons/1.htm">apache commons</a> <div>原文参考 http://www.javacodegeeks.com/2014/10/apache-commons-io-tutorial.html   Apache Commons IO 包绝对是好东西,地址在http://commons.apache.org/proper/commons-io/,下面用例子分别介绍:   1)  工具类   2</div> </li> <li><a href="/article/3262.htm" title="如何学习编程" target="_blank">如何学习编程</a> <span class="text-muted">lampcy</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B/1.htm">编程</a><a class="tag" taget="_blank" href="/search/C%2B%2B/1.htm">C++</a><a class="tag" taget="_blank" href="/search/c/1.htm">c</a> <div>首先,我想说一下学习思想.学编程其实跟网络游戏有着类似的效果.开始的时候,你会对那些代码,函数等产生很大的兴趣,尤其是刚接触编程的人,刚学习第一种语言的人.可是,当你一步步深入的时候,你会发现你没有了以前那种斗志.就好象你在玩韩国泡菜网游似的,玩到一定程度,每天就是练级练级,完全是一个想冲到高级别的意志力在支持着你.而学编程就更难了,学了两个月后,总是觉得你好象全都学会了,却又什么都做不了,又没有</div> </li> <li><a href="/article/3389.htm" title="架构师之spring-----spring3.0新特性的bean加载控制@DependsOn和@Lazy" target="_blank">架构师之spring-----spring3.0新特性的bean加载控制@DependsOn和@Lazy</a> <span class="text-muted">nannan408</span> <a class="tag" taget="_blank" href="/search/Spring3/1.htm">Spring3</a> <div>1.前言。    如题。 2.描述。    @DependsOn用于强制初始化其他Bean。可以修饰Bean类或方法,使用该Annotation时可以指定一个字符串数组作为参数,每个数组元素对应于一个强制初始化的Bean。 @DependsOn({"steelAxe","abc"}) @Comp</div> </li> <li><a href="/article/3516.htm" title="Spring4+quartz2的配置和代码方式调度" target="_blank">Spring4+quartz2的配置和代码方式调度</a> <span class="text-muted">Everyday都不同</span> <a class="tag" taget="_blank" href="/search/%E4%BB%A3%E7%A0%81/1.htm">代码</a><a class="tag" taget="_blank" href="/search/%E9%85%8D%E7%BD%AE/1.htm">配置</a><a class="tag" taget="_blank" href="/search/spring4/1.htm">spring4</a><a class="tag" taget="_blank" href="/search/quartz2.x/1.htm">quartz2.x</a><a class="tag" taget="_blank" href="/search/%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1/1.htm">定时任务</a> <div>前言:这些天简直被quartz虐哭。。因为quartz 2.x版本相比quartz1.x版本的API改动太多,所以,只好自己去查阅底层API……   quartz定时任务必须搞清楚几个概念: JobDetail——处理类 Trigger——触发器,指定触发时间,必须要有JobDetail属性,即触发对象 Scheduler——调度器,组织处理类和触发器,配置方式一般只需指定触发</div> </li> <li><a href="/article/3643.htm" title="Hibernate入门" target="_blank">Hibernate入门</a> <span class="text-muted">tntxia</span> <a class="tag" taget="_blank" href="/search/Hibernate/1.htm">Hibernate</a> <div>  前言   使用面向对象的语言和关系型的数据库,开发起来很繁琐,费时。由于现在流行的数据库都不面向对象。Hibernate 是一个Java的ORM(Object/Relational Mapping)解决方案。   Hibernte不仅关心把Java对象对应到数据库的表中,而且提供了请求和检索的方法。简化了手工进行JDBC操作的流程。   如</div> </li> <li><a href="/article/3770.htm" title="Math类" target="_blank">Math类</a> <span class="text-muted">xiaoxing598</span> <a class="tag" taget="_blank" href="/search/Math/1.htm">Math</a> <div>一、Java中的数字(Math)类是final类,不可继承。 1、常数 PI:double圆周率 E:double自然对数 2、截取(注意方法的返回类型) double ceil(double d) 返回不小于d的最小整数 double floor(double d) 返回不大于d的整最大数 int round(float f) 返回四舍五入后的整数 long round</div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html>