闲来无事,正好以前老碰到这个磁盘空间满的问题

背景

安卓手机用了一段时间之后经常就报磁盘空间不够了,当然可以用手机管家,或者缓存/应用清理工具释放空间,但是还是会有莫名其妙的空间不够;这是由安卓的属性导致的,即使把APP卸载,他占用的空间SD卡空间也不会被释放。

image.png

导致的结果是SD空间会越来越紧张,最后只能恢复出厂设置解决问题。

谁用了我的空间

我们自然会想到底是谁用了我的SD卡空间呢;现在各个厂家安卓系统都会提供一定功能,检测大文件,检测应用占用大空间;但是到目前我还没有发现有基于目录罗列的,列出每一个目录,每一个文件占用多大的空间,因为有了这个,我们就比较清楚,到底是谁在占用我们的空间。

然后我们可以自己判断,是否可以删除这个文件或者目录。手动把文件删除,以释放空间。

我的SD卡扫描程序

基于上述目标,反正闲着也是闲着,写了一个很简单的SD卡扫描程序,列出所有的大文件。

程序主题页面如下:

image.png

第一个输入框指示扫描多大的文件(M),点击"Scan"按钮,在下面的列表框中,显示出SD卡所有的大于指定大小的文件,在这个例子中一共22个大于5M的大文件。

这里我们可以看到Baidu_music和baiduTTS下面有很多大文件,这些文件是可以放心的删除的,而用手机管家(华为家的)就扫不出这个问题,他会认为这些是真实的APP文件,不能删除。

贴代码,供参考

在Android 6.0上测试通过。

AndroidManifest.xml

package="com.example.mydiskscan">

android:allowBackup="true"

android:icon="@mipmap/ic_launcher"

android:label="@string/app_name"

android:supportsRtl="true"

android:theme="@style/AppTheme">

这个地方,注意一点,因为其他都是缺省生成的:

我们需要SD卡的读取权限,因为要扫描SD卡啊。

两个layout文件

activity_main.xml

这是主activity,也就是APP的主界面。

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

android:focusable="true"

android:focusableInTouchMode="true"

tools:context="com.example.mydiskscan.MainActivity">

android:layout_width="match_parent"

android:layout_height="76dip"

android:orientation="horizontal" >

android:layout_width="80dip"

android:layout_height="40dip"

android:inputType="numberDecimal"

android:text="5"

android:id="@+id/edit_size"

android:contentDescription="Scan file greater than" />

android:layout_width="40dip"

android:layout_height="40dip"

android:text="M"

android:id="@+id/textView" />

android:text="Scan"

android:layout_width="120dip"

android:layout_height="40dip"

android:id="@+id/button_scan" />

android:layout_width="match_parent"

android:layout_height="match_parent"

android:id="@+id/list_file" />

注意在头上的这两行:

android:focusable="true"

android:focusableInTouchMode="true"

这两行是用来使得APP刚打开的时候焦点不在EditText框里面,否则每回一打开,焦点定位输入框,输入法窗口就显示出来,极不美观大方。

filelistitem.xml

这是文件的列表项的view,每一个大于指定大小的大文件,包含一项;内容包含序号,大小,和文件路径。

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="horizontal" >

android:id="@+id/filelistitem_id"

android:layout_width="20dp"

android:layout_height="20dp" />

android:id="@+id/filelistitem_size"

android:layout_width="40dp"

android:layout_height="20dp" />

android:id="@+id/filelistitem_path"

android:layout_width="wrap_content"

android:layout_height="20dp" />

activity源代码文件

作为简易程序,我把所有的代码都放在了一个源文件里面;当然这不是规范的做法,不符合软件工程的追求啊。

package com.example.mydiskscan;

import android.Manifest;

import android.app.Activity;

import android.content.pm.PackageManager;

import android.os.Bundle;

import android.os.Environment;

import android.os.StatFs;

import android.util.Log;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.Button;

import android.widget.EditText;

import android.widget.ListView;

import android.widget.TextView;

import java.io.File;

import java.util.ArrayList;

import java.util.List;

public class MainActivity extends Activity {

private static final String tag = MainActivity.class.getSimpleName();

private List fileList = new ArrayList();

private FileListAdapter fileListAdapter = new FileListAdapter();

private ScanListener scanListener = new ScanListener();

private EditText edtThreshold;

private ListView listFileView;

private Button btnScan;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

requestStoragePermission();

edtThreshold = (EditText)findViewById(R.id.edit_size);

listFileView = (ListView)findViewById(R.id.list_file);

btnScan = (Button) findViewById(R.id.button_scan);

btnScan.setOnClickListener(scanListener);

listFileView.setAdapter(fileListAdapter );

}

