You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中JavascriptInterface读取SQLite数据库崩溃问题求助

解决Android WebView调用JavascriptInterface读取SQLite崩溃问题

1. 禁止在主线程执行数据库操作

WebView的JavascriptInterface方法默认在主线程触发,直接在此方法内读写SQLite会阻塞UI线程,大概率引发ANR或崩溃。

解决方式:将数据库操作转移到子线程,通过Handler回调将结果返回给JS:

public class MyJavascriptInterface {
    private Context mContext;
    private Handler mMainHandler = new Handler(Looper.getMainLooper());
    private WebView mWebView;

    public MyJavascriptInterface(Context context, WebView webView) {
        mContext = context;
        mWebView = webView;
    }

    @JavascriptInterface
    public void fetchDbData(final String jsCallback) {
        new Thread(() -> {
            DataBaseHelper dbHelper = new DataBaseHelper(mContext);
            SQLiteDatabase db = dbHelper.getReadableDatabase();
            StringBuilder dataResult = new StringBuilder();
            
            try (Cursor cursor = db.rawQuery("SELECT * FROM your_table", null)) {
                if (cursor.moveToFirst()) {
                    do {
                        String value = cursor.getString(cursor.getColumnIndex("target_column"));
                        dataResult.append(value).append(",");
                    } while (cursor.moveToNext());
                }
            } catch (Exception e) {
                dataResult.append("Error: ").append(e.getMessage());
                e.printStackTrace();
            } finally {
                db.close();
            }
            
            // 切回主线程调用JS回调
            mMainHandler.post(() -> {
                mWebView.loadUrl("javascript:" + jsCallback + "('" + dataResult.toString() + "')");
            });
        }).start();
    }
}

2. 校验JavascriptInterface的核心要求

  • 接口方法必须添加@JavascriptInterface注解(Android 4.2及以上强制要求,否则JS无法调用)
  • 方法权限必须为public,private/protected方法会直接触发调用失败或崩溃

3. 确认数据库路径与初始化逻辑

检查DataBaseHelper的数据库路径是否正确,避免因找不到数据库文件引发崩溃:

public class DataBaseHelper extends SQLiteOpenHelper {
    private static final String DB_NAME = "app_db.db";
    private static final int DB_VERSION = 1;
    private Context mContext;

    public DataBaseHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
        mContext = context;
        copyDefaultDbIfNeeded();
    }

    private void copyDefaultDbIfNeeded() {
        File dbFile = mContext.getDatabasePath(DB_NAME);
        if (!dbFile.exists()) {
            try (InputStream in = mContext.getAssets().open(DB_NAME);
                 OutputStream out = new FileOutputStream(dbFile)) {
                byte[] buffer = new byte[1024];
                int len;
                while ((len = in.read(buffer)) != -1) {
                    out.write(buffer, 0, len);
                }
            } catch (IOException e) {
                throw new RuntimeException("Failed to copy default database", e);
            }
        }
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // 首次创建数据库的表结构(如果不需要拷贝默认库则实现此方法)
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // 数据库版本升级逻辑
    }
}

4. 确保WebView操作的线程安全

  • 所有WebView相关的API调用必须在主线程执行,包括loadUrl、evaluateJavascript
  • Android 4.4+推荐使用evaluateJavascript替代loadUrl,避免URL编码问题:
mMainHandler.post(() -> {
    mWebView.evaluateJavascript(String.format("%s('%s')", jsCallback, dataResult.toString()), null);
});

5. 添加异常捕获定位问题

在数据库操作和JS接口方法中加入try-catch,打印崩溃日志快速定位根因:

@JavascriptInterface
public void fetchDbData(final String jsCallback) {
    new Thread(() -> {
        try {
            // 数据库操作逻辑
        } catch (Exception e) {
            e.printStackTrace();
            mMainHandler.post(() -> {
                mWebView.loadUrl("javascript:" + jsCallback + "('Crash: " + e.getMessage() + "')");
            });
        }
    }).start();
}

内容的提问来源于stack exchange,提问作者Lo Dennis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 21:45:01