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

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

背景

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

e90f652155a5

image.png

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

谁用了我的空间

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

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

我的SD卡扫描程序

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

程序主题页面如下:

e90f652155a5

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卡。

e90f652155a5

image.png

后续还可以增强一下

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

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

谢谢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值