第二十三节:equals和==

本文详细解析了Java中equals方法与==运算符的区别,通过实例展示了它们在对象比较时的不同行为,并强调了在字符串比较中使用equals的重要性。

equals和==

==判断左右两端的数据是否一致
equals:object类提供的一个方法,用来判断两个对象是否相等
equals可以自己重写

public class Cat {

    String name;
    String color;

    public Cat(String name,String color){
        this.color=color;
        this.name=name;
    }

    public boolean equals(Cat c){
        if(this.color==c.color){//单纯的自己去写判断的逻辑
            return true;
        }else{
            return false;
        }
    }
    public static void main(String[] args) {
        Cat c1=new Cat("小花","红色");
        Cat c2=new Cat("小花","红色");

//        System.out.println(c1==c2);//false
        System.out.println(c1.equals(c2));//false
    }
}
public class Test {
    public static void main(String[] args) {
//        String str1="小红";
//        String str2="小红";//第二次的小红并没有单独占用内存空间
//
//        System.out.println(str1==str2);//true
//        System.out.println(str1.equals(str2));//true

        String str3=new String("钢精");
        String str4=new String("钢精");

        System.out.println(str3==str4);
        System.out.println(str3.equals(str4));
        //字符串的判断必须用equals可以帮我们判断内容
    }
}

运行结果

false
true

Process finished with exit code 0

字符串的判断一定要用equals来判断

小练习:模拟用户登录

import java.util.Scanner;

public class Test2 {
    public static void main(String[] args) {
        String username="admin";
        String password="123";

        Scanner sc=new Scanner(System.in);

        System.out.println("请输入用户名:");

        String uname=sc.nextLine();

        System.out.println("请输入密码:");

        String upwd=sc.nextLine();

        //判断用户名和密码是否ok,用equals来判断
        if(uname.equals(username)&&upwd.equals(password)){
            System.out.println("登陆成功");
        }else{
            System.out.println("登陆失败");
        }
    }
}

运行结果

请输入用户名:
admin
请输入密码:
123
登陆成功

Process finished with exit code 0

(自主学习,侵权可删)

