概述
闲来无事,正好以前老碰到这个磁盘空间满的问题
背景
安卓手机用了一段时间之后经常就报磁盘空间不够了,当然可以用手机管家,或者缓存/应用清理工具释放空间,但是还是会有莫名其妙的空间不够;这是由安卓的属性导致的,即使把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卡列出大文件的全部内容,希望文章能够帮你解决android 输入法sd卡,如何android扫描SD卡列出大文件所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复