安卓简易应用开发

安卓应用开发

项目一:双摄像头显示,HTTP实时上传预览数据

1.1、软件简介

? 打开APK后会自动打开摄像头,在上下界面中会显示前置和后置的画面,在下方可设置HTTP服务器的IP及端口,点击链接后,会一直发送当前的预览画面。

安卓简易应用开发

1.2、源码分析

因为要截取图像,使用拍照的话会特别慢,所以项目中采用截取预览画面的方案。方案中使用的Camera API 为 Camera1可兼容大部分机器。(Android 从5.0开始就有了Camera 2 API)

在界面配置中添加两个SurfaceView,用于显示两个摄像头预览。

activity_main.xml 部分

<SurfaceView
    android:id="@+id/surfaceView1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_weight="0.5" />

<SurfaceView
    android:id="@+id/surfaceView2"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_weight="0.5"/>

在MainActivity.java中配置摄像头显示

MainActivity.java 部分

surfaceView1 = (SurfaceView) this.findViewById(R.id.surfaceView1);
surfaceHolder1 = surfaceView1.getHolder();
surfaceView2 = (SurfaceView) this.findViewById(R.id.surfaceView2);
surfaceHolder2 = surfaceView2.getHolder();

设置摄像头

private void openCamera() {
    try {
        camera1 = Camera.open(1);
        camera2 = Camera.open(0);
    } catch (Exception e) {
        Log.e("camera", "open camera error!");
        e.printStackTrace();
        return;
    }
    Camera.Parameters params = camera1.getParameters();
    params.setPictureFormat(PixelFormat.JPEG);
    camera1.setParameters(params);

    params = camera2.getParameters();
    params.setPictureFormat(PixelFormat.JPEG);
    //params.setRotation(90);
    camera2.setParameters(params);
    try {
        camera1.setPreviewDisplay(surfaceHolder1);
        camera2.setPreviewDisplay(surfaceHolder2);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        Log.e("camera", "preview failed.");
        e.printStackTrace();
    }
    camera1.startPreview();
    camera2.startPreview();

    camera1.setPreviewCallback(new Camera.PreviewCallback() {

        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
            camera.addCallbackBuffer(data);
            Camera.Size previewSize = camera.getParameters().getPreviewSize();
            YuvImage image = new YuvImage(data, ImageFormat.NV21, previewSize.width, previewSize.height, null);
            if (image != null) {
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                image.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 80, stream);
                final Bitmap bitmap = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());

                if (bitmap != null) {
                    if (isSending == false){
                        saveBitmap2ByteArray(bitmap, 1);
                    }
                }
                try {
                    stream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    });
    camera2.setPreviewCallback(new Camera.PreviewCallback() {
        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
            camera.addCallbackBuffer(data);

            Camera.Size previewSize = camera.getParameters().getPreviewSize();
            //Log.d(">>>>>>>>>>>", "Camera 2 parameters" + Integer.toString(previewSize.height) + Integer.toString(previewSize.width));
            YuvImage image = new YuvImage(data, ImageFormat.NV21, previewSize.width, previewSize.height, null);
            if (image != null) {
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                image.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 80, stream);
                final Bitmap bitmap = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());

                if (bitmap != null) {
                    if (isSending == false){
                        saveBitmap2ByteArray(bitmap, 2);
                    }
                }
                try {
                    stream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    });
}

调整摄像头方向可直接使用

//params.setRotation(90);//参数0 90 180 270

预览数据转为jpg数据

    private void saveBitmap2ByteArray(Bitmap bitmap, int cameraChoose)
    {
        try {
            if(isSendStart) {
                if (cameraChoose == 1) {

                    if (byteArrayOutputStreamBitmapCamera1 != null) {
                        byteArrayOutputStreamBitmapCamera1.close();
                    }
                    byteArrayOutputStreamBitmapCamera1 = new ByteArrayOutputStream();
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 80, byteArrayOutputStreamBitmapCamera1);
                } else {
                    if (byteArrayOutputStreamBitmapCamera2 != null) {
                        byteArrayOutputStreamBitmapCamera2.close();
                    }
                    byteArrayOutputStreamBitmapCamera2 = new ByteArrayOutputStream();
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 80, byteArrayOutputStreamBitmapCamera2);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();

            Log.d(">>>>>>>>>>>>>>>>>>>>>", "saveBitmap2ByteArray err" + e);
        }
    }