private void requestStoragePermission() {

String[] permissions = {"android.permission.READ_EXTERNAL_STORAGE"};

int requestCode = 200;

int permission = checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE);

if (permission != PackageManager.PERMISSION_GRANTED) {

requestPermissions(permissions, requestCode);

}

}

private long getFileSize(String prefix, File file, int threshold) {

long size = file.length();

if (file.isDirectory()) {

File[] subs = file.listFiles();

if (subs != null) {

for (File sub : subs) {

size += getFileSize(prefix, sub, threshold);

}

}

}

float sizem = (float) (size * 1.0 / 1024 / 1024);

if (sizem > threshold && !file.isDirectory()) {

String path = file.getPath();

if (path.startsWith(prefix)) {

path = path.substring(prefix.length());

}

Log.i(tag, "File: path=" + path + ", size= " + sizem);

fileList.add(new ViewFile(path, sizem));

}

return size;

}

class ViewFile {

ViewFile(String p, float s) {

path = p;

size = s;

}

private String path;

private float size;

}

class ScanListener implements View.OnClickListener {

@Override

public void onClick(View v) {

StatFs sf = null;

long blockSize = 0, total = 0, free = 0, available = 0;

/*

File root = Environment.getRootDirectory();

sf = new StatFs(root.getPath());

blockSize = sf.getBlockSize();

total = sf.getBlockCount() * blockSize/1024/1024;

free = sf.getFreeBlocks() * blockSize/1024/1024;

available = sf.getAvailableBlocks() * blockSize/1024/1024;

Log.i(tag, "Root Storage: path = " + root.getAbsolutePath() + ", total=" + total + ", free=" + free + ", available=" + available);

*/

String state = Environment.getExternalStorageState();

if(Environment.MEDIA_MOUNTED.equals(state)) {

File sdcardDir = Environment.getExternalStorageDirectory();

//sf = new StatFs(sdcardDir.getPath());

//blockSize = sf.getBlockSize();

//total = sf.getBlockCount() * blockSize/1024/1024;

//free = sf.getFreeBlocks() * blockSize/1024/1024;

//available = sf.getAvailableBlocks() * blockSize/1024/1024;

//Log.i(tag, "External Storage: path=" + sdcardDir.getAbsolutePath() + ", total=" + total + ", free=" + free + ", available=" + available);

if (sdcardDir.isDirectory()) {

File[] subs = sdcardDir.listFiles();

if (subs != null) {

fileList.clear();

int threshold = 5;

try {

threshold = Integer.parseInt(edtThreshold.getText().toString());

} catch (NumberFormatException e) {

edtThreshold.setText("5");

}

for (int i = 0; i < subs.length; i++) {

getFileSize(sdcardDir.getPath(), subs[i], threshold);

}

fileListAdapter.notifyDataSetChanged();

}

}

}

}

}

class FileListAdapter extends BaseAdapter {

@Override

public int getCount() {

return fileList.size();

}

@Override

public View getView(int position, View convertView, ViewGroup parent) {

View view = null;

if(convertView == null){

LayoutInflater inflater = MainActivity.this.getLayoutInflater();

view = inflater.inflate(R.layout.filelistitem, null);

}else{

view = convertView;

}

ViewFile m = fileList.get(position);

TextView v = (TextView)view.findViewById(R.id.filelistitem_id);

v.setText( String.valueOf(position + 1) );

v = (TextView)view.findViewById(R.id.filelistitem_size);

v.setText( String.valueOf(m.size) );

v = (TextView)view.findViewById(R.id.filelistitem_path);

v.setText( m.path );

return view;

}

@Override

public Object getItem(int position) {

// TODO Auto-generated method stub

return null;

}

@Override

public long getItemId(int position) {

// TODO Auto-generated method stub

return 0;

}

}

}

几个注意的地方:

requestStoragePermission();

虽然在manifest文件里面指定了需要SD卡的读权限,但是后来的版本都需要APP显式的请求用户确认,以获取相应的权限,否则即使在manifest指定了权限,APP还是无法访问SD卡。

image.png

后续还可以增强一下

增加等待提示符,也就是在扫描的同时,提示用户我正在扫描,请稍后。

界面和代码可以继续美化改进

谢谢。

