Android 虹软人脸识别SDK-人脸对比

准备 :

登录官方网站,获取SDK,进行个人验证后新建项目,获取APP_ID,和SDK_KEY;

https://ai.arcsoft.com.cn/ucenter/resource/build/index.html#/ucenter/resource/openPlatform/application

实现 :

激活引擎 :

 /**
     * 激活引擎
     *
     * @param view
     */
    public void activeEngine(final View view) { if (!checkPermissions(NEEDED_PERMISSIONS)) { ActivityCompat.requestPermissions(this, NEEDED_PERMISSIONS, ACTION_REQUEST_PERMISSIONS); return; } if (view != null) { view.setClickable(false); } Observable.create(new ObservableOnSubscribe<Integer>() { @Override public void subscribe(ObservableEmitter<Integer> emitter) throws Exception { FaceEngine faceEngine = new FaceEngine(); //申请的APP_ID 和SDK_key int activeCode = faceEngine.active(FaceMainActivity.this, Constants.APP_ID, Constants.SDK_KEY); emitter.onNext(activeCode); } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<Integer>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(Integer activeCode) { if (activeCode == ErrorInfo.MOK) { showToast("OK"); } else if (activeCode == ErrorInfo.MERR_ASF_ALREADY_ACTIVATED) { showToast("Not Active"); } else { showToast("shibai"); } if (view != null) { view.setClickable(true); } } @Override public void onError(Throwable e) { } @Override public void onComplete() { } }); } 

初始化引擎 :

    private void initEngine() { faceEngine = new FaceEngine(); faceEngineCode = faceEngine.init(this, FaceEngine.ASF_DETECT_MODE_IMAGE, FaceEngine.ASF_OP_0_HIGHER_EXT, 16, 10, FaceEngine.ASF_FACE_RECOGNITION | FaceEngine.ASF_FACE_DETECT | FaceEngine.ASF_AGE | FaceEngine.ASF_GENDER | FaceEngine.ASF_FACE3DANGLE | FaceEngine.ASF_LIVENESS); VersionInfo versionInfo = new VersionInfo(); faceEngine.getVersion(versionInfo); Log.i(TAG, "initEngine: init: " + faceEngineCode + " version:" + versionInfo); if (faceEngineCode != ErrorInfo.MOK) { Toast.makeText(this, "TEST", Toast.LENGTH_SHORT).show(); } }

注册相机事件 :

  button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) { File outImage = new File(getExternalCacheDir(), "output_image.jpg"); try { if (outImage.exists()) { outImage.delete(); } outImage.createNewFile(); } catch (IOException e) { e.printStackTrace(); } if (Build.VERSION.SDK_INT >= 24) { uri = FileProvider.getUriForFile(FaceMainActivity.this, "com.example.gdzc.cameraalbumtest.fileprovider", outImage); } else { uri = Uri.fromFile(outImage); } Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(intent, TAKE_POTHO); } }); 

显示提示返回结果信息 :

 /**
     * 展示提示信息并且关闭提示框
     *
     * @param stringBuilder 带格式的提示文字
     */
    private void showNotificationAndFinish(final SpannableStringBuilder stringBuilder) { runOnUiThread(new Runnable() { @Override public void run() { if (tvNotice != null) { tvNotice.setText(stringBuilder.toString()); } if (progressDialog != null && progressDialog.isShowing()) { progressDialog.dismiss(); } } }); } /** * 追加提示信息 * * @param stringBuilder 提示的字符串的存放对象 * @param styleSpan 添加的字符串的格式 * @param strings 字符串数组 */ private void addNotificationInfo(SpannableStringBuilder stringBuilder, ParcelableSpan styleSpan, String... strings) { tvNotice.append(stringBuilder.toString()); if (stringBuilder == null || strings == null || strings.length == 0) { return; } int startLength = stringBuilder.length(); for (String string : strings) { stringBuilder.append(string); } int endLength = stringBuilder.length(); if (styleSpan != null) { stringBuilder.setSpan(styleSpan, startLength, endLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } }

人脸验证 :

首先人脸验证需要一个参照的人脸数据,与之后的人脸进行匹配,返回结果为通过与不通过。

 //人脸比对数据显示
            if (faceInfoList.size() > 0) {
                if (type == TYPE_MAIN) {
                    int size = showInfoList.size(); showInfoList.clear(); showInfoAdapter.notifyItemRangeRemoved(0, size); ivMainImage.setImageBitmap(mainBitmap); mainFeature = new FaceFeature(); int res = faceEngine.extractFaceFeature(nv21, width, height, FaceEngine.CP_PAF_NV21, faceInfoList.get(0), mainFeature); if (res != ErrorInfo.MOK) { mainFeature = null; } ivMainImage.setImageBitmap(bitmap); StringBuilder stringBuilder = new StringBuilder(); if (faceInfoList.size() > 0) { stringBuilder.append("face info:\n\n"); } for (int i = 0; i < faceInfoList.size(); i++) { stringBuilder.append("face[") .append(i) .append("]:\n") .append(faceInfoList.get(i)) .append("\nage:") .append(ageInfoList.get(i).getAge()) .append("\ngender:") .append(genderInfoList.get(i).getGender() == GenderInfo.MALE ? "MALE" : (genderInfoList.get(i).getGender() == GenderInfo.FEMALE ? "FEMALE" : "UNKNOWN")) .append("\nface3DAngle:") .append(face3DAngleList.get(i)) .append("\n\n"); } tvMainImageInfo.setText(stringBuilder); } else if (type == TYPE_ITEM) { FaceFeature faceFeature = new FaceFeature(); int res = faceEngine.extractFaceFeature(nv21, width, height, FaceEngine.CP_PAF_NV21, faceInfoList.get(0), faceFeature); if (res == 0) { FaceSimilar faceSimilar = new FaceSimilar(); int compareResult = faceEngine.compareFaceFeature(mainFeature, faceFeature, faceSimilar); if (compareResult == ErrorInfo.MOK) { String resStr = ""; BigDecimal bigDecimal = new BigDecimal(faceSimilar.getScore()); if (bigDecimal.compareTo(new BigDecimal(0.8)) >= 0) { resStr = "通过"; }else{ resStr = "不通过"; } ItemShowInfo showInfo = new ItemShowInfo(bitmap, ageInfoList.get(0).getAge(), genderInfoList.get(0).getGender(), faceSimilar.getScore(),resStr); showInfoList.add(showInfo); showInfoAdapter.notifyItemInserted(showInfoList.size() - 1); } else { showToast("error"); } } } } else { if (type == TYPE_MAIN) { mainBitmap = null; } } } else { showToast("can not get nv21 from bitmap!"); }

通过对比结果,对比结果值越接近1就越相似,此处识别通过标准为0.8。

代码 :

对比 :

package com.example.ttlock.activity;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.MediaStore; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v4.content.FileProvider; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; import android.view.WindowManager; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import com.arcsoft.face.AgeInfo; import com.arcsoft.face.ErrorInfo; import com.arcsoft.face.Face3DAngle; import com.arcsoft.face.FaceEngine; import com.arcsoft.face.FaceFeature; import com.arcsoft.face.FaceInfo; import com.arcsoft.face.FaceSimilar; import com.arcsoft.face.GenderInfo; import com.example.ttlock.R; import com.example.ttlock.adapter.widget.ShowInfoAdapter; import com.example.ttlock.model.ItemShowInfo; import com.example.ttlock.utils.ImageUtil; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class MultiImageActivity extends AppCompatActivity { private static final String TAG = "MultiImageActivity"; private static final int ACTION_CHOOSE_MAIN_IMAGE = 0x201; private static final int ACTION_ADD_RECYCLER_ITEM_IMAGE = 0x202; public static final int TAKE_POTHO = 1; private static final int ACTION_REQUEST_PERMISSIONS = 0x001; private Uri uri; private ImageView ivMainImage; private TextView tvMainImageInfo; /** * 选择图片时的类型 */ private int TYPE_MAIN = 0; private int TYPE_ITEM = 1; /** * 主图的第0张人脸的特征数据 */ private FaceFeature mainFeature; private ShowInfoAdapter showInfoAdapter; private List<ItemShowInfo> showInfoList; private FaceEngine faceEngine; private int faceEngineCode = -1; private Bitmap mainBitmap; Toast toast = null; private static String[] NEEDED_PERMISSIONS = new String[]{ Manifest.permission.READ_PHONE_STATE }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setContentView(R.layout.activity_multi_image); /** * 在选择图片的时候,在android 7.0及以上通过FileProvider获取Uri,不需要文件权限 */ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { List<String> permissionList = new ArrayList<>(Arrays.asList(NEEDED_PERMISSIONS)); permissionList.add(Manifest.permission.READ_EXTERNAL_STORAGE); NEEDED_PERMISSIONS = permissionList.toArray(new String[0]); } if (!checkPermissions(NEEDED_PERMISSIONS)) { ActivityCompat.requestPermissions(this, NEEDED_PERMISSIONS, ACTION_REQUEST_PERMISSIONS); } else { initEngine(); } initView(); } private void initView() { ivMainImage = findViewById(R.id.iv_main_image); tvMainImageInfo = findViewById(R.id.tv_main_image_info); RecyclerView recyclerFaces = findViewById(R.id.recycler_faces); showInfoList = new ArrayList<>(); showInfoAdapter = new ShowInfoAdapter(showInfoList, this); recyclerFaces.setAdapter(showInfoAdapter); recyclerFaces.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL)); recyclerFaces.setLayoutManager(new LinearLayoutManager(this)); } private void initEngine() { faceEngine = new FaceEngine(); faceEngineCode = faceEngine.init(this, FaceEngine.ASF_DETECT_MODE_IMAGE, FaceEngine.ASF_OP_0_HIGHER_EXT, 16, 6, FaceEngine.ASF_FACE_RECOGNITION | FaceEngine.ASF_AGE | FaceEngine.ASF_FACE_DETECT | FaceEngine.ASF_GENDER | FaceEngine.ASF_FACE3DANGLE); Log.i(TAG, "initEngine: init " + faceEngineCode); if (faceEngineCode != ErrorInfo.MOK) { Toast.makeText(this, "f", Toast.LENGTH_SHORT).show(); } } private void unInitEngine() { if (faceEngine != null) { faceEngineCode = faceEngine.unInit(); Log.i(TAG, "unInitEngine: " + faceEngineCode); } } @Override protected void onDestroy() { unInitEngine(); super.onDestroy(); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); // // if (data == null || data.getData() == null) { // showToast("failed"); // return; // } // if (requestCode == ACTION_CHOOSE_MAIN_IMAGE) { // mainBitmap = ImageUtil.getBitmapFromUri(data.getData(), this); // if (mainBitmap == null) { // showToast("failed"); // return; // } // processImage(mainBitmap, TYPE_MAIN); // } else if (requestCode == ACTION_ADD_RECYCLER_ITEM_IMAGE) { // Bitmap bitmap = ImageUtil.getBitmapFromUri(data.getData(), this); // if (bitmap == null) { // showToast("failed"); // return; // } // if (mainFeature == null) { // return; // } // processImage(bitmap, TYPE_ITEM); // } switch (requestCode) { case ACTION_CHOOSE_MAIN_IMAGE: try { mainBitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri)); // imageView.setImageBitmap(mBitmap); //将图片解析成Bitmap对象,并把它显现出来 processImage(mainBitmap, TYPE_MAIN); } catch (FileNotFoundException e) { e.printStackTrace(); } break; case ACTION_ADD_RECYCLER_ITEM_IMAGE: Bitmap bitmap = null; try { bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri)); } catch (FileNotFoundException e) { e.printStackTrace(); } if (bitmap == null) { showToast("failed"); return; } if (mainFeature == null) { return; } processImage(bitmap, TYPE_ITEM); default: break; } } public void processImage(Bitmap bitmap, int type) { if (bitmap == null) { return; } if (faceEngine == null) { return; } //NV21宽度必须为4的倍数,高度为2的倍数 bitmap = ImageUtil.alignBitmapForNv21(bitmap); if (bitmap == null) { return; } int width = bitmap.getWidth(); int height = bitmap.getHeight(); //bitmap转NV21 final byte[] nv21 = ImageUtil.bitmapToNv21(bitmap, width, height); if (nv21 != null) { List<FaceInfo> faceInfoList = new ArrayList<>(); //人脸检测 int detectCode = faceEngine.detectFaces(nv21, width, height, FaceEngine.CP_PAF_NV21, faceInfoList); if (detectCode != 0 || faceInfoList.size() == 0) { showToast("face detection finished, code is " + detectCode + ", face num is " + faceInfoList.size()); return; } //绘制bitmap bitmap = bitmap.copy(Bitmap.Config.RGB_565, true); Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(); paint.setAntiAlias(true); paint.setStrokeWidth(10); paint.setColor(Color.YELLOW); if (faceInfoList.size() > 0) { for (int i = 0; i < faceInfoList.size(); i++) { //绘制人脸框 paint.setStyle(Paint.Style.STROKE); canvas.drawRect(faceInfoList.get(i).getRect(), paint); //绘制人脸序号 paint.setStyle(Paint.Style.FILL_AND_STROKE); paint.setTextSize(faceInfoList.get(i).getRect().width() / 2); canvas.drawText("" + i, faceInfoList.get(i).getRect().left, faceInfoList.get(i).getRect().top, paint); } } int faceProcessCode = faceEngine.process(nv21, width, height, FaceEngine.CP_PAF_NV21, faceInfoList, FaceEngine.ASF_AGE | FaceEngine.ASF_GENDER | FaceEngine.ASF_FACE3DANGLE); Log.i(TAG, "processImage: " + faceProcessCode); if (faceProcessCode != ErrorInfo.MOK) { showToast("face process finished, code is " + faceProcessCode); return; } //年龄信息结果 List<AgeInfo> ageInfoList = new ArrayList<>(); //性别信息结果 List<GenderInfo> genderInfoList = new ArrayList<>(); //三维角度结果 List<Face3DAngle> face3DAngleList = new ArrayList<>(); //获取年龄、性别、三维角度 int ageCode = faceEngine.getAge(ageInfoList); int genderCode = faceEngine.getGender(genderInfoList); int face3DAngleCode = faceEngine.getFace3DAngle(face3DAngleList); if ((ageCode | genderCode | face3DAngleCode) != ErrorInfo.MOK) { showToast("at lease one of age、gender、face3DAngle detect failed! codes are: " + ageCode + " ," + genderCode + " ," + face3DAngleCode); return; } //人脸比对数据显示 if (faceInfoList.size() > 0) { if (type == TYPE_MAIN) { int size = showInfoList.size(); showInfoList.clear(); showInfoAdapter.notifyItemRangeRemoved(0, size); ivMainImage.setImageBitmap(mainBitmap); mainFeature = new FaceFeature(); int res = faceEngine.extractFaceFeature(nv21, width, height, FaceEngine.CP_PAF_NV21, faceInfoList.get(0), mainFeature); if (res != ErrorInfo.MOK) { mainFeature = null; } ivMainImage.setImageBitmap(bitmap); StringBuilder stringBuilder = new StringBuilder(); if (faceInfoList.size() > 0) { stringBuilder.append("face info:\n\n"); } for (int i = 0; i < faceInfoList.size(); i++) { stringBuilder.append("face[") .append(i) .append("]:\n") .append(faceInfoList.get(i)) .append("\nage:") .append(ageInfoList.get(i).getAge()) .append("\ngender:") .append(genderInfoList.get(i).getGender() == GenderInfo.MALE ? "MALE" : (genderInfoList.get(i).getGender() == GenderInfo.FEMALE ? "FEMALE" : "UNKNOWN")) .append("\nface3DAngle:") .append(face3DAngleList.get(i)) .append("\n\n"); } tvMainImageInfo.setText(stringBuilder); } else if (type == TYPE_ITEM) { FaceFeature faceFeature = new FaceFeature(); int res = faceEngine.extractFaceFeature(nv21, width, height, FaceEngine.CP_PAF_NV21, faceInfoList.get(0), faceFeature); if (res == 0) { FaceSimilar faceSimilar = new FaceSimilar(); int compareResult = faceEngine.compareFaceFeature(mainFeature, faceFeature, faceSimilar); if (compareResult == ErrorInfo.MOK) { String resStr = ""; BigDecimal bigDecimal = new BigDecimal(faceSimilar.getScore()); if (bigDecimal.compareTo(new BigDecimal(0.8)) >= 0) { resStr = "通过"; }else{ resStr = "不通过"; } ItemShowInfo showInfo = new ItemShowInfo(bitmap, ageInfoList.get(0).getAge(), genderInfoList.get(0).getGender(), faceSimilar.getScore(),resStr); showInfoList.add(showInfo); showInfoAdapter.notifyItemInserted(showInfoList.size() - 1); } else { showToast("error"); } } } } else { if (type == TYPE_MAIN) { mainBitmap = null; } } } else { showToast("can not get nv21 from bitmap!"); } } /** * 从本地选择文件 * * @param action 可为选择主图{@link #ACTION_CHOOSE_MAIN_IMAGE}或者选择item图{@link #ACTION_ADD_RECYCLER_ITEM_IMAGE} */ public void chooseLocalImage(int action) { // Intent intent = new Intent(Intent.ACTION_PICK); // intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*"); // startActivityForResult(intent, action); File outImage = new File(getExternalCacheDir(), "output_image.jpg"); try { if (outImage.exists()) { outImage.delete(); } outImage.createNewFile(); } catch (IOException e) { e.printStackTrace(); } if (Build.VERSION.SDK_INT >= 24) { uri = FileProvider.getUriForFile(MultiImageActivity.this, "com.example.gdzc.cameraalbumtest.fileprovider", outImage); } else { uri = Uri.fromFile(outImage); } Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(intent, action); } public void addItemFace(View view) { if (faceEngineCode != ErrorInfo.MOK) { showToast("引擎未初始化,错误码为" + faceEngineCode); return; } if (mainBitmap == null) { showToast("\"请先选择主图\""); return; } chooseLocalImage(ACTION_ADD_RECYCLER_ITEM_IMAGE); } public void chooseMainImage(View view) { if (faceEngineCode != ErrorInfo.MOK) { showToast("引擎未初始化,错误码为" + faceEngineCode); return; } chooseLocalImage(ACTION_CHOOSE_MAIN_IMAGE); } private void showToast(String s) { if (toast == null) { toast = Toast.makeText(this, s, Toast.LENGTH_SHORT); toast.show(); } else { toast.setText(s); toast.show(); } } private boolean checkPermissions(String[] neededPermissions) { if (neededPermissions == null || neededPermissions.length == 0) { return true; } boolean allGranted = true; for (String neededPermission : neededPermissions) { allGranted &= ContextCompat.checkSelfPermission(this, neededPermission) == PackageManager.PERMISSION_GRANTED; } return allGranted; } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == ACTION_REQUEST_PERMISSIONS) { boolean isAllGranted = true; for (int grantResult : grantResults) { isAllGranted &= (grantResult == PackageManager.PERMISSION_GRANTED); } if (isAllGranted) { initEngine(); } else { showToast("权限被拒绝"); } } } } 
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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="wrap_content" android:orientation="vertical" tools:context=".activity.MultiImageActivity"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_margin="20dp" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center"> <Button android:id="@+id/bt_choose_main_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="chooseMainImage" android:text="注册"/> <ImageView android:id="@+id/iv_main_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:minHeight="100dp" android:maxHeight="200dp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tv_main_image_info"/> </LinearLayout> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#88000000"/> <LinearLayout android:layout_margin="20dp" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center"> <Button android:id="@+id/bt_add_item" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="addItemFace" android:text="验证"/> <android.support.v7.widget.RecyclerView android:minHeight="300dp" android:id="@+id/recycler_faces" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> </LinearLayout> </ScrollView>