Http上传数据

    public void httpPostImage(String urlstr) {
        String end = "\r\n";
        String twoHyphens = "--";
        String boundary = "*****";//边界标识
        int TIME_OUT = 2*1000;   //超时时间
        HttpURLConnection con = null;
        DataOutputStream ds = null;
        InputStream is = null;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date(System.currentTimeMillis());
        //OutputStream outputStream;
        try {
            URL url = new URL(urlstr);
            con = (HttpURLConnection) url.openConnection();
            con.setReadTimeout(TIME_OUT);
            con.setConnectTimeout(TIME_OUT);
            /* 允许Input、Output,不使用Cache */
            con.setDoInput(true);
            con.setDoOutput(true);
            con.setUseCaches(false);

            // 设置http连接属性
            con.setRequestMethod("POST");//请求方式
            con.setRequestProperty("Connection", "Keep-Alive");//在一次TCP连接中可以持续发送多份数据而不会断开连接
            con.setRequestProperty("Charset", "UTF-8");//设置编码
            con.setRequestProperty("Content-Type",//multipart/form-data能上传文件的编码格式
                    "multipart/form-data;boundary=" + boundary);
            ds = new DataOutputStream(con.getOutputStream());
            ds.writeBytes("Content-Disposition: form-data; "
                    + "name=\"stblog\";filename=\"" + "camera1.jpg+camera2.jpg+" + "\"" + end);
            ds.writeBytes(end);
            byte[] buffer1 = byteArrayOutputStreamBitmapCamera1.toByteArray();
            byte[] decodeBytes1 = Base64.encode(buffer1, 0, buffer1.length, Base64.DEFAULT);
            ds.write(decodeBytes1, 0, decodeBytes1.length);
            ds.writeBytes("\r\n----------\r\n");
            byte[] buffer2 = byteArrayOutputStreamBitmapCamera2.toByteArray();
            byte[] decodeBytes2 = Base64.encode(buffer2, 0, buffer2.length, Base64.DEFAULT);
            ds.write(decodeBytes2, 0, decodeBytes2.length);
            ds.writeBytes(end);
            ds.writeBytes(twoHyphens + boundary + twoHyphens + end);//结束
            ds.flush();
            StringBuffer b = new StringBuffer();
            int responseCode = con.getResponseCode();
            //Log.d(">>>>>>>>>>>>>>>>>>>", "responseCode " + Integer.toString(responseCode));
            if (responseCode == 200) {
                is = con.getInputStream();
                int ch;
                while ((ch = is.read()) != -1) {
                    b.append((char) ch);
                }
            }
            Log.d(">>>>>>>>>>>>>>>", "Send OK!!!!!!");
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(">>>>>>>>>>>>>>>>>", "Http send err " + e);
            textViewMessage.setText(simpleDateFormat.format(date) + "  Cnt: " + Integer.toString(sendCnt) + " Err;Res > " + e);
        } finally {
            /* 关闭DataOutputStream */
            if(ds!=null){
                try {
                    ds.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (con != null) {
                con.disconnect();
            }
        }
    }

最后别忘了增加申请权限、动态申请权限

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    public void checkPermission()
    {
        int targetSdkVersion = 0;
        try {
            final PackageInfo info = this.getPackageManager().getPackageInfo(this.getPackageName(), 0);
            targetSdkVersion = info.applicationInfo.targetSdkVersion;//获取应用的Target版本
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (targetSdkVersion >= Build.VERSION_CODES.M) {
                boolean isAllGranted = checkPermissionAllGranted(PermissionString);
                if (isAllGranted) {
                    return;
                }
                ActivityCompat.requestPermissions(this,
                        PermissionString, 1);
            }
        }
    }

    /**
     * 检查是否拥有指定的所有权限
     */
    private boolean checkPermissionAllGranted(String[] permissions) {
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    //申请权限结果返回处理
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 1) {
            boolean isAllGranted = true;
            // 判断是否所有的权限都已经授予了
            for (int grant : grantResults) {
                if (grant != PackageManager.PERMISSION_GRANTED) {
                    isAllGranted = false;
                    break;
                }
            }
            if (isAllGranted) {
                // 所有的权限都授予了
                Log.e("err","权限都授权了");
            }
        }
    }

项目二:界面全屏打开一个网页

2.1、软件简介

一个WebView的Demo,只可用于简单演示。全屏显示一个网页。

安卓简易应用开发

2.2、源码分析

全屏显示

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

// 全屏展示
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                // 全屏显示,隐藏状态栏和导航栏,拉出状态栏和导航栏显示一会儿后消失。
                MainActivity.this.getWindow().getDecorView().setSystemUiVisibility(
                        View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                                | View.SYSTEM_UI_FLAG_FULLSCREEN
                                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
            } else {
                // 全屏显示,隐藏状态栏
                MainActivity.this.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
            }
        }
        setContentView(R.layout.activity_main);

WebView

        webView = findViewById(R.id.webView);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.loadUrl("http://www.bilibili.com/");
        webView.setWebViewClient(new WebViewClient());

项目三:UDP接收ANT数据

3.1、软件简介

? Ant数据是有板子上的NRF52832接收后,通过串口上传过来的,用C应用将接收的数据通过UDP方式上传到本机的50001端口。相当于透传。本APK仅用作演示。

安卓简易应用开发

3.2、源码分析

建立UDP连接并解析数据

           DatagramSocket socket = null;
            try {
                socket = new DatagramSocket(50001);
                byte[] data2=new byte[1024];
                byte[] recvData;
                DatagramPacket packet2=new DatagramPacket(data2, data2.length);
                while(true) {
                    socket.receive(packet2);
                    recvData = packet2.getData();
                    //Log.d(">>>>>>>>>>>", "length" + Integer.toString(packet2.getLength()));
                    udpRecvDataHandle(packet2.getData(), packet2.getLength());
                    Thread.sleep(1);
                }

            } catch (Exception e) {
                e.printStackTrace();

                Log.d(">>>>>>>>>>>", "err:" + e);
            } finally {
                if(socket != null){
                    socket.close();
                }
            }

安卓简易应用开发

上一篇:Webwork 学习之路【08】结合实战简析Controller 配置


下一篇:亚马逊云计算服务