具体思路:
点击imageButton后,调用系统相册,选择图片并进行裁剪,然后将图片数据存入mysql进行保存,随后通过读取数据将图片显示到ImageButton上

先上布局文件
Mainactivity.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">


    <ImageButton
    	android:id="@+id/imagebutton"
        android:layout_marginTop="50dp"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@mipmap/ic_launcher"
        android:background="#00FF0000"

        >

    </ImageButton>
    
</LinearLayout>

下面是主函数:

package com.example.image;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.print.PrinterId;
import android.provider.MediaStore;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;


import java.io.ByteArrayOutputStream;
import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class MainActivity extends AppCompatActivity {
//设置intent的返回码
    private final static int CODE_OF_GALLERY=2;
    private final static int CODE_OF_FINISH=3;
//声明用于存于和读取bitmap的资源    
    private Bitmap head;
    final static  String TAG="DBU";

    Handler handler;

//记得要在manifest中加读写权限
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        query(53);
        handler();
        setContentView(R.layout.activity_main);

//获取图片按钮
        final ImageButton imageButton=findViewById(R.id.imagebutton);


//        为图片按钮设置点击事件:打开本地照片文件夹
        imageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            //打开本地图库的函数,到这里,我们先来看一下这个函数,主要是这个函数怎么写的,然后调用就行了
                choseHeadimagefromGallery();

            }
        });
        
	}








//打开本地图库函数
    private  void choseHeadimagefromGallery(){
    //        这里的intent因为是调用系统文件夹这类资源,所以用Intent封装好的Intent.ACTION_PICK
        Intent intentfromGallery=new Intent(Intent.ACTION_PICK);
//            这里intent携带的数据是uri型

        intentfromGallery.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                "image/*");
//        设置intent携带的类型,固定的就那么几种,这里是选择图片用"image/*"。还有例如//        intent.setType(“audio/*”); 选择音频//        intent.setType(“video/*”); 选择视频(mp4 3gp 是android支持的视频格式)


        startActivityForResult(intentfromGallery,CODE_OF_GALLERY);
   *////    返回一个值代表这是从本地相册去图返回的活动
   *//     执行带返回值的intent要用staryActiityforresult
        
    }



*每次执行完intent都自动调用这个回调函数,根据返回码执行相应操作
    @Override
    protected void onActivityResult(int requestCode, int resultCode,  Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
		//传入返回码
        switch (requestCode){

//            调用本地相册的返回码的情况
            case CODE_OF_GALLERY:
//                从 返回码为CODE_OF_GALLERY的intent中取得数据,且该数据为uri型
                Uri uri=data.getData();
//                取得uri后,调用裁剪函数,把uri传进去,uri就是图片的全路径
                cropRawPhoto(uri);
                break;

//     CODE_OF_FINISH 是调用了裁剪函数的返回码,即每次调用完从本地图库选完图片的函数后,都会执行裁剪函数,而裁剪函数返回的这个返回码在这里执行
//            每当调用裁剪函数,都先从裁剪函数的intent中得到数据(都是通过intent传的数据,不管图片也好文字也好),数据类型是Bundle
            case CODE_OF_FINISH:
                ImageButton imageButton=findViewById(R.id.imagebutton);
//                先从裁剪函数的intent中得到数据,数据类型是Bundle
                Bundle bundle=data.getExtras();
                if(bundle!=null) {
//                这里的head是在全局中定义好的Bitmap类型的变量,从刚才获取的bundle调用getParcelable获得图片数据
                    head = bundle.getParcelable("data");

//                  这里开始将bitmap设置成圆形
                    RoundedBitmapDrawable roundedBitmapDrawable= 					  RoundedBitmapDrawableFactory.create(getResources(),head);
                    roundedBitmapDrawable.setCornerRadius(500);
                    roundedBitmapDrawable.setAntiAlias(true); //设置抗锯齿

//                    对imagebutton组件的图片进行更新,传入刚才设置好的圆形bitmap
                    imageButton.setImageDrawable(roundedBitmapDrawable);

//                    每次设置完头像都要把头像的图片数据写到数据库中,后期应该改为一开始有一个默认图片,每次选择完头像都是对原图片信息的更新
//                    开始传入数据库
//                    先把图片的bitmap类型数据转为string类型,这个方法总的来说就是先把bitmap转二进制数组,再通过base64转为string类型,别人做好的,注意数据库中存放图片信息的对应字段类型要设置为mediatext,不然长度不够
                    String string;
                    ByteArrayOutputStream bStream=new ByteArrayOutputStream();
                    head.compress(Bitmap.CompressFormat.PNG,100,bStream);
                    byte[]bytes=bStream.toByteArray();
                    string=Base64.encodeToString(bytes,Base64.DEFAULT);
                    
//                    调用写入数据库函数
                    link(string);
                }
                break;
        }
    }


