KillProcessesWithOpenFiles /sdcard

android在处理sdcard被占用后会扫描哪些进程的还占有sdcard上的文件的文件句柄,这些进程都将被kill,一般导致的情况就是程序被退出了,这里就不做什么评价了。

我们要做的处理就是监听sdcard的状态,这里看看系统播放器的源码中的处理

    /**
     * Registers an intent to listen for ACTION_MEDIA_EJECT notifications.
     * The intent will call closeExternalStorageFiles() if the external media
     * is going to be ejected, so applications can clean up any files they have open.
     */
    public void registerExternalStorageListener() {
        if (mUnmountReceiver == null) {
            mUnmountReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    String action = intent.getAction();
                    if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
                        saveQueue(true);
                        mOneShot = true; // This makes us not save the state again later,
                                         // which would be wrong because the song ids and
                                         // card id might not match. 
                        closeExternalStorageFiles(intent.getData().getPath());
                    } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
                        mMediaMountedCount++;
                        mCardId = MusicUtils.getCardId(MediaPlaybackService.this);
                        reloadQueue();
                        notifyChange(QUEUE_CHANGED);
                        notifyChange(META_CHANGED);
                    }
                }
            };
            IntentFilter iFilter = new IntentFilter();
            iFilter.addAction(Intent.ACTION_MEDIA_EJECT);
            iFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
            iFilter.addDataScheme("file");
            registerReceiver(mUnmountReceiver, iFilter);
        }
    }

在closeExernalStorageFiles中,对player进行了reset(),如果有打开本地文件的,需要在这里进行close。

但是也遇到了一些情况就是还没接收receiver的信息,进程就被kill了,提高了recevier的优先级也没能起做用,暂时还没有解决办法。


还有一个问题,关于MappedByteBuffer的unmap的缺失。

MappedByteBuffer只能通过调用FileChannel的map()取得,再没有其他方式.但是令人奇怪的是,SUN提供了map()却没有提供unmap().这样会导致什么后果呢? 
举个例子,文件test.tmp是一个临时构建的文件,在业务处理(通过SocketChannel发送)完之后将不再有效.一般的做法都是这样的: 
(1)File file = new File("test.tmp"); 
FileInputStream in = new FileInputStream(file); 
FileChannel ch = in.getChannel(); 
MappedByteBuffer buf = ch.map(FileChannel.MapMode.READ_ONLY, 0, file.length()); 

(2)SocketChannel sch = 已经构造好了; 
while (buf.hasRemaining()) 
sch.write(buf); 

(3)ch.close(); 
in.close(); 
file.delete(); 

上面的操作都会正常的完成,除了最后一步:文件无法删除!即使你通过资源管理器直接强制删除也不行,说"文件正在使用". 
为什么会出现这种情况? 
说"文件正在使用",说明文件句柄没有清零,还有在使用它的地方---就是被MappedByteBuffer占用了!尽管FileChannel,FileInputStream都已经关闭了,但是在map里还打开着一个文件句柄.但是在外部看不见也无法操作它.那么这个句柄在什么时候才会正常地关闭呢?根据JAVADOC的说明,是在垃圾收集的时候.而众所周知垃圾收集是程序根本无法控制的. 
既然MappedByteBuffer是从FileChannel中map()出来的,为什么它又不提供unmap()呢?SUN自己也没有讲清楚为什么.O'Reilly的<<Java NIO>>中说是因为"安全"的原因,但是到底unmap()会怎么不安全,作者也没有讲清楚. 

所以我觉得这似乎就将MappedbyteBuffer在android判了半个死刑,暂时是RandomAccessFile来进行代替。

更多的介绍

