android棘手综合问题小记

代码只是解决特定问题的方法,并未深入研究每一个方法的原理,仅作为自身积累所用。如果对你有启发,请点赞哦。
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);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值