多个Fragment界面重叠和拍照闪退问题

记录最近遇到的多个Fragment界面重叠和调用系统相机拍照闪退问题,同时总结解决方案。

----------------------------------------------------------------------------------------------------------------------------------------------------------------

环境:Activity(一个)+Fragment(多个)

问题一:多个fragment出现重叠现象

首先,Android管理Fragment有两种方式,使用add、hide、show的方式和replace方式,两种方式各有优缺点。

--> replace方式
如果使用这种方式,是可以避免重叠的问题,但是每次replace会把生命周期全部执行一遍,如果在这些生命周期函数里拉取数据的话,就会不断重复的加载刷新数据,所以我们并不推荐使用这种方式。

--> add、hide、show的方式
虽然这种方式避免了可能重复加载刷新数据的问题,但是会出现重叠的问题。

原因:

当系统内存不足,Fragment 的宿主 Activity 回收的时候,Fragment 的实例并没有随之被回收。Activity 被系统回收时,会主动调用 onSaveInstance() 方法来保存视图层(View Hierarchy),所以当 Activity 通过导航再次被重建时,之前被实例化过的 Fragment 依然会出现在 Activity 中,此时的 FragmentTransaction 中的相当于又再次 add 了 fragment 进去的,hide()和show()方法对之前保存的fragment已经失效了,所以就出现了重叠。
然而我们还是推荐使用这个,我们可以解决。

解决方法:MainActivity.Class中重写onAttachFragment,重新让新的Fragment指向了原本未被销毁的fragment,它就是onAttach方法对应的Fragment对象

 @Override
    public void onAttachFragment(Fragment fragment) {
        if (tab1 == null && fragment instanceof Tab1Fragment)
            tab1 = fragment;
        if (tab2 == null && fragment instanceof Tab2Fragment)
            tab2 = fragment;
        if (tab3 == null && fragment instanceof Tab3Fragment)
            tab3 = fragment;
        if (tab4 == null && fragment instanceof Tab4Fragment)
            tab4 = fragment;
    }

问题二:调用系统相机拍照闪退

在onActivityResult方法里通过Intent的getData方法获取的数据转换成bitmap并显示在界面上,有时候会有取不到数据,或者显示的bitmap会非常小,如果将bitmap保存到sd卡后会发现,图片的分辨率很低,并且图片大小也是经过压缩的,不管将相机的像素设置多高,最后通过这种方式返回的bitmap总是经过压缩了的。如果想获得理想的照片大小和分辨率改如何处理呢?以下是我的处理方法,虽然不是最好,但是帮我解决了这个需求。我先来简述一下为什么返回的图片是经过了压缩的。

大家都知道,现在手机像素少则500W或800W,多则4KW(某亚),就拿常见的800W像素的相机拍出来的照片来说,分辨率大概在3200*2400左右,我的测试机型是LG optimus 2x,2.3.7的系统,用800W像素拍出来大概就是这个分辨率,照片大小在2M左右。试想一下,在Android系统中最常用的Bitmap格式(ARGB_8888)一个像素占用4byte(字节),例如一张分辨率为3200*2400px的照片,其耗用内存情况是:3200*2400*4/1024/1024=29.296875(MB)。如果为了一张图片,耗用这么大的内存,肯定是不合理的,并且,官方文档中有说明,Android系统分配给每个应用的最大内存是16M,所以,系统为了防止应用内存占用过大,对于在应用内通过相机拍摄的图片最终返回来的结果进行了压缩,压缩后的图片变得很小,通过之前说的getData的方式只能满足比如显示个头像这样的需求,如果要显示大图,就会出现模糊的情况。如何获得清晰的大图,思路如下:

1.拍照时,将拍得的照片先保存在本地,其中启动相机程序如下;

        Intent getImageByCameraIntent = new Intent("android.media.action.IMAGE_CAPTURE");                Uri imageUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "image.jpg"));                getImageByCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);          startActivityForResult(getImageByCameraIntent, TAKE_PHOTO);