其实掌握MappedByteBuffer并不难,只要记住“三方三法三特性”(我自己总结的,呵呵~~不要扔鸡蛋哦。。。)这句话就可以轻松搞定!MappedByteBuffer 只是一种特殊的 ByteBuffer ,即是ByteBuffer的子类。 MappedByteBuffer 将文件直接映射到内存(这里的内存指的是虚拟内存,并不是物理内存,后面说证明这一点)。通常,可以映射整个文件,如果文件比较大的话可以分段进行映射,只要指定文件的那个部分就可以。而且,与ByteBuffer十分类似,没有构造函数(你不可new MappedByteBuffer()来构造一个MappedByteBuffer),我们可以通过 java.nio.channels.FileChannel 的 map() 方法来获取 MappedByteBuffer 。其实说的通俗一点就是Map把文件的内容被映像到计算机虚拟内存的一块区域,这样就可以直接操作内存当中的数据而无需操作的时候每次都通过I/O去物理硬盘读取文件,所以效率上有很大的提升!

三种方式:

              FileChannel提供了map方法来把文件影射为内存映像文件: MappedByteBuffer map(int mode,long position,long size); 可以把文件的从position开始的size大小的区域映射为内存映像文件,mode指出了 可访问该内存映像文件的方式:READ_ONLY,READ_WRITE,PRIVATE.                     

a. READ_ONLY,(只读): 试图修改得到的缓冲区将导致抛出 ReadOnlyBufferException.(MapMode.READ_ONLY)

       b. READ_WRITE(读/写): 对得到的缓冲区的更改最终将传播到文件;该更改对映射到同一文件的其他程序不一定是可见的。 (MapMode.READ_WRITE)

        c. PRIVATE(专用): 对得到的缓冲区的更改不会传播到文件,并且该更改对映射到同一文件的其他程序也不是可见的;相反,会创建缓冲区已修改部分的专用副本。 (MapMode.PRIVATE)

 

三个方法:

a. fore();缓冲区是READ_WRITE模式下,此方法对缓冲区内容的修改强行写入文件

b. load()将缓冲区的内容载入内存,并返回该缓冲区的引用

c. isLoaded()如果缓冲区的内容在物理内存中,则返回真,否则返回假

三个特性:

调用信道的map()方法后,即可将文件的某一部分或全部映射到内存中,映射内存缓冲区是个直接缓冲区,继承自ByteBuffer,但相对于ByteBuffer,它有更多的优点:

a. 读取快

b. 写入快

c. 随时随地写入

       口说无凭,俗话说的好,是金子是银子拿来炼一炼就知道(也不知道有没有这么一句俗话,反正用到这还合适,就这么凑合吧,大家扔鸡蛋~~~)!

1 MappedByteBuffer的读取/写入文件和普通I/O流的对比

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.nio.ByteBuffer;

import java.nio.CharBuffer;

import java.nio.MappedByteBuffer;

import java.nio.channels.FileChannel;

import java.nio.charset.Charset;

import java.nio.charset.CharsetDecoder;

 

 

public class MapMemeryBuffer {

       public static void main(String[] args) throws Exception {

              ByteBuffer byteBuf = ByteBuffer.allocate(1024 * 14 * 1024);

              byte[] bbb = new byte[14 * 1024 * 1024];

              FileInputStream fis = new FileInputStream("d://test");

              FileOutputStream fos = new FileOutputStream("d://outFile.txt");

              FileChannel fc = fis.getChannel();

             

              long timeStar = System.currentTimeMillis();//得到当前的时间

 

              fc.read(byteBuf);//1 读取

 

              long timeEnd = System.currentTimeMillis();//得到当前的时间

 

              System.out.println("Read time :" + (timeEnd - timeStar) + "ms");

              timeStar = System.currentTimeMillis();

 

              fos.write(bbb);// 写入

 

              timeEnd = System.currentTimeMillis();

              System.out.println("Write time :" + (timeEnd - timeStar) + "ms");

              fos.flush();

              fc.close();

              fis.close();

       }

}

输出结果:

Read time :1874ms

Write time :360ms

把上面的程序的1换成MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fileLength);

2换成mbb.flip();

输出结果:

Read ByteBuf take time :16ms

Write ByteBuf take time :0ms

可见普通I/O和MappedByteBuffer是没法比的。另外在写入的时候花了0ms说明Map写入机制是根据你的更改量来决定,就是只保存修改部分的!





http://zhangwenzhuo.iteye.com/blog/163754

http://blog.csdn.net/mgoann/article/details/3345850

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值