具体思路:
点击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的头像表中的图片字段并输出在页面上