代码只是解决特定问题的方法,并未深入研究每一个方法的原理,仅作为自身积累所用。如果对你有启发,请点赞哦。
1. 使用Gson解析自定义javabean
①.中括号开头的json
Type listType = new TypeToken<List<User>>(){}.getType();
Gson gson = new Gson();
List<User> users = gson.fromJson(jsonData, listType);
②.大括号开头的json
Gson gson = new Gson();
User user = gson.fromJson(jsonData, User.class);
2. 使用httpclient上传图文混合信息给服务器,httpclient在android6.0系统上被移除,其它低版本系统上自带
public static String postFileList(List<File> fileList, String url) throws IOException {
if(fileList==null||fileList.size()==0)return null;
FileBody bin = null;
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
//请记住,这边传递汉字会出现乱码,解决方法如下,设置好编码格式就好
StringBody username = new StringBody("136哈哈哈", Charset.forName("UTF-8"));
MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, null,
Charset.forName("UTF-8"));
for(File file :fileList){
bin = new FileBody(file);
String name=file.getName().substring(5, file.getName().length()-4);
reqEntity.addPart(name, bin);
}
reqEntity.addPart("sid", username);
httppost.setEntity(reqEntity);
System.out.println("执行: " + httppost.getRequestLine());
HttpResponse response = httpclient.execute(httppost);
System.out.println("statusCode is " + response.getStatusLine().getStatusCode());
HttpEntity resEntity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
String result = null;
if (resEntity != null) {
System.out.println("返回长度: " + resEntity.getContentLength());
System.out.println("返回类型: " + resEntity.getContentType());
}
int returnCode = response.getStatusLine().getStatusCode();
if(returnCode==200){
//HttpEntity responseEntity = response.getEntity();
result = EntityUtils.toString(resEntity);
System.out.println(result);
return result;
}
else {
return null;
}
}
3. 使用Glide给视频文件的一帧图片附加播放图标
Glide使用方式:
Glide.with(context)
.load(数据源)
.into(targetImageView);
其中数据源类型可以是如何,很可惜没有Bitmap:
.load(String string) string可以为一个文件路径、uri或者url
.load(Uri uri) uri类型
.load(File file) 文件
.load(Integer resourceId) 资源Id,R.drawable.xxx或者R.mipmap.xxx
.load(byte[] model) byte[]类型
.load(T model) 自定义类型
那么问题来了,如何使用Glide加载两个Bitmap组合或者拼接后的Bitmap呢,找到一种方法可以解决,例如要给一个视频文件加一个播放的图标在其中间:
File imageFile = "xxx/xx.jpg";
Glide.with(mContext).load(imageFile).asBitmap().into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
Bitmap waterBitmap =((BitmapDrawable)mContext.getResources().getDrawable(R.mipmap.video_play)).getBitmap();
//Bitmap拼接函数不再展开,此处是在图片上添加了居中播放的图标
Bitmap bm = BitmapUtil.Watermark(resource,waterBitmap,255);
imageView.setImageBitmap(bm);
}
});
4. 布局中的组件被渲染之前getWidth()和getMeasuredWidth()都是0,却要使用其大小做一些计算。
假如有两个View,在没有渲染出来之前代码计算大小,两个的宽度都要设定为两个View中较大的一个,其核心是在组件还没有被展示之前得到其大小。getMeasuredWidth()是measure之后有值,而getWidth是在layout执行之后才有值,故手动调用measure测量一下大小,就能用getMeasuredWidth()获取值了。
TextView nameView = (TextView) linearLayout.findViewById(R.id.recognizerresult_name);
TextView ageView = (TextView) linearLayout.findViewById(R.id.recognizerresult_age);
nameView.measure(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
ageView.measure(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
int maxWidth = Math.max(nameView.getMeasuredWidth(),ageView.getMeasuredWidth());
nameView.getLayoutParams().width = maxWidth;
ageView.getLayoutParams().width = maxWidth;
5. onPreviewFrame使用子线程解析每一帧数据,以及避免读写同时操作导致闪退
做人脸检测时或者二维码扫描,为了避免ui线程阻塞,肯定是要把检测人脸处理和耗时的计算操作放入子线程执行的,放入子线程就会有很多数据同步上的问题,此处我参考了opencv的JavaCameraView的代码,在此记录一下。
刚开始一直报如下错误,且运行过程中没有任何提示闪退,其中2255是处理每一帧数据的子线程id,遇到此类错误可以考虑是多线程同时读写或者数据不同步导致的。
09-18 11:10:09.352 27814-28458/com.seengene.launcher A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x5a001 in tid 28458 (engene.launcher)
09-18 11:10:09.352 27814-30398/com.seengene.launcher A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x1 in tid 30398 (Thread-2255)
以下是整理简化过的JavaCameraView部分代码,只作为记录原理用,不是实际代码。
//**这是一个长度为2的数组,之所以设计了这个,是为了避免onpreviewFrame所在线程和处理每一帧数据的线程同时读写同一个Mat数据
//试想如果只是一个Mat那么肯定存在两个线程同时读写的情况,会导致程序运行过程中直接闪退**。
private Mat[] mFrameChain;
private int mChainIdx = 0;
//省略无关代码且有改动简化
mFrameChain= new Mat[2];
mFrameChain[0] = new Mat();
mFrameChain[1] = new Mat();
}
public void onPreviewFrame(byte[] frame, Camera arg1) {
//通过对象锁的机制叫醒等待的人脸检测线程,当然如果人脸检测线程还没有在await状态,notify也是没有用的
synchronized (this) {
mFrameChain[mChainIdx].put(0, 0, frame);
mCameraFrameReady = true;
this.notify();
}
//省略无关代码
}
//关闭相机之前一定要notify处理每一帧数据的子线程,不然会导致程序erro闪退
protected void disconnectCamera() {
/* 1. We need to stop thread which updating the frames
* 2. Stop camera and release it
*/
try {
//先notify处理每一帧数据的子线程
mStopThread = true;
Log.d(TAG, "Notify thread");
synchronized (this) {
this.notify();
}
Log.d(TAG, "Wating for thread");
if (mThread != null)
mThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
mThread = null;
}
//然后释放相机
/* Now release camera */
releaseCamera();
mCameraFrameReady = false;
}
//处理每一帧数据,检测人脸、画人脸框的子线程
private class CameraWorker implements Runnable {
@Override
public void run() {
do {
boolean hasFrame = false;
synchronized (JavaCameraView.this) {
try {
while (!mCameraFrameReady && !mStopThread) {
JavaCameraView.this.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
if (mCameraFrameReady)
{
//在此处要把mChainIdx变化一下,这样下次onpreviewFrame中操作的是另外一个Mat了,这样我们这个线程就可以安心的用当前的这帧的Mat了
mChainIdx = 1 - mChainIdx;
mCameraFrameReady = false;
hasFrame = true;
}
}
if (!mStopThread && hasFrame) {
//因为mChainIdx已经变了,故要1-mChainIdx才是当前这帧的Mat数据
if (!mFrameChain[1 - mChainIdx].empty())
deliverAndDrawFrame(mCameraFrame[1 - mChainIdx]);
}
} while (!mStopThread);
}
}