android 输入法sd卡,如何android扫描SD卡列出大文件相关推荐

  1. 开发android 输入法,Android输入法开发实例解析 Android开发技术

    Android输入法开发实例解析 Android开发技术 2013 年 4 月 13 日 这里我们建立表1为BiHua,同时构建两个字段,字段1为"input"来存放输入的,字段2 ...

  2. android pda界面美化,安卓设备扫描cpu卡和rfid超频卡插件cordova-plugin-pda

    1.该插件只支持安卓设备,可以扫描上海复旦fm1216卡(CPU卡),s50卡,rfid超频卡等:这是我写的一个cordova插件,下面是安装步骤 2.安装方法: cordova plugin add ...

  3. android 输入法 候选,写一个Android输入法02——候选窗、转换

    上一篇介绍了完成Android输入法的最小化步骤,它只能将按键对应的字符上屏.一般的东亚语言都有一个转换的过程,比如汉语输入拼音,需要由拼音转成汉字再上屏.本文将在前文基础上加入完成转换过程所必需的候 ...

  4. 哪些公司开发android输入法软件,六款Android平台第三方输入法软件横评

    虽然现在非智能手机在第三方应用上已经有了相当大的进步,不少已经支持软件后台运行,与智能手机一样可以同时挂QQ.听音乐.看网页等等.不过安装第三方输入法仍然还只是智能手机的专利.记得第一次在诺基亚668 ...

  5. 2022-09-06 Android输入法顶起输入框,遮挡RecyclerView

    背景 IM项目中的会话界面,一般就是顶部一个标题,底部是输入区域,中间显示消息列表. 微信的会话界面中,进入会话界面,有以下几点: 隐藏输入法 当消息数量能占满屏幕时,底部显示最后一条,依次往上排列 ...

  6. Android基础—基于Socket实现上传大文件

    上节中我们给大家接触了Socket的一些基本概念以及使用方法,然后写了一个小猪简易聊天室的 Demo,相信大家对Socket有了初步的掌握,本节我们来学习下使用Socket来实现大文件的断点续传! 这 ...

  7. android 扫描手机内存和SD卡,获取手机的视频、音频文件。把获取不到的文件扫描出来

    网上查了下android手机扫描内存或者SD卡里面的音频或者视频文件,进行显示.但是有些视频或者音频扫描不出来.有其中一个原因是当你添加了一个视频或者音频文件后,手机自身没有重新进行扫描.只有手机重启 ...

  8. android 无法显示SD卡目录,Android studio无法在SD卡上创建新目录?

    我使用名为scanlibrary的库来扫描照片,然后将它传递给tess-two来执行OCR过程.问题是,在目录"ScanDemoExample"不被创建因此tessdata文件不会 ...

  9. android ProgressBar实现扫描SD卡文件 + SimpleAdapter绑定ListView

    代码 activity_main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/andro ...

最新文章

  1. ubuntu 查看内存和cpu使用情况
  2. 腾讯GaiaStack容器平台负责人罗韩梅:All on GaiaStack
  3. CAN总线抗干扰的六种解决方案
  4. leetcode——面试题 17.10. 主要元素
  5. CompletableFuture 异步编程
  6. 罗马音平假名片假名转换器_记不住五十音的你,你肯定需要这套日语五十音谐音巧记法...
  7. C语言基础教程读书笔记2(第二章常量、变量、类型转换)
  8. 华为与奔驰展开合作 HMS for Car登陆S级轿车
  9. put与putIfAbsent区别
  10. FPGA厂家谁家强?
  11. 开始学习鸟哥的Linux私房菜-基础篇(第五章)
  12. 如何将pdf分割成一页一页的
  13. c语言学习——设圆半径r = 1.5,圆柱高h = 3,求圆周长,圆面积,圆球表面积,圆球体积,圆柱体积
  14. LeedCode 376. 摆动序列
  15. 如何用echarts组件制作图表
  16. 史玉柱: 我的成功不是偶然
  17. Java 本地接口(JNI)编程指南和规范学习笔记2
  18. vue+echarts+3D地图 制作大屏
  19. 虎父的素数年之黄帝内经谭
  20. linux下ant编译android,linux(以ubuntu為例)下Android利用ant自動編譯、修改配置文件、批量多渠道,打包生成apk文件...

热门文章

  1. 大一matlab知识整理,MATLAB基础课程 第二章 MATLAB绘图知识(5)
  2. java 指针 引用_java中的引用与c中的指针
  3. python随机生成奇数_python实现按照给定范围随机生成小数,偶数,奇数,整数,正态分布,均匀分布数据以及图片...
  4. devops 解决方案_DevOps是值得投资的职业倦怠解决方案
  5. angular 创建服务器_使用D3和Angular创建通用的可视化
  6. VSCode自定义代码片段9——JS中的面向对象编程
  7. 组件化开发_思维导图
  8. 面试 | #面试面试面试 做#Java 就是要这种不要脸的…
  9. Bootstrap3 模态对话框的事件
  10. Integer 数据类型