android
配置
使用 android studio 的时候使用gradle同步的时候,如果配置了socket proxy,那么gradle同步时,会提示是否要设置gradle的配置,这时候要点取消,否则会报错表示socket连接有问题
android camera2 api
框架
操作API
mContext.getSystemService(Context.CAMERA_SERVICE);
用于获取系统的cameraManager
id = mCameraManager.getCameraIdList()
mCameraManager.getCameraCharacteristics(id)
选择不同的摄像头
mCameraManager.openCamera(mCameraId, mStateCallback, null);
根据id打开摄像头,并设置callback,callback决定了摄像头不同状态时会触发什么函数
1
2
3
4
5
6
7
8
9
10
11
12private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
public void onOpened(@NonNull CameraDevice cameraDevice) {
// 打开相机时调用此方法。 在这里开始相机预览。
mCameraDevice = cameraDevice;
//创建CameraPreviewSession
Log.i(TAG, "onOpened: before createCameraPreviewSession");
createCameraPreviewSession();
Log.i(TAG, "onOpened: after createCameraPreviewSession");
}
}createCameraPreviewSession()
根据captureRequestBuilder的设置,通过manager设置一个 caputrueSession,不断发送请求。
createCaptureSession
设定了返回的值的数据1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mCaptureRequestBuilder.addTarget(mSurface);
mCaptureRequestBuilder.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE, CameraMetadata.STATISTICS_FACE_DETECT_MODE_FULL);
mCameraDevice.createCaptureSession(Collections.singletonList(mSurface), new CameraCaptureSession.StateCallback() {
public void onConfigured(@NonNull CameraCaptureSession session) {
//构建captureRequest对象
//设置人脸检测
// 会话准备好后,我们开始显示预览
mCaptureSession = session;
try {
// 自动对焦
mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// 最终开启相机预览并添加事件
mPreviewRequest = mCaptureRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest,
mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}CameraCaptureSession.CaptureCallback mCaptureCallback
根据callback设定返回的结果和如何处理(有一部分
1
2
3
4
5
6
7
8private final CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() {
/**
* 对摄像头返回的结果进行处理,并获取人脸数据
* @param result 摄像头数据
*/
private void process(CaptureResult result) {
// do something
}
网络通信
请求到http服务器,并通过post请求发送图片数据
注意事项:不要在主进程发送http请求,会报错解决方法1. 通过handler创建新的进程 2. 用方法忽略掉
1
2
3
4
5(Build.VERSION_CODES.GINGERBREAD)
"NewApi") (
// function
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);将bitmap 压缩成png图片,并且转码为base64字符串,用utf-8编码(注意,如果不用utf-8编码,在post的时候有些特殊字符会变成空格,比如+会变成空格)
1
2
3
4
5
6
7
8
9
10baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
baos.flush();
baos.close();
byte[] bitmapBytes = baos.toByteArray();
result = Base64.encodeToString(bitmapBytes, Base64.DEFAULT);
String key = URLEncoder.encode(encoded, "utf-8");
return key将base64字符串发送到服务器,并接受返回文本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31// input string, url_adress
URL url = new URL(url_adress);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(50000);//超时时间
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
out.write(string);
out.flush();
out.close();
InputStream inputStream = conn.getInputStream();
byte[] data = StreamTool.read(inputStream);
html = new String(data, "utf-8");
return html;
class StreamTool {
public static byte[] read(InputStream inStream) throws Exception {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, len);
}
inStream.close();
return outStream.toByteArray();
}
}
多线程编程
因为非主线程不能修改ui界面,所以操作非主线程需要让一个主进程的handler来修改主线程的内容
实现一个集成Thread的类,override其中的run()
如果需要将信息返回到主进程修改界面
1
2
3
4
5
6
7
8
9
10
11
12
13private Handler uiHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
mTextView.setText("face");
}
};
// ......
Message msg = new Message();
msg.what = 0;
msg.arg1 = response;
uiHandler.sendMessage(msg);
列表 listview
自定义item的格式
首先需要一个xml文件描述item
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="15dp">
<ImageView
android:id="@+id/IamgeView_List"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#FFFFFF" />
<TextView
android:id="@+id/TextView_List"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="30dp"
android:text="内容"
android:textSize="30sp" />
</LinearLayout>
自定义listAdapter
1 | public class ImageListAdapter extends ArrayAdapter<ImageListArray> { |
显示list的内容
1 | ImageListAdapter imageListAdapter = new ImageListAdapter(MainActivity.this, R.layout.item_layout, imageList); |
fragment
fragment是一种较为方便讲每个显示的界面模块化的方法
生命周期
生成fragment的同时调用其中的控件
如果想在生成fragment的时候获取fragment中的resource(比如listView),则必须在onCreateView()之后,通过view.findViewByID才可以找得到,代码如下1
2
3
4
5
6
7
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_record_layout, container, false);
mListView = view.findViewById(R.id.img_listview);
return view;
}
fragment的静态引用
注意这一段必须在一个layout里面1
2
3
4
5
6<fragment
android:id="@+id/fragment_record"
android:name="com.zhu.driveractionrecognition.RecordFragmentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" />
其中name表示了这个fragment对应的类的类名