android拍照_android拍照上传 - CSDN
精华内容
参与话题
  • android拍照的两种方法

    千次阅读 2018-07-11 09:59:56
    android系统的照相功能,已实现2种方法,可供大家参考:1.调用系统摄像头来拍照首先,找到AndroidManifest.xml文件里加入用户权限<uses-permission android:name="android.permission.CAMERA"&...

    android系统的照相功能,已实现2种方法,可供大家参考:

    1.调用系统摄像头来拍照

    首先,找到AndroidManifest.xml文件里加入用户权限

    <uses-permission android:name="android.permission.CAMERA"></uses-permission>

     <uses-feature android:name="android.hardware.camera" />
     <uses-feature android:name="android.hardware.camera.autofocus" />

    其次,在主类java文件里加入2个控件(button和imageview),是用来触发按钮事件和显示图片的,纯是个人爱好

    final int TAKE_PICTURE = 1;//为了表示返回方法中辨识你的程序打开的相机

    关键是这里:startActivityForResult(new Intent("android.media.action.IMAGE_CAPTURE"), TAKE_PICTURE);

    是打开系统自带相机,以下是处理拍照得到的数据,将数据保存下来

        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (requestCode == TAKE_PICTURE) {
                if (resultCode == RESULT_OK) {
                    Bitmap bm = (Bitmap) data.getExtras().get("data");
                    img.setImageBitmap(bm);//想图像显示在ImageView视图上,private ImageView img;
                    File myCaptureFile = new File("sdcard/123456.jpg");
                    try {
         BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile));
          /* 采用压缩转档方法 */
               bm.compress(Bitmap.CompressFormat.JPEG, 80, bos);
              
               /* 调用flush()方法,更新BufferStream */
               bos.flush();
              
               /* 结束OutputStream */
               bos.close();
        } catch (FileNotFoundException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
         
        } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
        }
                }
            }
    }

    这样就能实现调用系统自带的摄像头了,很简单的操作。

    2.自己写程序来保存照片

    照片格局文件lay.xml里要先进行这些定义

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="vertical"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
    >
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="130px"
        android:paddingRight="200px"
      >
      <SurfaceView
        android:id="@+id/mSurfaceView1"
        android:visibility="visible"
        android:layout_width="320px"
        android:layout_height="240px">
      </SurfaceView>
      </LinearLayout>
      </LinearLayout>

     

    其中SurfaceView是用来进行预览的,

    在Oncreat函数里初始化一系列的值:

     requestWindowFeature(Window.FEATURE_NO_TITLE);
     setContentView(R.layout.lay);

     /* 取得屏幕解析像素 */
         DisplayMetrics dm = new DisplayMetrics();
         getWindowManager().getDefaultDisplay().getMetrics(dm);
        // mImageView01 = (ImageView) findViewById(R.id.myImageView1);
        
         /* 以SurfaceView作为相机Preview之用 */
         mSurfaceView01 = (SurfaceView) findViewById(R.id.mSurfaceView1);
        
         /* 绑定SurfaceView,取得SurfaceHolder对象 */
         mSurfaceHolder01 = mSurfaceView01.getHolder();
        
         /* Activity必须实现SurfaceHolder.Callback */
         mSurfaceHolder01.addCallback(takephoto.this);
        
         /*
          * 以SURFACE_TYPE_PUSH_BUFFERS(3)
          * 作为SurfaceHolder显示类型
          * */
         mSurfaceHolder01.setType
         (SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

     

    首先进行初始化照相机的功能函数和参数设置:

    private Camera mCamera01;

    mCamera01 = Camera.open();

     /* 创建Camera.Parameters对象 */
        Camera.Parameters parameters = mCamera01.getParameters();
            
        /* 设置相片格式为JPEG */
        parameters.setPictureFormat(PixelFormat.JPEG);
        Log.i(TAG, "pic is jpeg");
            
        /* 指定preview的屏幕大小 */
        parameters.setPreviewSize(320, 240);
        Log.i(TAG, "pic pingmu fenbianlv");
            
        /* 设置图片分辨率大小 */
        parameters.setPictureSize(1024, 768);
        Log.i(TAG, "pic tupian fenbianlv");
            
        /* 将Camera.Parameters设置予Camera */
        mCamera01.setParameters(parameters);
            
        /* setPreviewDisplay唯一的参数为SurfaceHolder */
        mCamera01.setPreviewDisplay(mSurfaceHolder01);
            
        /* 立即运行Preview */
        mCamera01.startPreview();

    初始化成功后就可以进行拍照了,拍照函数依然是通过调用camera类的函数来实现

    mCamera01.takePicture
           (shutterCallback, rawCallback, jpegCallback);

    只需实现jpegCallback这个回调函数来就行解码、保存即可,前2个参数可以直接设为null,不过系统一般会自动帮你把这些都写进来的

     private PictureCallback jpegCallback = new PictureCallback()
       {
         public void onPictureTaken(byte[] _data, Camera _camera)
         {
           // TODO Handle JPEG image data
          
           /* onPictureTaken传入的第一个参数即为相片的byte */
           Bitmap bm = BitmapFactory.decodeByteArray
                       (_data, 0, _data.length);
          
           /* 创建新文件 */
                  picname = "sdcard/1234566.jpg";//要保存在哪里,路径你自己设
           File myCaptureFile = new File(picname);
           try
           {
             BufferedOutputStream bos = new BufferedOutputStream
             (new FileOutputStream(myCaptureFile));
            
             /* 采用压缩转档方法 */
             bm.compress(Bitmap.CompressFormat.JPEG, 80, bos);
            
             /* 调用flush()方法,更新BufferStream */
             bos.flush();
            
             /* 结束OutputStream */
             bos.close();
            
             /* 将拍照下来且存储完毕的图文件,显示出来 */
             //mImageView01.setImageBitmap(bm);
            
             /* 显示完图文件,立即重置相机,并关闭预览 */
             resetCamera();
             
              }
           catch (Exception e)
           {
             Log.e(TAG, e.getMessage());
           }
         }
       };

     

    拍照完了要重置照相机,然后可以继续拍照

    /* 相机重置 */
       private void resetCamera()
       {
         if (mCamera01 != null && bIfPreview)
         {
           mCamera01.stopPreview();
           /* 扩展学习,释放Camera对象 */
           mCamera01.release();
           mCamera01 = null;
           bIfPreview = false;
         }
       }

     

    2种拍照方式的比较

    1.调用系统自带的照相机,照片格式大小只有几种选择,照片拍出来比较大,而自己程序实现的话可以调节照片大小为任意尺寸,图片的容量可以调节

    2.调用系统的简单,而且外观一般比自己设置的要好看

    3.调用系统的操作简单、方便,不易出错,自己编程的话需要注意,容易引起系统出错意外终止

    展开全文
  • 现在一般的手机应用...调用系统相机拍照后crash,或者返回RESULT_CANCEL(0)3.选择相片后得到的Uri为空或者为Uri后半段为资源ID(%1234567这种)4.调用系统裁剪后crash5.小米手机的特别情况还有许多小问题,大多都...

    现在一般的手机应用都会有上传头像的功能,我在实现这个功能的时候遇到很多问题,这里专门记录一下。

    add 2018/5/10 21:05

    先列举一下我出现过的问题:

    1.运行时权限

    2.调用系统相机拍照后crash,或者返回RESULT_CANCEL(0)

    3.选择相片后得到的Uri为空或者为Uri后半段为资源ID(%1234567这种)

    4.调用系统裁剪后crash

    5.小米手机的特别情况

    还有许多小问题,大多都是上面问题引起的并发症,就不一一列举了。


    先上代码,慢慢讲。


    1.布局


    只关注头像那一栏就可以了,点击头像后会弹出选择页面。PopupWindow的实现如下:

    1.1    新建layout文件pop_item

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#66000000">
    
        <LinearLayout
            android:id="@+id/ll_pop"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="15dp"
            android:layout_marginRight="15dp"
            android:orientation="vertical"
            android:layout_alignParentBottom="true">
            <Button
                android:id="@+id/icon_btn_camera"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@drawable/white_btn_top"
                android:textColor="@color/colorMainGreen"
                android:text="拍照"/>
            <View
                android:layout_width="match_parent"
                android:layout_height="1dp"
                />
            <Button
                android:id="@+id/icon_btn_select"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@drawable/white_btn_bottom"
                android:textColor="@color/colorMainGreen"
                android:text="从相册选择"/>
            <Button
                android:id="@+id/icon_btn_cancel"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:layout_marginBottom="15dp"
                android:background="@drawable/white_btn"
                android:textColor="@color/colorMainGreen"
                android:text="取消"/>
        </LinearLayout>
    
    </RelativeLayout>

            三个Button分别对应三个按钮,中间的View是两个按钮之间的线,colorMainGreen是

    <color name="colorMainGreen">#40cab3</color>

    1.2    可以看到三个按钮分别是上圆角,下圆角,全圆角,在drawable中新建3个xml,绘制Button样式

    white_btn_top

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <solid android:color="@android:color/white" />
        <corners android:topLeftRadius="10dp"
            android:topRightRadius="10dp"
            android:bottomRightRadius="0dp"
            android:bottomLeftRadius="0dp"/>
        <stroke android:width="0dp" android:color="@android:color/white" />
    </shape>

    white_btn_bottom

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <solid android:color="@android:color/white" />
        <corners android:topLeftRadius="0dp"
            android:topRightRadius="0dp"
            android:bottomRightRadius="10dp"
            android:bottomLeftRadius="10dp"/>
        <stroke android:width="0dp" android:color="@android:color/white" />
    </shape>

    while_btn

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <solid android:color="@android:color/white"/>
        <corners android:radius="10dp"/>
        <stroke android:width="0dp" android:color="@android:color/white" />
    </shape>

            简单解释一下shape的用法,每一组< />中制定一个属性(不知道是不是这么叫,但是是这个意思),在每条属性中可以指定更多的细节。solid指定填充,corners指定圆角,在corners中的radius指定了圆角的半径,stroke用于描边。

    1.3    PhotoPopupWindow布局都写好了,现在我们要写自己的PhotoPopupWindow类加载它,同时给他添加点击事件。新建一个package,命名为popup(这样做的目的是使得代码结构清晰),在这个包下新建PhotoPopupWindow类,继承PopupWindow

    public class PhotoPopupWindow extends PopupWindow {
        private static final String TAG = "PhotoPopupWindow";
        private View mView; // PopupWindow 菜单布局
        private Context mContext; // 上下文参数
        private View.OnClickListener mSelectListener; // 相册选取的点击监听器
        private View.OnClickListener mCaptureListener; // 拍照的点击监听器
    
        public PhotoPopupWindow(Activity context, View.OnClickListener selectListener, View.OnClickListener captureListener) {
            super(context);
            this.mContext = context;
            this.mSelectListener = selectListener;
            this.mCaptureListener = captureListener;
            Init();
        }
    
        /**
         * 设置布局以及点击事件
         */
        private void Init() {
            LayoutInflater inflater = (LayoutInflater) mContext
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            assert inflater != null;
            mView = inflater.inflate(R.layout.pop_item, null);
            Button btn_camera = (Button) mView.findViewById(R.id.icon_btn_camera);
            Button btn_select = (Button) mView.findViewById(R.id.icon_btn_select);
            Button btn_cancel = (Button) mView.findViewById(R.id.icon_btn_cancel);
    
            btn_select.setOnClickListener(mSelectListener);
            btn_camera.setOnClickListener(mCaptureListener);
            btn_cancel.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dismiss();
                }
            });
    
            // 导入布局
            this.setContentView(mView);
            // 设置动画效果
            this.setAnimationStyle(R.style.popwindow_anim_style);
            this.setWidth(WindowManager.LayoutParams.MATCH_PARENT);
            this.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
            // 设置可触
            this.setFocusable(true);
            ColorDrawable dw = new ColorDrawable(0x0000000);
            this.setBackgroundDrawable(dw);
            // 单击弹出窗以外处 关闭弹出窗
            mView.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    int height = mView.findViewById(R.id.ll_pop).getTop();
                    int y = (int) event.getY();
                    if (event.getAction() == MotionEvent.ACTION_UP) {
                        if (y < height) {
                            dismiss();
                        }
                    }
                    return true;
                }
            });
        }
    }

            代码是很主流的写法,没什么特别的。TAG常量会出现在每一个JAVA类中,即使我用不到他。这样写便于区别Log发生的位置。两个OnClickListener需要在实例化的时候实现。

    1.4    弹出框写好了,接下来是头像页面的布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/backgroundWhite"
        tools:context=".activity.UserInfoActivity">
    
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar_userinfo"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:title="用户信息"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
        </android.support.v7.widget.Toolbar>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            >
            <RelativeLayout
                android:id="@+id/user_head"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:layout_marginTop="1dp"
                android:background="@drawable/bg_info_rl">
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:gravity="center_vertical"
                    android:layout_marginLeft="15dp"
                    android:textSize="16sp"
                    android:text="头像 "/>
                <de.hdodenhof.circleimageview.CircleImageView
                    android:id="@+id/user_head_iv"
                    android:layout_width="40dp"
                    android:layout_height="40dp"
                    android:layout_alignParentEnd="true"
                    android:layout_alignParentRight="true"
                    android:layout_centerVertical="true"
                    android:layout_marginRight="25dp"
                    app:civ_border_color="#F3F3F3"
                    app:civ_border_width="1dp"/>
            </RelativeLayout>
    
            <RelativeLayout
                android:id="@+id/user_nick_name"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:layout_marginTop="1dp"
                android:background="@drawable/bg_info_rl">
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:gravity="center_vertical"
                    android:layout_marginLeft="15dp"
                    android:textSize="16sp"
                    android:text="昵称"/>
                <TextView
                    android:id="@+id/user_nick_name_TV"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:gravity="center_vertical"
                    android:layout_marginRight="10dp"
                    android:textSize="16sp"
                    android:layout_toLeftOf="@id/user_nick_name_IV" />
                <ImageView
                    android:id="@+id/user_nick_name_IV"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:src="@drawable/ic_chevron_right_black_24dp"
                    android:layout_alignParentRight="true"
                    android:layout_marginRight="15dp"
                    />
            </RelativeLayout>
    
            <RelativeLayout
                android:id="@+id/user_gender"
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:layout_marginTop="1dp"
                android:background="@drawable/bg_info_rl">
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:gravity="center_vertical"
                    android:layout_marginLeft="15dp"
                    android:textSize="16sp"
                    android:text="性别"/>
                <TextView
                    android:id="@+id/user_gender_TV"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:gravity="center_vertical"
                    android:layout_marginRight="10dp"
                    android:textSize="16sp"
                    android:layout_toLeftOf="@id/user_gender_IV" />
                <ImageView
                    android:id="@+id/user_gender_IV"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:src="@drawable/ic_chevron_right_black_24dp"
                    android:layout_marginRight="15dp"
                    android:layout_alignParentRight="true"
                    />
            </RelativeLayout>
    
        </LinearLayout>
    </LinearLayout>
            我解释一下有疑问的地方。Toolbar是谷歌推荐的标题栏,比Actionbar具有更好的拓展性。CircleImageView是一个开源库,自行百度GitHub地址,用于产生圆形图片。这一部分的设计可以参考郭霖大神的《第一行代码》或者他的博客,有关Material design的内容(在十一章好像),他讲解的很详细。backgroundWhite是
    <color name="backgroundWhite">#EBEBEB</color>
    tools:context指定了该layout将在哪个activiy展示,指定了tools:context的layout可以动态预览布局,也就是说我在acticity的onCreate里改变了某个控件,我可以在不run的情况下预览这个改变的效果。tools还有一些别的功能,我懂的也不多,就不介绍了。bg_info_rl是可变背景,这里我只是简单设置了点击和松开时候的颜色,代码这段结束后贴,ic_chevron_right_black_24dp是Material design提供的小图标,样式是“>”,大家可以自行搜索,这是谷歌官方提供的免费素材包,可以在谷歌MD的官网或者GitHub上获取。
    bg_info_rl
    <?xml version="1.0" encoding="UTF-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_window_focused="false" android:drawable="@drawable/bg_info_rl_normal" />
        <item android:state_pressed="true" android:drawable="@drawable/bg_info_rl_pressed" />
    </selector>
    bg_info_rl_normal
    <?xml version="1.0" encoding="UTF-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <solid android:color="@color/white" />
    </shape>
    bg_info_rl_pressed
    <?xml version="1.0" encoding="UTF-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <solid android:color="@color/light_grey" />
    </shape>
    color
    <color name="white">#FFFFFF</color>
    <color name="light_grey">#EAEAEA</color> <!--浅灰色-->

    2.运行时权限的问题

    add 2018/5/11 10:18

            android 6.0引入了运行时权限,用户不必在安装时授予所有权限,可以在使用到相关功能时再授权。普通权限不需要运行时申请,危险权限则必须,否则程序会crash掉。

            头像功能需要以下三个权限

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.CAMERA" />

            读写SD卡,使用相机,他们都是危险权限,接下来新建UserInfoAcitivity,继承AppCompatActivity 继承View.OnClickListener接口。

    变量和常量

    private static final String TAG = "UserInfoActivity";
        private static final int REQUEST_IMAGE_GET = 0;
        private static final int REQUEST_IMAGE_CAPTURE = 1;
        private static final int REQUEST_SMALL_IMAGE_CUTTING = 2;
        private static final int REQUEST_CHANGE_USER_NICK_NAME = 10;
        private static final String IMAGE_FILE_NAME = "user_head_icon.jpg";
    
        PhotoPopupWindow mPhotoPopupWindow;
        TextView textView_user_nick_name;
        TextView textView_user_gender;
        CircleImageView circleImageView_user_head;
    初始化布局
    @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_userinfo);
    
            textView_user_nick_name = findViewById(R.id.user_nick_name_TV);
            textView_user_gender = findViewById(R.id.user_gender_TV);
            circleImageView_user_head = findViewById(R.id.user_head_iv);
            //InfoPrefs自己封装的一个 SharedPreferences 工具类
            //init()指定文件名,getData(String key)获取key对应的字符串,getIntData(int key)获取key对应的int
            InfoPrefs.init("user_info");
            refresh();
    
            RelativeLayout relativeLayout_user_nick_name = findViewById(R.id.user_nick_name);
            relativeLayout_user_nick_name.setOnClickListener(this);
    
            RelativeLayout relativeLayout_user_gender = findViewById(R.id.user_gender);
            relativeLayout_user_gender.setOnClickListener(this);
    
            RelativeLayout relativeLayout_user_head = findViewById(R.id.user_head);
            relativeLayout_user_head.setOnClickListener(this);
            //初始化 toolbar
            Toolbar toolbar = findViewById(R.id.toolbar_userinfo);
            setSupportActionBar(toolbar);
            ActionBar actionBar = getSupportActionBar();
    
            if (actionBar != null) {
                //指定toolbar左上角的返回按钮,这个按钮的id是home(无法更改)
                actionBar.setDisplayHomeAsUpEnabled(true);
                //actionBar.setHomeAsUpIndicator();
            }
        }


    public void refresh(){
            textView_user_nick_name.setText(InfoPrefs.getData(Constants.UserInfo.NAME));
            textView_user_gender.setText(InfoPrefs.getData(Constants.UserInfo.GENDER));
            showHeadImage();
            //circleImageView_user_head.setImageURI();
        }

            为每一个RelativeLayout都添加了点击事件,这里我们只关注头像的点击事件。出现的工具类我只解释功能,完整代码可以在文末我的GitHub获取,这个项目是一个手机桌面宠物的demo,包括悬浮窗、蓝牙、闹钟等,合作写的,代码的风格不太一致,见谅。

    @Override
        public void onClick(View v) {
            switch(v.getId()){
                case R.id.user_head:
                    //创建存放头像的文件夹
                    PictureUtil.mkdirMyPetRootDirectory();
                    mPhotoPopupWindow = new PhotoPopupWindow(UserInfoActivity.this, new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            // 文件权限申请
                            if (ContextCompat.checkSelfPermission(UserInfoActivity.this,
                                    Manifest.permission.WRITE_EXTERNAL_STORAGE)
                                    != PackageManager.PERMISSION_GRANTED) {
                                // 权限还没有授予,进行申请
                                ActivityCompat.requestPermissions(UserInfoActivity.this,
                                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 200); // 申请的 requestCode 为 200
                            } else {
                                // 如果权限已经申请过,直接进行图片选择
                                mPhotoPopupWindow.dismiss();
                                Intent intent = new Intent(Intent.ACTION_PICK);
                                intent.setType("image/*");
                                // 判断系统中是否有处理该 Intent 的 Activity
                                if (intent.resolveActivity(getPackageManager()) != null) {
                                    startActivityForResult(intent, REQUEST_IMAGE_GET);
                                } else {
                                    Toast.makeText(UserInfoActivity.this, "未找到图片查看器", Toast.LENGTH_SHORT).show();
                                }
                            }
                        }
                    }, new View.OnClickListener()
                    {
                        @Override
                        public void onClick (View v){
                            // 拍照及文件权限申请
                            if (ContextCompat.checkSelfPermission(UserInfoActivity.this,
                                    Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
                                    || ContextCompat.checkSelfPermission(UserInfoActivity.this,
                                    Manifest.permission.WRITE_EXTERNAL_STORAGE)
                                    != PackageManager.PERMISSION_GRANTED) {
                                // 权限还没有授予,进行申请
                                ActivityCompat.requestPermissions(UserInfoActivity.this,
                                        new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 300); // 申请的 requestCode 为 300
                            } else {
                                // 权限已经申请,直接拍照
                                mPhotoPopupWindow.dismiss();
                                imageCapture();
                            }
                        }
                    });
                    View rootView = LayoutInflater.from(UserInfoActivity.this).inflate(R.layout.activity_userinfo, null);
                    mPhotoPopupWindow.showAtLocation(rootView,
                            Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);
                    break;
    
                case R.id.user_nick_name:
                    ChangeInfoBean bean = new ChangeInfoBean();
                    bean.setTitle("修改昵称");
                    bean.setInfo(InfoPrefs.getData(Constants.UserInfo.NAME));
                    Intent intent = new Intent(UserInfoActivity.this,ChangeInfoActivity.class);
                    intent.putExtra("data", bean);
                    startActivityForResult(intent,REQUEST_CHANGE_USER_NICK_NAME);
                    break;
    
                case R.id.user_gender:
                    new ItemsAlertDialogUtil(UserInfoActivity.this).setItems(Constants.GENDER_ITEMS).
                            setListener(new ItemsAlertDialogUtil.OnSelectFinishedListener() {
                                @Override
                                public void SelectFinished(int which) {
                                    InfoPrefs.setData(Constants.UserInfo.GENDER,Constants.GENDER_ITEMS[which]);
                                    textView_user_gender.setText(InfoPrefs.getData(Constants.UserInfo.GENDER));
                                }
                            }).showDialog();
                    break;
                default:
            }
        }
    

            运行时权限的逻辑很简单,先判断是否已经授权过,如果已经授权,则直接进行操作,否则请求授权,根据请求结果处理。请求结果在onRequestPermissonsResult里处理。有一点要提一下,运行时权限申请是按照组来处理的,也就是说同属一个组的权限的请求是一样的,而用户只要授权一个,同组的权限也会同时被授权。SD卡的读写全是同属STORAGE组,所以我在申请SD卡读写权限的时候只申请读权限或者写权限就可以了。

    @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            switch (requestCode) {
                case 200:
                    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        mPhotoPopupWindow.dismiss();
                        Intent intent = new Intent(Intent.ACTION_PICK);
                        intent.setType("image/*");
                        // 判断系统中是否有处理该 Intent 的 Activity
                        if (intent.resolveActivity(getPackageManager()) != null) {
                            startActivityForResult(intent, REQUEST_IMAGE_GET);
                        } else {
                            Toast.makeText(UserInfoActivity.this, "未找到图片查看器", Toast.LENGTH_SHORT).show();
                        }
                    } else {
                        mPhotoPopupWindow.dismiss();
                    }
                    break;
                case 300:
                    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        mPhotoPopupWindow.dismiss();
                        imageCapture();
                    } else {
                        mPhotoPopupWindow.dismiss();
                    }
                    break;
            }
            //super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }

            到这里,运行时权限就已经处理好了。

    3.拍照和选图

    add 2018/5/11 11:30

            从这里开始就可能会NullPointerException,SecurityException等问题。

    3.1    拍照

    private void imageCapture() {
            Intent intent;
            Uri pictureUri;
            //getMyPetRootDirectory()得到的是Environment.getExternalStorageDirectory() + File.separator+"MyPet"
            //也就是我之前创建的存放头像的文件夹(目录)
            File pictureFile = new File(PictureUtil.getMyPetRootDirectory(), IMAGE_FILE_NAME);
            // 判断当前系统
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                //这一句非常重要
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                //""中的内容是随意的,但最好用package名.provider名的形式,清晰明了
                pictureUri = FileProvider.getUriForFile(this,
                        "com.example.mypet.fileprovider", pictureFile);
            } else {
                intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                pictureUri = Uri.fromFile(pictureFile);
            }
            // 去拍照,拍照的结果存到pictureUri对应的路径中
            intent.putExtra(MediaStore.EXTRA_OUTPUT, pictureUri);
            Log.e(TAG,"before take photo"+pictureUri.toString());
            startActivityForResult(intent, REQUEST_IMAGE_CAPTURE);
        }

            从android7.0(SDK>=24)开始,直接使用本地真实路径的Uri被认为是不安全的,会抛出一个FileUri什么什么Exception(记不清了),必须使用FileProvider封装过的Uri,感兴趣可以自己看下,7.0y以上得到的uri是content开头,以下以file开头。那么FileProvider怎么使用呢?

            首先,在res->xml文件文件夹下新建provider_paths.xml

    <?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <external-path path="MyPet/" name="MyPetRoot" />
        <external-path name="sdcard_root" path="."/>
    </paths>

            paths指定要用到的目录,external-path是SD卡根目录,所以我的第一条的路径是SD卡根目录下新建的MyPet文件夹,取名为MyPetRoot,这个虚拟目录名可以随意取,最终的Uri会是这样 content://com.example.mypet.fileprovider/MyPetRoot/......。第二条是将SD卡共享,这是用于相册选图。

            接下来,在AndroidManifest.xml中注册这个provider

    <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="com.example.mypet.fileprovider"
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/provider_paths" />
            </provider>

            有几点要注意:authorities要与之前使用FileProvider时""中的内容相同(实际上的逻辑是使用FileProvider时要与声明的authorites相同)。exported必须要并且只能设为false,否则会报错,其实也很好理解,我们将sd卡共享了,如果再设置成可以被外界访问,那么权限就没有用了。grantUriPermissions要设置为true,这样才能让其他程序(系统相机等)临时使用这个provider。最后在<meta-data />指定使用的resource,也就是我们刚才写的xml。

            现在我们回到imageCapture,还有两句没有解释。addflags的作用是给Intent添加一个标记(我不知道应该怎么叫,看我后面的解释),这里我们添加的是Intent.FLAG_GRANT_READ_URI_PERMISSION,他的作用是临时授权Intent启动的Activity使用我们Rrovider封装的Uri。最后一行启动拍照Activity,请求码是REQUEST_IMAGE_CAPTURE,这个值自己设置,用于区分回调结果来自哪个请求。这样,我们就完成了拍照请求,会跳转到系统拍照界面,接下来就要处理拍照得到的照片了。

            重写onActicityResult方法,我直接把所有请求先全贴了,拍照后的回调是case REQUEST_IMAGE_CAPTURE下的内容,逻辑很简单,拍照后需要裁剪,裁剪需要用到我们拍照得到的图片的Uri。

    @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            // 回调成功
            if (resultCode == RESULT_OK) {
                switch (requestCode) {
    
                    // 切割
                    case REQUEST_SMALL_IMAGE_CUTTING:
                        Log.e(TAG,"before show");
                        File cropFile=new File(PictureUtil.getMyPetRootDirectory(),"crop.jpg");
                        Uri cropUri = Uri.fromFile(cropFile);
                        setPicToView(cropUri);
                        break;
    
                    // 相册选取
                    case REQUEST_IMAGE_GET:
                        Uri uri= PictureUtil.getImageUri(this,data);
                        startPhotoZoom(uri);
                        break;
    
                    // 拍照
                    case REQUEST_IMAGE_CAPTURE:
                        File pictureFile = new File(PictureUtil.getMyPetRootDirectory(), IMAGE_FILE_NAME);
                        Uri pictureUri;
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                            pictureUri = FileProvider.getUriForFile(this,
                                    "com.example.mypet.fileprovider", pictureFile);
                            Log.e(TAG,"picURI="+pictureUri.toString());
                        } else {
                            pictureUri = Uri.fromFile(pictureFile);
                        }
                        startPhotoZoom(pictureUri);
                        break;
                    // 获取changeinfo销毁 后 回传的数据
                    case REQUEST_CHANGE_USER_NICK_NAME:
                        String returnData = data.getStringExtra("data_return");
                        InfoPrefs.setData(Constants.UserInfo.NAME,returnData);
                        textView_user_nick_name.setText(InfoPrefs.getData(Constants.UserInfo.NAME));
                        break;
                    default:
                }
            }else{
                Log.e(TAG,"result = "+resultCode+",request = "+requestCode);
            }
        }
            到这里,拍照的功能已经实现了,如果不想裁剪,可以直接将  sd卡根目录/MyPet/user_head_icon.jpg这张图片显示,接下来讲一下相册选取的实现。

    3.2    相册选取

            其实相册选取的代码我在上面已经完全贴过了,权限申请的时候已经调用了相册,OnActivityResult中处理回调,这里我要说一下我踩的一个大坑

    Uri uri= PictureUtil.getImageUri(this,data);

            具体的各种问题我已经记不清了,没办法进行梳理,我只能笼统的说一下了(本来想说的很多,结果解决后把坑玩的差不多了,嘤嘤嘤,以后要一边踩坑一边写)。总体上是因为android4.4开始相册中返回的图片不再是图片的真是Uri了,而是封装过的。我测试的时候返回的Uri五花八门,有的是可以正常处理的,有的需要进行解析,其中以小米最乱(不得不说MIUI对开发者各种不友好,为了用户体验各种不遵守规则)。最终在各种博客(可能是我用法的原因,有不少博客的方法我用了还是会报错)的洗礼下终于解决了,我把他封装在了PictureUtil里面,过程是    乱七八糟的uri ->真实路径 ->统一的uri 。

            部分 50% 来自《第一行代码》,部分 25% 来自他人博客,部分 25% 是我自己写的

    public class PictureUtil {
        private static final String TAG = "PictureUtil";
        private static final String MyPetRootDirectory = Environment.getExternalStorageDirectory() + File.separator+"MyPet";
    
        public static String getMyPetRootDirectory(){
            return MyPetRootDirectory;
        }
    
        public static Uri getImageUri(Context context,Intent data){
            String imagePath = null;
            Uri uri = data.getData();
            if(Build.VERSION.SDK_INT >= 19){
                if(DocumentsContract.isDocumentUri(context,uri)){
                    String docId = DocumentsContract.getDocumentId(uri);
                    if("com.android.providers.media.documents".equals(uri.getAuthority())){
                        String id = docId.split(":")[1];
                        String selection = MediaStore.Images.Media._ID+"="+id;
                        imagePath = getImagePath(context,MediaStore.Images.Media.EXTERNAL_CONTENT_URI,selection);
                    }else if("com.android.providers.downloads.documents".equals(uri.getAuthority())){
                        Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),Long.valueOf(docId));
                        imagePath = getImagePath(context,contentUri,null);
                    }
                }else if("content".equalsIgnoreCase(uri.getScheme())){
                    imagePath = getImagePath(context,uri,null);
                }else if("file".equalsIgnoreCase(uri.getScheme())){
                    imagePath = uri.getPath();
                }
            }else{
                uri= data.getData();
                imagePath = getImagePath(context,uri,null);
            }
            File file = new File(imagePath);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                uri = FileProvider.getUriForFile(context,
                      "com.example.mypet.fileprovider", file);
            } else {
                uri = Uri.fromFile(file);
            }
    
            return uri;
        }
    
        private static String getImagePath(Context context,Uri uri, String selection) {
            String path = null;
            Cursor cursor = context.getContentResolver().query(uri,null,selection,null,null);
            if(cursor != null){
                if(cursor.moveToFirst()){
                    path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                }
                cursor.close();
            }
            return path;
        }
    
        public static void mkdirMyPetRootDirectory(){
            boolean isSdCardExist = Environment.getExternalStorageState().equals(
                    Environment.MEDIA_MOUNTED);// 判断sdcard是否存在
            if (isSdCardExist) {
                File MyPetRoot = new File(getMyPetRootDirectory());
                if (!MyPetRoot.exists()) {
                    try {
                        MyPetRoot.mkdir();
                        Log.d(TAG, "mkdir success");
                    } catch (Exception e) {
                        Log.e(TAG, "exception->" + e.toString());
                    }
                }
            }
        }
    }

            到这里,有关图片获取的内容就都结束了

    4.图片裁剪

            前面传入的Uri处理好了,一般裁剪不会出什么问题,只有一个可能出现OOM(out of memory)问题,先上代码

    private void startPhotoZoom(Uri uri) {
            Log.d(TAG,"Uri = "+uri.toString());
            //保存裁剪后的图片
            File cropFile=new File(PictureUtil.getMyPetRootDirectory(),"crop.jpg");
            try{
                if(cropFile.exists()){
                    cropFile.delete();
                    Log.e(TAG,"delete");
                }
            }catch(Exception e){
                e.printStackTrace();
            }
            Uri cropUri;
            cropUri = Uri.fromFile(cropFile);
    
            Intent intent = new Intent("com.android.camera.action.CROP");
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                //添加这一句表示对目标应用临时授权该Uri所代表的文件
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            }
            intent.setDataAndType(uri, "image/*");
            intent.putExtra("crop", "true");
            intent.putExtra("aspectX", 1); // 裁剪框比例
            intent.putExtra("aspectY", 1);
            intent.putExtra("outputX", 300); // 输出图片大小
            intent.putExtra("outputY", 300);
            intent.putExtra("scale", true);
            intent.putExtra("return-data", false);
    
            Log.e(TAG,"cropUri = "+cropUri.toString());
    
            intent.putExtra(MediaStore.EXTRA_OUTPUT, cropUri);
            intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
            intent.putExtra("noFaceDetection", true); // no face detection
            startActivityForResult(intent, REQUEST_SMALL_IMAGE_CUTTING);
        }

    主要问题在这一句

    intent.putExtra("return-data", false);

    如果设置成true,那么裁剪得到的图片将会直接以Bitmap的形式缓存到内存中,Bitmap是相当大的,如果手机内存不足,或者手机分配的内存不足会导致OOM问题而闪退。当然,实际上现在的手机300X300一般不会OOM,但为了保险起见和可能需要更大图片的需求,最好将“return-data”置为false。

    5.保存并显示图片

            回调的代码在上面已经贴过了,这里可能会有一个疑问

    case REQUEST_SMALL_IMAGE_CUTTING:
                        Log.e(TAG,"before show");
                        File cropFile=new File(PictureUtil.getMyPetRootDirectory(),"crop.jpg");
                        Uri cropUri = Uri.fromFile(cropFile);
                        setPicToView(cropUri);
                        break;

            按理说应该分版本获取Uri,否则会抛出异常。实际上并非如此,我之前没有搞明白7.0的Uri保护到底是做什么的,后来看了文档才明白 : 

    一个应用提供自身文件给其它应用使用时,如果给出一个file://格式的URI的话,应用会抛出FileUriExposedException

            也就是说提供给外界时才需要fileprovider,也就是调用相机、相册、裁剪的时候才需要,自己使用是不需要的。谷歌做出这个改动的原因是 

    谷歌认为目标app可能不具有文件权限,会造成潜在的问题。所以让这一行为快速失败。

    好了,基本上所有的坑都踩完了,下面补上其他的代码

    public void setPicToView(Uri uri)  {
            if (uri != null) {
                Bitmap photo = null;
                try {
                    photo = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
                }catch (FileNotFoundException e){
                    e.printStackTrace();
                }
                // 创建 Icon 文件夹
                if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                    //String storage = Environment.getExternalStorageDirectory().getPath();
                    File dirFile = new File(PictureUtil.getMyPetRootDirectory(),  "Icon");
                    if (!dirFile.exists()) {
                        if (!dirFile.mkdirs()) {
                            Log.d(TAG, "in setPicToView->文件夹创建失败");
                        } else {
                            Log.d(TAG, "in setPicToView->文件夹创建成功");
                        }
                    }
                    File file = new File(dirFile, IMAGE_FILE_NAME);
                    InfoPrefs.setData(Constants.UserInfo.HEAD_IMAGE,file.getPath());
                    //Log.d("result",file.getPath());
                    // Log.d("result",file.getAbsolutePath());
                    // 保存图片
                    FileOutputStream outputStream = null;
                    try {
                        outputStream = new FileOutputStream(file);
                        photo.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
                        outputStream.flush();
                        outputStream.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                // 在视图中显示图片
                showHeadImage();
                //circleImageView_user_head.setImageBitmap(InfoPrefs.getData(Constants.UserInfo.GEAD_IMAGE));
            }
        }
    private void showHeadImage() {
            boolean isSdCardExist = Environment.getExternalStorageState().equals(
                    Environment.MEDIA_MOUNTED);// 判断sdcard是否存在
            if (isSdCardExist) {
    
                String path = InfoPrefs.getData(Constants.UserInfo.HEAD_IMAGE);// 获取图片路径
    
                File file = new File(path);
                if (file.exists()) {
                    Bitmap bm = BitmapFactory.decodeFile(path);
                    // 将图片显示到ImageView中
                    circleImageView_user_head.setImageBitmap(bm);
                }else{
                    Log.e(TAG,"no file");
                    circleImageView_user_head.setImageResource(R.drawable.huaji);
                }
            } else {
                Log.e(TAG,"no SD card");
                circleImageView_user_head.setImageResource(R.drawable.huaji);
            }
        }

    huaji是一张在没有头像情况下的默认头像

    6.总结

            最后做一个总结,如果按照以上代码执行的话,会在SD卡根目录下创建一下文件和文件夹

            dir:MyPet

            file:user_head_icon.jpg

            file:crop.jpg

                    dir:Icon

            file:user_head_icon.jpg


        MyPet/user_head_icon.jpg是拍照得到的原图,MyPet/crop.jpg是裁剪得到的图片,我们最后显示的是MyPet/Icon/user_head_icon.jpg,所以前两个如果不需要可以在最后删掉,删掉的代码我就不写了。


            最后的最后,UserInfoActivity和整个项目的完整代码可在我的GitHub获取:NeedKwok

           之后我也可能写一下如何实现一个闹钟




    展开全文
  • android 拍照

    2018-10-27 14:36:16
    android 拍照 一、布局:使用RecyclerView横向滑动显示。 二、拍照、系统适配 1、动态判断权限 2、FileProvider适配 &lt;provider android:name="a...

                                                                                        android 拍照

    • 一、布局:使用RecyclerView横向滑动显示。
    • 效果图
    • 二、拍照、系统适配
    • 1、动态判断权限
    • 2、FileProvider适配
    • <provider
          android:name="android.support.v4.content.FileProvider"
          android:authorities="包名.FileProvider"
          android:exported="false"
          android:grantUriPermissions="true">
          <meta-data
              android:name="android.support.FILE_PROVIDER_PATHS"
              android:resource="@xml/rc_file_path" />
      </provider>

      xml文件

    • <?xml version="1.0" encoding="utf-8"?>
      <paths>
          <external-path
              name="test"
              path="Android/data/com/test" />
          <external-path
              name="external_storage_root"
              path="." />
      </paths>

      自定义path路径

    • 3、拍照

    private void startDeviceCamera() {
        Intent mIntent = new Intent();
        mIntent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
        setSavePath();
        deviceFile = new File(saveFile, System.currentTimeMillis() + ".jpg");
        Uri uri = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkPermission()) {
                requestPermission();
            } else {
                mIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    uri = FileProvider.getUriForFile(this, "包名.FileProvider", deviceFile);
                } else {
                    uri = Uri.fromFile(deviceFile);
                }
            }
        } else {
            //6.0以下直接转换Uri
            uri = Uri.fromFile(deviceFile);
        }
        mIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        startActivityForResult(mIntent, 101);
    }
    
    private void setSavePath() {
        saveFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/test"); // 自定义路径
        if (!saveFile.exists()) {
            saveFile.mkdirs();
        }
    }

    三、设置数据

     

    Bean类  声明图片为Object类型

    private Object imgPath;

    向List添加数据

    AuthDeviceBean deviceBean = new AuthDeviceBean();
    deviceBean.setImgPath(R.mipmap.ic_apply_add);
    authDeviceList.add(deviceBean);

    为Adapter设置点击事件

    authDeviceAdapter.setOnItemClickListener(new BaseAdapter.OnItemClickListener() {
        @Override
        public void onItemClick(View view, int position) {
            if (position == authDeviceList.size() - 1) {
                    startDeviceCamera();
            }
        }
    });
    
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == 101) {
                if (deviceFile.exists() && deviceFile.isFile()) {
                    String imgPath = deviceFile.getAbsolutePath();
                    AuthDeviceBean authDeviceBean = new AuthDeviceBean();
                    authDeviceBean.setImgPath(imgPath);
                    authDeviceList.add(authDeviceList.size(), authDeviceBean);
                    authDeviceAdapter.notifyDataSetChanged();
                }
            }
        }
    }

    四、问题

    此时,连续拍照功能初步完成。运行发现,2个问题。

    问题1:拍第1张照片后,“+”号显示在照片前面。

    解决:onActivityResult() 方法中,向List添加数据

    authDeviceList.add(authDeviceList.size(), authDeviceBean);
    // 改为
    authDeviceList.add(authDeviceList.size() - 1, authDeviceBean);
    //注:通过add()方法,List长度减去1解决。

    问题2:未限制拍照个数。

    解决:adapter 点击事件中,进行判断。

    if (position == authDeviceList.size() - 1) {
                    startDeviceCamera();
            }
    // 例如:连续拍3张。通过List下标处理。
    if (position == authDeviceList.size() - 1) {
        if (authDeviceList.size() <= 3) {
            startDeviceCamera();
        } else {
            Toast.makeText(mContext, "最多3张", Toast.LENGTH_SHORT).show();
        }
    }

    连续拍照功能完成。

    展开全文
  • 使用android拍照,实现起来比较简单,直接调用手机内置的摄像头。调用代码android的demo程序中已经给出。我在上面稍微做了些修改。下面我们看下具体代码。 源代码见:...

    使用android拍照,实现起来比较简单,直接调用手机内置的摄像头。调用代码android的demo程序中已经给出。我在上面稍微做了些修改。下面我们看下具体代码。

    源代码见:http://zhengxdstudy.googlecode.com/svn/trunk/zhengxdstudy/Photo/

    import android.app.Activity; 
    import android.content.Intent; 
    import android.graphics.Bitmap; 
    import android.os.Bundle; 
    import android.provider.MediaStore; 
    import android.util.Log;

    public class PhotographActivity extends Activity { 
        /** Called when the activity is first created. */ 
        private String logTag = "Exception"; 
        @Override 
        public void onCreate(Bundle savedInstanceState) { 
            super.onCreate(savedInstanceState); 
            setContentView(R.layout.main); 
            try { 
                 Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
                 startActivityForResult(intent, 0); 
            } catch (Exception e) { 
                Log.v(logTag, e.getMessage()); 
            } 
        }

        protected void onActivityResult(int requestCode, int resultCode, Intent data) 
        { 
            try { 
                if (requestCode != 0) { 
                    return; 
                } 
                super.onActivityResult(requestCode, resultCode, data);

                Bundle extras = data.getExtras(); 
                Bitmap b = (Bitmap) extras.get("data"); 
                Intent intent = new Intent();

                //得到图片后,我们在另一个activity中显示 
                intent.setClass(this, ShowImageActivity.class); 
                intent.putExtra("image",b); 
                this.startActivity(intent); 
            } catch (Exception e) { 
                // TODO: handle exception 
                Log.v(logTag, e.getMessage()); 
            } 
        }

    }

    新建一个显示图片的activity。这样,在这个activity中就可以对图片做其他更多的操作。

    import android.app.Activity; 
    import android.graphics.Bitmap; 
    import android.os.Bundle; 
    import android.util.Log; 
    import android.widget.ImageView;

    public class ShowImageActivity extends Activity {

        private String logTag = "exception";

        private ImageView view; 
        @Override 
        protected void onCreate(Bundle savedInstanceState) { 
            super.onCreate(savedInstanceState); 
            setContentView(R.layout.show);

            try { 
                view = (ImageView) findViewById(R.id.view);   
                Bundle bundle = this.getIntent().getExtras(); 
                Bitmap b = bundle.getParcelable("image"); 
                view.setImageBitmap(b); 
                //setContentView(view); 
            } catch (Exception e) { 
                Log.v(logTag, e.getMessage()); 
                throw new RuntimeException(e); 
            } 
        } 
    }

    效果图如下:

      

    展开全文
  • 更换头像或者上传图片功能已基本是每个 APP 所具备的基础功能了,但这对于开发者来说是一个很麻烦的事情,除机型之外,适配版本就至少要考虑这几种情况(6.0以下版本、6.0的动态权限、7.0的FileProvider、8.0的特殊...
  • Android调用摄像头拍照(兼容7.0)

    万次阅读 多人点赞 2018-04-08 11:28:01
    先从一个简单的demo了解android拍照 xml代码 &lt;Button android:id="@+id/take_photo" android:layout_width="match_parent" android:layout_height="wrap_content" ...
  • android拍照或从相册选取图片

    千次阅读 2020-04-23 10:06:28
    从相册或拍照更换图片功能的实现:(取图无裁剪功能) 获取图片方式:(类似更换头像的效果) 手机拍照 选择图片; 相册选取图片; 本文只是简单实现该功能,页面展示有些简陋,运行效果图如下: 创建xml布局...
  • Android拍照,相册选择图片以及Android6.0权限管理

    万次阅读 多人点赞 2016-10-02 11:24:05
    概述在android开发过程中,拍照或者从相册中选择图片是很常见的功能。android6.0后,推出了动态权限管理。以往我们将涉及到的权限全部写在清单文件中,只要用户安装了该程序,程序在运行过程中都会获得相应权限。...
  • import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Calendar; import java.util.Locale;...import android.annotation.Su
  • 对于Android 6.0之前,想要使用系统的相机进行拍照,那么只要在AndroidManifedt.xml中进行添加相应的权限,主要是两个: uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> uses-...
  • android拍照开发android开发实现拍照功能主要有两种方法: 直接调用系统照相机API实现拍照,拍完后,图片会保存在相册中,返回保存照片的路径,从而获取图片。 自己写SurfaceView调用camera来实现拍照,该方法触发一...
  • 拍照前(预览): 拍照后(显示):  从上图可以看出拍照前跟拍照后清晰度完全不一致。当我把他保存为图片文件结果这个文件的大小只有10几KB,然后我使用其他机型的手机来测试结果出乎我的意料居然没问题。百度、谷歌...
  • Android 实现 拍照测距 的APP

    万次阅读 热门讨论 2016-05-09 16:54:19
    应朋友需求做了款拍照测距的APP,可以测出你到目标物体的距离。 源码发到了Github上,欢迎star、下载 github地址:点击打开链接 主要难点: 1.自定义相机 2.SurfaceView双缓冲问题 3.别的也没啥了  README.md...
  • android camera无预览拍照 后台拍照

    万次阅读 热门讨论 2013-10-03 20:28:21
    前言:相信有许多人和我一样,希望在不让用户知道的情况下,使用后台Server调用摄像头拍照, 在网上找了不少资料,大致都讲到不预览无法实现拍照,涉及到用户隐私,属于非法调用摄像头...怎么办!!! 曾经看到一篇...
  • Android播放照相机声音

    千次阅读 2011-08-05 09:20:05
    用华硕的一个Android 3.1平板电脑测试的时候。发现拍照没有声音。  由于需求需要加上声音,只好自己播放系统的照相机声音。 /** * 播放系统拍照声音 */ public void shootSound() { AudioManage
  • Android camera拍照分辨率

    千次阅读 2016-12-16 15:30:14
    camera拍照拍照之前需要设置camera parameter,不然拍照分辨率会按照系统默认的最低分辨率(160x120)来设置, Camera.Parameters param = mCamera.getParameters(); param.setPictureSize(1920, 1080); //如果不...
  • Android静默拍照(无感知拍照)

    万次阅读 2019-10-31 18:27:42
    在安卓系统下,实现拍照主要有两种方式:第一种就是直接调用系统的相机实现拍照,简单快捷。但是弊端就是不能自定义拍照界面。第二种就是根据Android系统提供的相关API进行自定义拍照,这样就是可以根据具体需求实现...
  • 拍照时弹出新的界面,像二维码那样有个框,需要按下拍照按钮才拍照拍照获取的只有被框住的图像? 是否有demo? 或者麻烦给个大概的代码
  • Android 7.0调用相机拍照,返回后显示拍照照片

    万次阅读 多人点赞 2017-11-29 08:33:02
    Android 7.0调用相机拍照,返回后显示拍照照片,并显示到手机相册中
  • Android调用系统相机拍照并保存到指定位置 @Click(R.id.btn_takePhoto) void onclick() { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File file = new File(imagePath, Utils.getCurrentDa
1 2 3 4 5 ... 20
收藏数 33,214
精华内容 13,285
关键字:

android拍照