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

Android:Fragment内CircleImageView图片的SQLite存储读取问题

问题分析

你的核心问题集中在三个方面:

  • 保存时没有传入默认图片的Bitmap,直接传了null导致数据库图片字段为空,读取时触发崩溃
  • DatabaseHelper的getBitmapAsByteArray方法未处理null参数,会引发空指针异常
  • 读取图片时没有判断Blob是否为空,直接解码导致崩溃

下面是分步解决方案,附带修改后的完整代码:


1. 全局维护当前头像的Bitmap

在Fragment中声明全局变量,用来记录当前使用的头像(默认图或用户选择的图片),确保保存时能拿到正确的Bitmap:

private Bitmap mCurrentProfileBitmap;
private CircleImageView mProfilePhoto;
private EditText mNameInput; // 假设你有输入用户名的EditText

然后在onViewCreated中初始化默认图片:

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    mProfilePhoto = view.findViewById(R.id.your_circle_image_view_id);
    mNameInput = view.findViewById(R.id.your_username_input_id);
    
    // 加载默认图片到全局变量,初始化头像显示
    mCurrentProfileBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.default_profile_image);
    mProfilePhoto.setImageBitmap(mCurrentProfileBitmap);
}

2. 修复onActivityResult,更新全局Bitmap

修改相册选择后的逻辑,把选中的图片赋值给全局变量,确保后续保存时能拿到:

@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode == 0 && resultCode == Activity.RESULT_OK && data != null) { 
        Uri path = data.getData(); 
        try { 
            mCurrentProfileBitmap = MediaStore.Images.Media.getBitmap(getContext().getContentResolver(), path);
            mProfilePhoto.setImageBitmap(mCurrentProfileBitmap); 
        } catch (IOException e) { 
            e.printStackTrace();
            // 图片加载失败时恢复默认图
            mCurrentProfileBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.default_profile_image);
            mProfilePhoto.setImageBitmap(mCurrentProfileBitmap);
        } 
    }
}

3. 修复保存按钮的逻辑

点击保存时传入全局的mCurrentProfileBitmap,不再传null:

@Override 
public void onClick(View v) { 
    switch (v.getId()){ 
        case R.id.saveProfileButton: 
            String username = mNameInput.getText().toString().trim();
            if(!username.isEmpty()){
                // 传入当前维护的头像Bitmap
                addUserInformation(username, mCurrentProfileBitmap); 
            } else {
                toastMessage("请输入用户名");
            }
            break; 
        case R.id.profile_photo: 
            Intent i = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); 
            try { 
                startActivityForResult(Intent.createChooser(i, "Select Picture"), 0); 
            }catch (ActivityNotFoundException ex){ 
                ex.printStackTrace(); 
            } 
            break; 
    } 
}

4. 修复DatabaseHelper的空Bitmap处理

修改getBitmapAsByteArray方法,避免传入null时崩溃,同时优化图片压缩质量(0会严重失真,推荐80):

private static byte[] getBitmapAsByteArray(Bitmap bitmap) { 
    if(bitmap == null){
        return null;
    }
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 
    // 调整压缩质量,平衡图片清晰度和大小
    bitmap.compress(Bitmap.CompressFormat.PNG, 80, outputStream); 
    return outputStream.toByteArray(); 
}

同时优化addUserInformation方法,单用户场景下避免重复插入数据:

public boolean addUserInformation(String username, Bitmap picture){ 
    if(username == null || username.trim().isEmpty()){
        return false;
    }
    SQLiteDatabase db = this.getWritableDatabase(); 
    ContentValues values = new ContentValues(); 
    values.put("USERNAME", username.trim()); 
    byte[] data = getBitmapAsByteArray(picture); 
    if(data != null){
        values.put("PICTURE", data); 
    }

    // 单用户场景:先清空旧数据再插入,避免多条记录
    db.delete(TABLE_NAME1, null, null);
    long id = db.insert(TABLE_NAME1, null, values); 
    db.close(); 
    return id != -1; 
}

5. 修复读取图片的崩溃问题

读取时先判断Blob是否存在,再解码,避免空指针:

private void getUserInformation(){ 
    Cursor data = databaseHelper.getUserInformation(); 
    if(data != null && data.moveToFirst()) { 
        // 先获取Blob字段,判断是否有效
        byte[] blobData = data.getBlob(2);
        if(blobData != null && blobData.length > 0){
            Bitmap bitmap = BitmapFactory.decodeByteArray(blobData, 0, blobData.length); 
            if(bitmap != null) {
                mCurrentProfileBitmap = bitmap;
                mProfilePhoto.setImageBitmap(bitmap);
            } else {
                // 解码失败,显示默认图
                resetToDefaultProfile();
            }
        } else {
            // 数据库无图片数据,显示默认图
            resetToDefaultProfile();
        }
        mProfileName = data.getString(1); 
    } else {
        // 无用户数据,显示默认状态
        resetToDefaultProfile();
        mProfileName = "";
    }
    if(data != null){
        data.close(); 
    }
}

// 封装重置默认头像的方法,减少重复代码
private void resetToDefaultProfile(){
    mCurrentProfileBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.default_profile_image);
    mProfilePhoto.setImageBitmap(mCurrentProfileBitmap);
}

别忘了确保DatabaseHelper中有正确的查询方法:

// 在DatabaseHelper中添加该方法(如果还没有)
public Cursor getUserInformation(){
    SQLiteDatabase db = this.getReadableDatabase();
    return db.query(TABLE_NAME1, null, null, null, null, null, null);
}

额外建议

  • SQLite存储Bitmap的局限性:Bitmap转Blob后体积可能较大,频繁读写会影响性能,实际项目中更推荐存储图片的本地文件路径,而非直接存Blob(仅小尺寸头像可考虑Blob)。
  • 内存优化:如果用户选择的图片尺寸很大,建议先压缩再存储,避免内存溢出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:56:41