//    这个函数是写死的基本不需要改动,这里是采取圆形的图片
//    裁剪函数的形参是uri,先根据intent的返回码执行将选取相册中图片intent中的uri数据取出,再传入裁剪函数
    public void cropRawPhoto(Uri uri){
        Intent intent=new Intent("com.android.camera.action.CROP");
//        裁剪调用系统自带的Intent

        intent.setDataAndType(uri,"image/*");

//        设计裁剪
        intent.putExtra("crop","true");

        intent.putExtra("aspectX",1);
        intent.putExtra("aspectY",1);

        intent.putExtra("outputX",180);
        intent.putExtra("outputY",180);
        intent.putExtra("return-data",true);
        /*记得start并返回返回码*/
        startActivityForResult(intent,CODE_OF_FINISH);
    }


//插入数据库函数
    public void link(String str){
        final String str2=str;
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
               DBUtiles.getConnection("img");
                try {
                //向数据库中插入bitmap图片 
                    DBUtiles.insert("img",str2);
                } catch (SQLException e) {
                    Log.d(TAG, e.getMessage());
                    e.printStackTrace();
                }
            }
        });
        thread.start();
    }




//注意这里,线程可以封装到函数里,这里查找函数通过查找用户id或者说这里暂时只是图片源id,把对应id的图片的string类型数据放到map里,然后由handler传出去
    public void query(final int id){

        Thread thread=new Thread(new Runnable() {
            HashMap<String,Object> map=new HashMap<String, Object>();
            @Override
            public void run() {
                    DBUtiles.getConnection("img");
                try {
                    map=DBUtiles.getinfo("img",id);

                } catch (SQLException e) {
                    e.printStackTrace();
                }
                Message message=Message.obtain();
                message.what=1;
                message.obj=map;
                handler.sendMessage(message);
            }
        });
            thread.start();

    }


//这里是处理query传出的string类型的图片源信息,并将string数据重新转为bitmap型并添加到imagebutton中
    @SuppressLint("HandlerLeak")
    public void handler(){

        handler=new Handler(){
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
                if (msg.what==1){
                    HashMap<String,Object> map= (HashMap<String, Object>) msg.obj;

                    String str= map.get("img").toString();


                        byte[] bitmapArray;
                        bitmapArray = Base64.decode(str, Base64.DEFAULT);
                        Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0,
                                bitmapArray.length);



//                        通过RoundedBitmapDrawable先把bitmap资源设置为圆形的
                        RoundedBitmapDrawable roundedBitmapDrawable= RoundedBitmapDrawableFactory.create(getResources(),bitmap);
                        roundedBitmapDrawable.setCornerRadius(500);
                        roundedBitmapDrawable.setAntiAlias(true); //设置抗锯齿
                        ImageButton imageButton=findViewById(R.id.imagebutton);

//                        这是设置成方形头像
//                        imageButton.setImageBitmap(bitmap);
//                    再传给imagebutton
                        imageButton.setImageDrawable(roundedBitmapDrawable);

                }
            }
        };
    }


}

下面说明一下程序跑的流程:
先点击imagebutton后,调用从本地图片库取图片的函数f1,f1携带一个返回码,程序会根据返回码去回调onActivityResult中的方法,根据f1的返回码,进行对应的操作,在这个程序中,在f1的返回码中调用裁剪函数,然后去调用裁剪函数,裁剪函数中也含有返回码,根据这个返回码,再回调onActivity
Result中的方法,即将裁剪好的图片取出并转为String类型存入数据库的方法。

而两个有关数据库的函数
插入函数的思路是:连接数据库后,插入数据
查询函数的思路是:查询数据库后,将查到的对象通过message和handler传出。查询函数的功能仅限于此

而显示图片的功能写在handler中,通过查询函数中handler出的message.what,获得message携带的数据库查询得到的数据,并将这个数据重新转为bitmap型并未imagebutton设置bitmap源

这里只是实现了更新,实际应用中,每当用户注册完毕或第一次登陆点击头像按钮后,便在数据库中创建一张与用户id关联的用户头像表(空表,仅有关联id和空的图片资源字段),用户更换头像应该用数据库的update功能,每次更新都如此,查询出并实时显示在操作界面上应每次登陆后都查询对应id的头像表中的图片字段并输出在页面上