2.在onActivityResult方法中再将图片取出,并经过缩小处理再显示在界面上或保存在自定义文件夹下,其中压缩比例自定义;

   @Override  
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            switch (requestCode) {
            case TAKE_PICTURE:

          //将保存在本地的图片取出并缩小后显示在界面上
                    Bitmap bitmap = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+"/image.jpg");
                    Bitmap newBitmap = ImageTools.zoomBitmap(bitmap, bitmap.getWidth() / SCALE, bitmap.getHeight() / SCALE);
                    //由于Bitmap内存占用较大,这里需要回收内存,否则会报out of memory异常
                    bitmap.recycle();

                    //将处理过的图片显示在界面上,并保存到本地
                    //取当前时间为照片名
                   String imageName= DateFormat.format("yyyyMMdd_hhmmss",Calendar.getInstance(Locale.CHINA))+".png";
                   ImageTools.savePhotoToSDCard(newBitmap, getPhotoPath(), imageName);
          break;
            default:
                break;
            }
        }
    }

其中ImageTools是自定义的图片工具类,zoomBitmap()和savePhotoToSDCard()方法具体如下:

/**
* Resize the bitmap
*
* @param bitmap
* @param width
* @param height
* @return
*/
public static Bitmap zoomBitmap(Bitmap bitmap, int width, int height) {
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        Matrix matrix = new Matrix();
        float scaleWidth = ((float) width / w);
        float scaleHeight = ((float) height / h);
        matrix.postScale(scaleWidth, scaleHeight);
        Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);
        return newbmp;
    }

    /**
     * Save image to the SD card
     * @param photoBitmap
     * @param photoName
     * @param path
     */
    public static void savePhotoToSDCard(Bitmap photoBitmap,String path,String photoName){
        if (checkSDCardAvailable()) {
            File dir = new File(path);
            if (!dir.exists()){
                dir.mkdirs();
            }

            File photoFile = new File(path , photoName );
            FileOutputStream fileOutputStream = null;
            try {
                fileOutputStream = new FileOutputStream(photoFile);
                if (photoBitmap != null) {
                    if (photoBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)) {
                        fileOutputStream.flush();
                    }
                }
            } catch (FileNotFoundException e) {
                photoFile.delete();
                e.printStackTrace();
            } catch (IOException e) {
                photoFile.delete();
                e.printStackTrace();
            } finally{
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    } 

说明:由于Android给bitmap分配的内存最大不超过8M,所以对使用完的较大的Bitmap要释放内存,调用其recycle()方法即可。然后将缩小(缩小方法在Demo源码中有)后的bitmap显示在界面上或保存到SD卡,至于之前保存的原图,可以删掉,也可以放在那,下次拍照时,这张原图就会被下一张照片覆盖,所以SD卡上使用只有一张临时图片,占用也不是很大。

---------------------------------------------------------------------------------------------------------------------------------

参考资料:

http://blog.csdn.net/whitley_gong/article/details/51987911    //关于Fragment重叠问题分析和解决

https://m.th7.cn/show/14/201612/1045726.html        //android系统相机的使用、及解决拍照闪退的问题

http://m.blog.csdn.net/article/details?id=8654137   //Android相机、相册获取图片显示并保存到SD卡

时间: 2024-08-01 08:56:30

多个Fragment界面重叠和拍照闪退问题的相关文章

Android横屏下Fragment界面重叠问题

前言: 项目是基于平板开发的,设计的界面是要求横屏展示界面.所以我将所有的Activity都强制设置为横屏 android:screenOrientation="landscape" ----------------------------------------------------------------------------------------------------- 问题: 主界面,最常见的Activity+n个Fragment 我这里使用的hide.show Fra

安装Linux 16.04 时,选择好分区后,进到选择地点的界面后,总是闪退,退到最原始的界面

这两天装 Linux 系统,总是遇到一个很蛋疼的问题: 当你累死累活把分区什么的都设置好了之后,在输入了系统名字,开机密码那几项之后,再选择地点的时候(如:选择 "上海"),然后就会卡死,然后,闪退到,刚开始进去安装镜像的那个界面,怎么回事呢? --- 答曰:万恶的Linux,万恶的网线!  将网线拔掉(即:装Linux时,千万不要联网)...就可以了,一切顺利,我尼玛,浪费了很长时间解决这个问题. 以为是系统镜像问题,重新做了多少次系统启动盘:以为是显卡问题,拔掉显卡重新装,还是这样

解决ubuntu上在androidstudio中启动emulator闪退的问题

作者 彭东林 [email protected] 平台 Ubuntu14.04 64 androidstudio 2.3.3 现象 在创建好模拟器后,点击启动时,模拟器界面刚出来就闪退了 解决 由于是在图形界面点击启动的,看不到任何出错的log,所以我们需要使用命令行启动emulator的方式,这样会把出错的信息打印出来. 1.查看我们创建的模拟器的名字: 从上图看到模拟器的名字是: 32_QVGA_ADP2_API_25 2.找到android sdk中模拟器 对于我的机器,模拟器存放在/ho

解决Linux Kettle出现闪退问题

linux环境, 运行sh spoon.sh打开图形化界面时经常出现闪退情况. 报错信息如下: cfgbuilder - Warning: The configuration parameter [org] is not supported by the default configuration builder for scheme: sftpjava: cairo-misc.c:380: _cairo_operator_bounded_by_source: Assertion `NOT_RE

DOSBox闪退问题

最近学习王爽的<汇编语言>,里面提到了用debug操作寄存器,但是64位系统没有debug命令了,解决办法是下载DOSBox,这个网上有很多教程. 按照网上教程安装好后,双击DOSBox 0.74.exe启动后出现如下界面一会就闪退. 自己试了好几次之后终于发现了门道,解决办法很神奇,哈哈.就是在上面那个界面还没有闪退时点一下后面那个大的窗口,让大窗口在前面,像下面这样.后面大窗口把小窗口覆盖了,所以看不到小窗口了. 点了之后,这样过一会,就启动成功了,出现如下界面. 输入debug命令玩起来

Android 使用Fragment界面向下跳转并一级级返回

1.首先贴上项目结构图: 2.先添加一个接口文件BackHandledInterface.java,定义一个setSelectedFragment方法用于设置当前加载的Fragment在栈顶,主界面MainActivity须实现此接口,代码如下: package com.example.testdemo; public interface BackHandledInterface { public abstract void setSelectedFragment(BackHandledFrag

安卓使用Intent开启照相机拍照时闪退的处理

1.现象 在使用安卓手机的一些应用调用照相机时,我们会发现有时候当我们拍照完毕时,程序会出现闪退,非常影响用户体验.目前项目中也有类似的拍照上传功能,当使用米3手机测试时,拍照上传功能可以正常使用,当我们换上红米或者其他一些比较早或者比较低端的手机时,就出现了闪退的问题. 1.1开启相机的intent /* mPictureCachePath为当前照相相片的存储路径 */ pictureCachePath = Utility.getExternalCacheDir(this)+...; inte

Linux登录图形界面闪退&quot;终极&quot;解决方法

其实是一个笨方法...但很有效 (个人经验,仅供参考) 实测环境:Debian 9 64bit  gnome3 起因是使用apt-get安装了fcitx fcitx-pinyin fcitx-tools,后执行 im-config 配置,又卸载了ibus. 不知道哪里出了问题,登出gnome3后无法再次登入了. 现象: 1.键入密码后,应该是通过进入了,但桌面尚未加载完即闪退回登录界面. 2.root用户可以正常登入 3.等入xfce正常 4.各版本gnome均闪退 5.字符终端正常,各命令使用

【重要】安卓微信闪退,非清空数据法解决,不破坏聊天记录【完善中】

前言 [本文不建议跳读.少读] 之前研究过微信记录的恢复办法,对其存储结构稍有了解,今天又遇到闪退的问题,真想用现在流行的话说:日了狗了. 于是乎,到网上搜索了一番,全是让你清除数据.重装.卸载之类的.对于这些方法,我只想说,简直就是害人.如果你是刚装的微信这样做,或者聊天记录对你来说不重要,那么你就去折腾.但是,度过聊天记录对你来说很重要,那么,请慎重! 本文通过自己的探索,寻求了闪退的终极解决办法,如果还不能解决,需要保全聊天记录的,可以联系我来帮您导出,切勿手贱! 症状描述 最近老是提示空