RecyclerView 适配器:

package com.example.ttlock.adapter.widget;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.example.ttlock.R; import com.example.ttlock.model.ItemShowInfo; import java.util.List; public class ShowInfoAdapter extends RecyclerView.Adapter<ShowInfoAdapter.ShowInfoHolder> { private List<ItemShowInfo> showInfoList; private LayoutInflater inflater; public ShowInfoAdapter(List<ItemShowInfo> showInfoList, Context context) { this.showInfoList = showInfoList; this.inflater = LayoutInflater.from(context); } @NonNull @Override public ShowInfoHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { View itemView = inflater.inflate(R.layout.item_show_info, viewGroup, false); ImageView ivHeadImage = itemView.findViewById(R.id.iv_item_head_img); TextView tvNotification = itemView.findViewById(R.id.tv_item_notification); ShowInfoHolder holder = new ShowInfoHolder(itemView); holder.ivHeadImage = ivHeadImage; holder.tvNotification = tvNotification; return holder; } @Override public void onBindViewHolder(@NonNull ShowInfoHolder showInfoHolder, int i) { showInfoHolder.tvNotification.setText(showInfoList.get(i).getIsOk()); showInfoHolder.ivHeadImage.setImageBitmap(showInfoList.get(i).getBitmap()); } @Override public int getItemCount() { return showInfoList==null?0:showInfoList.size(); } class ShowInfoHolder extends RecyclerView.ViewHolder{ ImageView ivHeadImage; TextView tvNotification; ShowInfoHolder(@NonNull View itemView) { super(itemView); } } } 
<?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="110dp" android:paddingTop="10dp" android:orientation="horizontal"> <ImageView android:id="@+id/iv_item_head_img" android:layout_margin="10dp" android:layout_width="80dp" android:layout_height="80dp" /> <TextView android:layout_gravity="center_vertical" android:id="@+id/tv_item_notification" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> 

item :

package com.example.ttlock.model;

import android.graphics.Bitmap;

import com.arcsoft.face.GenderInfo;


public class ItemShowInfo { private Bitmap bitmap; private int age; private int gender; private float similar; private String isOk; public ItemShowInfo() { } public ItemShowInfo(Bitmap bitmap, int age, int gender, float similar, String isOk) { this.bitmap = bitmap; this.age = age; this.gender = gender; this.similar = similar; this.isOk = isOk; } public String getIsOk() { return isOk; } public void setIsOk(String isOk) { this.isOk = isOk; } public Bitmap getBitmap() { return bitmap; } public void setBitmap(Bitmap bitmap) { this.bitmap = bitmap; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getGender() { return gender; } public void setGender(int gender) { this.gender = gender; } public float getSimilar() { return similar; } public void setSimilar(float similar) { this.similar = similar; } @Override public String toString() { return " age=" + age + ", gender=" + (gender == GenderInfo.MALE ? "MALE" : (gender == GenderInfo.FEMALE ? "FEMALE" : "UNKNOWN")) + ", similar=" + similar; } }

猜你喜欢

转载自www.cnblogs.com/yangchaojie/p/11102361.html