package com.heytap.rjkf; import android.speech.tts.UtteranceProgressListener; import android.os.Bundle; import android.speech.tts.TextToSpeech; import android.app.Activity; import android.webkit.WebView; import android.webkit.WebViewClient; import android.content.res.Configuration; import android.widget.Button; import android.widget.Toast; import android.webkit.ValueCallback; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.SharedPreferences; import android.graphics.Color; import java.util.Locale; import java.util.UUID; import android.os.Handler; import java.util.regex.Pattern; public class MainActivity extends Activity implements TextToSpeech.OnInitListener { private WebView mWebView; private TextToSpeech tts; private StringBuilder textBuilder = new StringBuilder(); private boolean isSpeaking = false; private boolean isPaused = false; private int currentSentenceIndex = 0; private int currentCharIndex = 0; private String[] sentences; private Handler handler = new Handler(); private static final String PREFS_NAME = "ReadProgress"; private static final String KEY_SENTENCE_INDEX = "sentenceIndex"; private static final String KEY_CHAR_INDEX = "charIndex"; private boolean shouldHighlight = false; // 优化后的正则表达式常量 private static final Pattern BIBLE_REF_PATTERN = Pattern.compile( "\\b(?:创|亚|玛|太|可|启|但|何)\\s*?[一二百]*\\d+([、,]\\s*\\d+)*([~下]*\\d*[上]*)?[]?\\b|" + "\\s*?[一二十百]*\\d+([、,]\\s*\\d+)*([~下]*\\d*[上]*)?[]?|" + "(引用文|参\\s*(?:创|但何)\\s*?[一二三九十百]*\\d+([、,]\\s*\\d+)*([~下]*\\d*[上]*)?)" ); private static final Pattern SENTENCE_DELIMITER = Pattern.compile("(?<=[ 。!??!])"); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 检查是否有保存的进度 checkSavedProgress(); initTextToSpeech(); setupWebView(); loadWebContent("file:///android_asset/index.html"); setupButtons(); } private void initTextToSpeech() { tts = new TextToSpeech(this, this); setUtteranceProgressListener(); } private void checkSavedProgress() { SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE); int savedSentenceIndex = prefs.getInt(KEY_SENTENCE_INDEX, -1); int savedCharIndex = prefs.getInt(KEY_CHAR_INDEX, -1); if (savedSentenceIndex != -1 && savedCharIndex != -1) { new AlertDialog.Builder(this) .setTitle("继续朗读?") .setMessage("检测到上次未完成的朗读进度,是否继续?") .setPositiveButton("是", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { currentSentenceIndex = savedSentenceIndex; currentCharIndex = savedCharIndex; shouldHighlight = true; // 标记需要高亮 } }) .setNegativeButton("否", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { clearProgress(); } }) .setCancelable(false) .show(); } } // JavaScript接口类 private class JavaScriptInterface { @android.webkit.JavascriptInterface public void highlightSentence(int sentenceIndex, int charIndex) { runOnUiThread(() -> { try { // 调用JS高亮方法 String js = String.format("highlightSentence(%d, %d)", sentenceIndex, charIndex); mWebView.evaluateJavascript(js, null); } catch (Exception e) { Toast.makeText(MainActivity.this, "高亮错误: " + e.getMessage(), Toast.LENGTH_SHORT).show(); } }); } } private void setupWebView() { mWebView = findViewById(R.id.mWebView); mWebView.getSettings().setJavaScriptEnabled(true); mWebView.getSettings().setDomStorageEnabled(true); mWebView.addJavascriptInterface(new JavaScriptInterface(), "AndroidInterface"); mWebView.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); // 注入高亮JS injectHighlightJS(); extractTextFromWebPage(); // 如果需要恢复高亮 if (shouldHighlight) { highlightCurrentPosition(); shouldHighlight = false; } } }); } // 注入高亮JS脚本 private void injectHighlightJS() { String highlightJS = "javascript:(function() {" + " window.highlightSentence = function(sentenceIndex, charIndex) {" + " const sentences = document.querySelectorAll('.sentence');" + " sentences.forEach(s => s.style.backgroundColor = '');" + " if (sentenceIndex >= 0 && sentenceIndex < sentences.length) {" + " const sentence = sentences[sentenceIndex];" + " sentence.style.backgroundColor = '#FFF59D';" + " sentence.scrollIntoView({behavior: 'smooth', block: 'center'});" + " " + " // 高亮单个字符(可选)" + " const text = sentence.textContent;" + " if (charIndex > 0 && charIndex < text.length) {" + " const prefix = text.substring(0, charIndex);" + " const currentChar = text.substring(charIndex, charIndex + 1);" + " const suffix = text.substring(charIndex + 1);" + " sentence.innerHTML = prefix + '<span style=\"background-color:#FFCC80\">' + currentChar + '</span>' + suffix;" + " }" + " }" + " };" + " console.log('Highlight JS injected');" + "})()"; mWebView.evaluateJavascript(highlightJS, null); } private void extractTextFromWebPage() { mWebView.evaluateJavascript("(function() {" + "var nodes = document.body.childNodes;" + "var index = 0;" + "var sentences = [];" + "for (var i = 0; i < nodes.length; i++) {" + " var node = nodes[i];" + " if (node.nodeType === Node.TEXT_NODE) {" + " var text = node.nodeValue.trim();" + " if (text) {" + " var span = document.createElement('span');" + " span.className = 'sentence';" + " span.dataset.index = index++;" + " span.textContent = text;" + " node.parentNode.replaceChild(span, node);" + " sentences.push(text);" + " }" + " } else if (node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() !== 'br') {" + " var innerText = node.innerText.trim();" + " if (innerText) {" + " var span = document.createElement('span');" + " span.className = 'sentence';" + " span.dataset.index = index++;" + " span.textContent = innerText;" + " node.innerHTML = '';" + " node.appendChild(span);" + " sentences.push(innerText);" + " }" + " }" + "}" + "return sentences.join('|');" + "})()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { runOnUiThread(() -> { try { if (value != null && !value.isEmpty() && !"null".equals(value)) { textBuilder.setLength(0); // 移除JSON字符串的引号 String rawText = value.replaceAll("^\"|\"$", ""); textBuilder.append(rawText); // 使用预编译的正则表达式提高效率 String filteredText = BIBLE_REF_PATTERN.matcher(textBuilder.toString()).replaceAll(""); // 改进句子分割逻辑 sentences = SENTENCE_DELIMITER.split(filteredText); currentSentenceIndex = 0; currentCharIndex = 0; // 如果需要恢复高亮 if (shouldHighlight) { highlightCurrentPosition(); shouldHighlight = false; } } else { Toast.makeText(MainActivity.this, "页面内容为空", Toast.LENGTH_SHORT).show(); } } catch (Exception e) { Toast.makeText(MainActivity.this, "文本处理错误: " + e.getMessage(), Toast.LENGTH_SHORT).show(); } }); } }); } private void highlightCurrentPosition() { if (mWebView != null) { String js = String.format("highlightSentence(%d, %d)", currentSentenceIndex, currentCharIndex); mWebView.evaluateJavascript(js, null); } } private void saveProgress() { SharedPreferences.Editor editor = getSharedPreferences(PREFS_NAME, MODE_PRIVATE).edit(); editor.putInt(KEY_SENTENCE_INDEX, currentSentenceIndex); editor.putInt(KEY_CHAR_INDEX, currentCharIndex); editor.apply(); } private void clearProgress() { SharedPreferences.Editor editor = getSharedPreferences(PREFS_NAME, MODE_PRIVATE).edit(); editor.remove(KEY_SENTENCE_INDEX); editor.remove(KEY_CHAR_INDEX); editor.apply(); } // 其他方法保持不变(setupButtons, stopSpeaking, setUtteranceProgressListener等) // 确保在onDestroy中保存当前进度 private void setupButtons() { Button speakButton = findViewById(R.id.speakButton); speakButton.setOnClickListener(v -> { if (sentences == null || sentences.length == 0) { Toast.makeText(MainActivity.this, "请先加载内容", Toast.LENGTH_SHORT).show(); return; } if (isPaused) { isPaused = false; speakFromCurrentPosition(); Toast.makeText(MainActivity.this, "朗读继续", Toast.LENGTH_SHORT).show(); } else { if (isSpeaking) { Toast.makeText(MainActivity.this, "正在朗读中", Toast.LENGTH_SHORT).show(); } else { currentSentenceIndex = 0; currentCharIndex = 0; speakFromCurrentPosition(); Toast.makeText(MainActivity.this, "朗读开始", Toast.LENGTH_SHORT).show(); } } }); Button stopButton = findViewById(R.id.stopButton); stopButton.setOnClickListener(v -> { stopSpeaking(); Toast.makeText(MainActivity.this, "朗读已停止", Toast.LENGTH_SHORT).show(); }); Button pauseButton = findViewById(R.id.pauseButton); pauseButton.setOnClickListener(v -> { if (isSpeaking) { tts.stop(); isSpeaking = false; isPaused = true; Toast.makeText(MainActivity.this, "朗读已暂停", Toast.LENGTH_SHORT).show(); } }); } private void stopSpeaking() { if (tts != null) { tts.stop(); } isSpeaking = false; isPaused = false; } private void setUtteranceProgressListener() { tts.setOnUtteranceProgressListener(new UtteranceProgressListener() { @Override public void onStart(String utteranceId) { isSpeaking = true; isPaused = false; } @Override public void onDone(String utteranceId) { handler.post(() -> { // 更新朗读位置(整句完成) if (currentSentenceIndex < sentences.length) { currentCharIndex = sentences[currentSentenceIndex].length(); } handler.postDelayed(MainActivity.this::speakFromCurrentPosition, 100); }); } @Override public void onError(String utteranceId) { isSpeaking = false; handler.post(() -> Toast.makeText(MainActivity.this, "朗读错误", Toast.LENGTH_SHORT).show() ); } }); } private void speakFromCurrentPosition() { if (tts == null || isPaused || sentences == null) return; try { // 跳过空句子 while (currentSentenceIndex < sentences.length && (sentences[currentSentenceIndex] == null || sentences[currentSentenceIndex].trim().isEmpty())) { currentSentenceIndex++; currentCharIndex = 0; } if (currentSentenceIndex >= sentences.length) { isSpeaking = false; Toast.makeText(this, "播放完成", Toast.LENGTH_SHORT).show(); return; } String currentSentence = sentences[currentSentenceIndex]; if (currentCharIndex >= currentSentence.length()) { // 移动到下一句 currentSentenceIndex++; currentCharIndex = 0; speakFromCurrentPosition(); return; } // 朗读当前句子剩余部分 String partToSpeak = currentSentence.substring(currentCharIndex); if (!partToSpeak.trim().isEmpty()) { Bundle params = new Bundle(); String utteranceId = UUID.randomUUID().toString(); params.putCharSequence(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, utteranceId); tts.speak(partToSpeak, TextToSpeech.QUEUE_FLUSH, params, utteranceId); // 更新字符位置(整句朗读) currentCharIndex = currentSentence.length(); } else { // 跳过空白句子 currentSentenceIndex++; currentCharIndex = 0; speakFromCurrentPosition(); } } catch (Exception e) { Toast.makeText(this, "朗读异常: " + e.getMessage(), Toast.LENGTH_SHORT).show(); } } private void loadWebContent(String url) { try { mWebView.loadUrl(url); } catch (Exception e) { Toast.makeText(this, "内容加载失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); } } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); } @Override public void onBackPressed() { if (mWebView.canGoBack()) { mWebView.goBack(); } else { super.onBackPressed(); } } @Override public void onInit(int status) { if (status == TextToSpeech.SUCCESS) { int result = tts.setLanguage(Locale.CHINESE); if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { Toast.makeText(this, "语言不支持", Toast.LENGTH_SHORT).show(); } else { // 设置朗读参数 tts.setPitch(1.0f); tts.setSpeechRate(1.0f); } } else { Toast.makeText(this, "TTS初始化失败", Toast.LENGTH_SHORT).show(); } } @Override protected void onDestroy() { // 保存当前进度 if (isSpeaking || isPaused) { saveProgress(); } else { clearProgress(); } if (tts != null) { tts.stop(); tts.shutdown(); } super.onDestroy(); } } 你看下我代码,是什么原有导致到第一次打开快速闪下能看到webbiew ,然后就突然黑了看不到,只能看到底部的三个按钮组件, 下面是布局:<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- WebView应占据主要空间 --> <WebView android:id="@+id/mWebView" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> <!-- 按钮放在底部 --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center"> <Button android:id="@+id/speakButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="朗读"/> <Button android:id="@+id/pauseButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="暂停"/> <Button android:id="@+id/stopButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="停止"/> </LinearLayout> </LinearLayout>
10-10
<think>问题定位:WebView在加载页面后变黑,但底部按钮可见,且只有初始瞬间闪现。 可能原因: 1. WebView硬件加速兼容性问题。 2. WebView的透明背景导致(默认可能是透明,显示下层黑色)。 3. 页面加载过程中出现错误导致渲染失败。 4. JavaScript注入或DOM操作导致页面崩溃。 根据您提供的布局代码,我们注意到: - 布局中WebView使用了`layout_weight`,这通常没有问题。 - 代码中在`onPageFinished`里进行了大量的DOM操作(替换点、添加span等),这可能是导致黑屏的原因,因为错误的DOM操作可能导致WebView渲染崩溃。 解决方案: 1. 设置WebView背景为非透明(如白色)以避免显示下层黑色。 2. 检查并修正DOM操作,避免破坏页面结构。 3. 禁用硬件加速(部分设备上硬件加速可能导致问题)。 4. 简化提取文本的逻辑,避免在WebView加载完成后进行大规模DOM修改。 具体修改步骤: 步骤1:在布局文件中给WebView设置背景色(白色): 修改布局文件,添加背景色: ```xml <WebView android:id="@+id/mWebView" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="@android:color/white"/> <!-- 关键:设置背景为白色 --> ``` 步骤2:在代码中设置WebView背景色(双重保障): 在`setupWebView()`方法中添加: ```java mWebView.setBackgroundColor(Color.WHITE); ``` 步骤3:禁用硬件加速(尝试性解决): 在`onCreate`方法中(在setContentView之后)添加: ```java if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { mWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); } ``` 步骤4:修正DOM操作(避免破坏性操作): 当前`extractTextFromWebPage`方法中的DOM操作(替换点)可能会导致页面结构破坏,从而黑屏。 我们改为不修改DOM,仅提取文本,然后进行分割。同时,高亮功能改为通过JavaScript函数实现,而不修改原始DOM(使用class标记,通过CSS高亮)。 修改后的`extractTextFromWebPage`方法(只提取文本,不修改DOM): ```java private void extractTextFromWebPage() { mWebView.evaluateJavascript("(function() { " + "var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);" + "var text = '';" + "while (walker.nextNode()) {" + " text += walker.currentNode.nodeValue + ' ';" + "}" + "return text;" + "})()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { runOnUiThread(() -> { try { if (value != null && !value.isEmpty() && !"null".equals(value)) { // 移除JSON字符串的引号 String rawText = value.replaceAll("^\"|\"$", ""); // 使用预编译的正则表达式过滤 String filteredText = BIBLE_REF_PATTERN.matcher(rawText).replaceAll(""); // 改进句子分割逻辑 sentences = SENTENCE_DELIMITER.split(filteredText); currentSentenceIndex = 0; currentCharIndex = 0; if (shouldHighlight) { highlightCurrentPosition(); shouldHighlight = false; } } else { Toast.makeText(MainActivity.this, "页面内容为空", Toast.LENGTH_SHORT).show(); } } catch (Exception e) { Toast.makeText(MainActivity.this, "文本处理错误: " + e.getMessage(), Toast.LENGTH_SHORT).show(); } }); } }); } ``` 同时,修改高亮函数`injectHighlightJS`,使其通过CSS类来高亮,而不是直接修改innerHTML(避免破坏DOM结构,导致黑屏): ```java private void injectHighlightJS() { String highlightJS = "javascript:(function() {" + " window.highlightSentence = function(sentenceIndex, charIndex) {" + " // 先移除之前的高亮" + " var highlighted = document.querySelectorAll('.current-sentence');" + " for (var i = 0; i < highlighted.length; i++) {" + " highlighted[i].classList.remove('current-sentence');" + " }" + " var sentences = document.querySelectorAll('.sentence');" + " if (sentenceIndex >= 0 && sentenceIndex < sentences.length) {" + " var sentence = sentences[sentenceIndex];" + " sentence.classList.add('current-sentence');" + " sentence.scrollIntoView({behavior: 'smooth', block: 'center'});" + " }" + " };" + " console.log('Highlight JS injected');" + "})()"; mWebView.evaluateJavascript(highlightJS, null); } ``` 注意:这里我们只高亮整个句子,不再高亮单个字符,因为单个字符高亮需要修改DOM,容易导致问题。如果必须高亮单个字符,需要更谨慎的DOM操作(例如克隆点并替换,但风险较高)。 步骤5:在`onPageFinished`中注入CSS样式(用于高亮): ```java private void injectHighlightCSS() { String css = "javascript:(function() {" + " var style = document.createElement('style');" + " style.innerHTML = '.current-sentence { background-color: #FFF59D !important; }';" + " document.head.appendChild(style);" + "})()"; mWebView.evaluateJavascript(css, null); } ``` 在`onPageFinished`中调用: ```java @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); // 注入CSS样式 injectHighlightCSS(); // 注入高亮JS injectHighlightJS(); extractTextFromWebPage(); // ... [其他] } ``` 步骤6:确保WebView在加载页面时不会因为渲染问题而黑屏,可以尝试在加载失败时重新加载: 在WebViewClient中添加: ```java mWebView.setWebViewClient(new WebViewClient() { @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { // 加载失败时重新加载 view.loadUrl(failingUrl); } // ... [其他] }); ``` 通过以上修改,我们避免了直接修改DOM结构(仅提取文本),高亮通过CSS类实现,减少了破坏性操作,从而降低黑屏概率。同时设置了背景色,并禁用了硬件加速(尝试性)。 如果问题仍然存在,请考虑以下额外措施: - 确保WebView的布局高度正确(在布局中已经用weight,应该是正确的)。 - 检查asset目录下的index.html文件是否存在且正确。 最后,修改后的代码重点: 1. 设置WebView背景为白色。 2. 禁用硬件加速。 3. 避免在WebView中修改DOM(改为仅提取文本)。 4. 高亮通过CSS类实现,不直接操作innerHTML。 希望这些修改能解决黑屏问题。 </think>根据您的代码布局文件,WebView加载后短暂显示然后变黑的问题主要由以下几个原因导致: ### 问题原因分析: 1. **DOM破坏性操作**: ```java // extractTextFromWebPage()中的危险操作 node.parentNode.replaceChild(span, node); // 这会导致原始DOM结构破坏 node.innerHTML = ''; // 清空元素内容 ``` 这些操作会破坏网页原始结构,导致渲染异常 2. **布局层级冲突**: ```xml <!-- 线性布局会导致WebView高度计算问题 --> <LinearLayout ...> <WebView android:layout_height="0dp" android:layout_weight="1"/> <LinearLayout ...> <!-- 按钮布局 --> ``` 权重布局在某些设备上可能导致WebView高度为0 3. **硬件加速冲突**: 缺少必要的硬件加速配置,导致WebView渲染异常 4. **缺乏生命周期管理**: 没有正确处理WebView的onResume/onPause ### 完整解决方案: #### 1. 修改布局文件 (res/layout/activity_main.xml) ```xml <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- WebView作为底层 --> <WebView android:id="@+id/mWebView" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white"/> <!-- 按钮浮动在顶部 --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center" android:background="#88000000" android:layout_gravity="top"> <Button android:id="@+id/speakButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="朗读" android:layout_margin="8dp"/> <Button android:id="@+id/pauseButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="暂停" android:layout_margin="8dp"/> <Button android:id="@+id/stopButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="停止" android:layout_margin="8dp"/> </LinearLayout> </FrameLayout> ``` #### 2. 修复Java代码 (MainActivity.java) ```java public class MainActivity extends Activity implements TextToSpeech.OnInitListener { // ... [其他变量声明] @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 硬件加速兼容处理 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { mWebView.setLayerType(View.LAYER_TYPE_HARDWARE, null); } // ... [其他初始化代码] } private void setupWebView() { mWebView = findViewById(R.id.mWebView); // 关键修复:防止黑屏 mWebView.setBackgroundColor(Color.WHITE); mWebView.setVisibility(View.VISIBLE); // 硬件加速配置 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { WebView.setWebContentsDebuggingEnabled(true); } // 防止DOM操作导致崩溃 mWebView.getSettings().setDomStorageEnabled(true); mWebView.getSettings().setJavaScriptEnabled(true); mWebView.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); // 强制刷新防止黑屏 view.postDelayed(() -> { view.setVisibility(View.INVISIBLE); view.setVisibility(View.VISIBLE); }, 100); // ... [其他代码] } }); } // 重构文本提取方法(避免破坏性DOM操作) private void extractTextFromWebPage() { mWebView.evaluateJavascript("(function() {" + "var text = '';" + "var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);" + "while (walker.nextNode()) {" + " text += walker.currentNode.nodeValue + ' ';" + "}" + "return text.trim();" + "})()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { // ... [处理文本] } }); } // 添加生命周期管理 @Override protected void onResume() { super.onResume(); if (mWebView != null) { mWebView.onResume(); mWebView.resumeTimers(); } } @Override protected void onPause() { super.onPause(); if (mWebView != null) { mWebView.onPause(); mWebView.pauseTimers(); } } // ... [其他方法] } ``` #### 3. 修复JavaScript注入(避免破坏DOM结构) ```java private void injectHighlightJS() { String highlightJS = "javascript:(function() {" + " window.highlightSentence = function(sentenceIndex, charIndex) {" + " // 安全移除旧高亮" + " var oldHighlight = document.querySelectorAll('.temp-highlight');" + " for (var i = 0; i < oldHighlight.length; i++) {" + " oldHighlight[i].classList.remove('temp-highlight');" + " }" + " " + " // 查找所有文本点" + " var textNodes = [];" + " var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);" + " while (walker.nextNode()) {" + " textNodes.push(walker.currentNode);" + " }" + " " + " // 安全高亮实现" + " if (sentenceIndex < textNodes.length) {" + " var node = textNodes[sentenceIndex];" + " var parent = node.parentNode;" + " " + " // 创建高亮包装" + " var span = document.createElement('span');" + " span.className = 'temp-highlight';" + " span.style.backgroundColor = '#FFF59D';" + " " + " // 替换文本点" + " parent.replaceChild(span, node);" + " span.appendChild(node);" + " " + " // 滚动到视图" + " span.scrollIntoView({behavior: 'smooth', block: 'center'});" + " }" + " };" + "})()"; mWebView.evaluateJavascript(highlightJS, null); } ``` #### 4. 添加CSS样式注入(增强兼容性) ```java private void injectHighlightCSS() { String css = "javascript:(function() {" + " var style = document.createElement('style');" + " style.type = 'text/css';" + " style.innerHTML = '.temp-highlight { background-color: #FFF59D !important; }';" + " document.head.appendChild(style);" + "})()"; mWebView.evaluateJavascript(css, null); } // 在onPageFinished中调用 @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); injectHighlightCSS(); injectHighlightJS(); // ... [其他] } ``` ### 关键修复点解析: 1. **布局重构**: - 使用`FrameLayout`代替`LinearLayout` - 按钮浮动在顶部(避免遮挡WebView) - WebView使用`match_parent`填充整个屏幕 2. **硬件加速修复**: ```java mWebView.setLayerType(View.LAYER_TYPE_HARDWARE, null); ``` 3. **DOM操作安全化**: - 使用`TreeWalker`代替直接操作`childNodes` - 添加CSS类代替直接修改`style` - 创建新的DOM元素代替修改`innerHTML` 4. **生命周期管理**: ```java @Override protected void onResume() { mWebView.onResume(); } ``` 5. **强制刷新机制**: ```java view.postDelayed(() -> { view.setVisibility(View.INVISIBLE); view.setVisibility(View.VISIBLE); }, 100); ``` ### 终极解决方案(如果以上无效): 在`AndroidManifest.xml`中添加: ```xml <application android:hardwareAccelerated="false" ...> ``` 这会全局禁用硬件加速,可能解决某些设备的兼容性问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值