将文件转换为字节数组会减慢应用程序的速度
Converting file to byte array slowing down the app
我正在使用这个库:https://github.com/alxrm/audiowave-progressbar 来提供类似 Soundcloud 音乐播放器的音频波形效果。
我是这样实现的:
byte[] data = convert(songsList.get(currentSongIndex).get("songPath"));
final AudioWaveView waveView = (AudioWaveView) findViewById(R.id.wave);
waveView.setScaledData(data);
waveView.setRawData(data, new OnSamplingListener() {
@Override
public void onComplete() {
}
});
waveView.setOnProgressListener(new OnProgressListener() {
@Override
public void onStartTracking(float progress) {
}
@Override
public void onStopTracking(float progress) {
}
@Override
public void onProgressChanged(float progress, boolean byUser) {
}
});
这是使用所述文件路径将文件转换为字节数组的方法
public byte[] convert(String path) throws IOException {
FileInputStream fis = new FileInputStream(path);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
for (int readNum; (readNum = fis.read(b)) != -1;) {
bos.write(b, 0, readNum);
}
byte[] bytes = bos.toByteArray();
return bytes;
}
可能是因为没有异步获取数组导致的问题,但我不确定。
谁能帮我解决这个问题?
编辑:正如@commonsware 正确建议的那样,我这样做了:
class AudioWave extends AsyncTask<String,Integer,String>{
private Context mContext;
private View rootView;
public MusicPlayerActivity m;
final AudioWaveView waveView = (AudioWaveView) m.findViewById(R.id.wave);
public AudioWave(MusicPlayerActivity m1){
m = m1;
}
// Runs in UI before background thread is called
@Override
protected void onPreExecute() {
super.onPreExecute();
// Do something like display a progress bar
}
byte[] b2;
// This is run in a background thread
@Override
protected String doInBackground(String... params){
// get the string from params, which is an array
String path = params[0];
try {
FileInputStream fis = new FileInputStream(path);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
try {
for (int readNum; (readNum = fis.read(b)) != -1; ) {
bos.write(b, 0, readNum);
}
}catch(IOException e){
}
byte[] bytes = bos.toByteArray();
b2=bytes;
new MusicPlayerActivity().setData(b2);
}
catch (FileNotFoundException e){
}
return "lol";
}
// This is called from background thread but runs in UI
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// Do things like update the progress bar
}
// This runs in UI when background thread finishes
@Override
protected void onPostExecute(String result) {
waveView.setScaledData(b2);
waveView.setRawData(b2, new OnSamplingListener() {
@Override
public void onComplete() {
}
});
waveView.setOnProgressListener(new OnProgressListener() {
@Override
public void onStartTracking(float progress) {
}
@Override
public void onStopTracking(float progress) {
}
@Override
public void onProgressChanged(float progress, boolean byUser) {
}
});
super.onPostExecute(result);
// Do things like hide the progress bar or change a TextView
}
}
按照您的方式加载本地文件是完全低效的:
您正在使用一个非常小的 1024 字节缓冲区。缓冲区越大速度越快,尤其是考虑到智能手机使用的闪存在内部使用更大的内存块。
您正在使用 ByteArrayOutputStream
。这是一个动态增长的字节数组。每次它增长到超过当前缓冲区的大小时,所有内容都会从旧缓冲区复制到新缓冲区。由于它是一个本地文件,您知道文件大小,因此您可以使用完整大小初始化缓冲区。
但是你不再需要 ByteArrayOutputStream 了。
因此您可以使用一个读取命令简单地加载文件:
File f = new File(path);
int size = (int) g.length();
byte[] fileData = new byte[size];
try (DataInputStream in = new DatInpuStream(FileInputStream(f)))) {
in.readFully(fileData);
}
无论如何,当您将其完全加载到内存中时,这仅适用于 "small" 个文件。如果您的 AudioWaveView 支持它,您应该使用流式处理方法:将 FileInputStream 与 BufferedInputStream 包装在一起,并将其缓冲区大小设置为 512KB 左右。
在主应用程序线程上执行 I/O 会在 I/O 期间冻结您的 UI,这意味着您的 UI 将没有响应。将 I/O 移动到后台线程对于 well-behaved UI.
是必要的
Android 坚持认为我们只能从主应用程序线程安全地更新 UI,这意味着您需要使用 AsyncTask
、Thread
和runOnUiThread()
、RxJava/RxAndroid 或其他安排后台工作并在后台工作完成后更新 UI 的方法。
对于您的情况,在后台线程上执行 convert()
逻辑,并在主应用程序线程上更新 waveView
应该会有所帮助。
请使用此功能提高性能---
private static byte[] readBytesFromFile(String filePath) {
FileInputStream fileInputStream = null;
byte[] bytesArray = null;
try {
File file = new File(filePath);
bytesArray = new byte[(int) file.length()];
//read file into bytes[]
fileInputStream = new FileInputStream(file);
fileInputStream.read(bytesArray);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return bytesArray;
}
我正在使用这个库:https://github.com/alxrm/audiowave-progressbar 来提供类似 Soundcloud 音乐播放器的音频波形效果。
我是这样实现的:
byte[] data = convert(songsList.get(currentSongIndex).get("songPath"));
final AudioWaveView waveView = (AudioWaveView) findViewById(R.id.wave);
waveView.setScaledData(data);
waveView.setRawData(data, new OnSamplingListener() {
@Override
public void onComplete() {
}
});
waveView.setOnProgressListener(new OnProgressListener() {
@Override
public void onStartTracking(float progress) {
}
@Override
public void onStopTracking(float progress) {
}
@Override
public void onProgressChanged(float progress, boolean byUser) {
}
});
这是使用所述文件路径将文件转换为字节数组的方法
public byte[] convert(String path) throws IOException {
FileInputStream fis = new FileInputStream(path);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
for (int readNum; (readNum = fis.read(b)) != -1;) {
bos.write(b, 0, readNum);
}
byte[] bytes = bos.toByteArray();
return bytes;
}
可能是因为没有异步获取数组导致的问题,但我不确定。
谁能帮我解决这个问题?
编辑:正如@commonsware 正确建议的那样,我这样做了:
class AudioWave extends AsyncTask<String,Integer,String>{
private Context mContext;
private View rootView;
public MusicPlayerActivity m;
final AudioWaveView waveView = (AudioWaveView) m.findViewById(R.id.wave);
public AudioWave(MusicPlayerActivity m1){
m = m1;
}
// Runs in UI before background thread is called
@Override
protected void onPreExecute() {
super.onPreExecute();
// Do something like display a progress bar
}
byte[] b2;
// This is run in a background thread
@Override
protected String doInBackground(String... params){
// get the string from params, which is an array
String path = params[0];
try {
FileInputStream fis = new FileInputStream(path);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
try {
for (int readNum; (readNum = fis.read(b)) != -1; ) {
bos.write(b, 0, readNum);
}
}catch(IOException e){
}
byte[] bytes = bos.toByteArray();
b2=bytes;
new MusicPlayerActivity().setData(b2);
}
catch (FileNotFoundException e){
}
return "lol";
}
// This is called from background thread but runs in UI
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// Do things like update the progress bar
}
// This runs in UI when background thread finishes
@Override
protected void onPostExecute(String result) {
waveView.setScaledData(b2);
waveView.setRawData(b2, new OnSamplingListener() {
@Override
public void onComplete() {
}
});
waveView.setOnProgressListener(new OnProgressListener() {
@Override
public void onStartTracking(float progress) {
}
@Override
public void onStopTracking(float progress) {
}
@Override
public void onProgressChanged(float progress, boolean byUser) {
}
});
super.onPostExecute(result);
// Do things like hide the progress bar or change a TextView
}
}
按照您的方式加载本地文件是完全低效的:
您正在使用一个非常小的 1024 字节缓冲区。缓冲区越大速度越快,尤其是考虑到智能手机使用的闪存在内部使用更大的内存块。
您正在使用
ByteArrayOutputStream
。这是一个动态增长的字节数组。每次它增长到超过当前缓冲区的大小时,所有内容都会从旧缓冲区复制到新缓冲区。由于它是一个本地文件,您知道文件大小,因此您可以使用完整大小初始化缓冲区。 但是你不再需要 ByteArrayOutputStream 了。
因此您可以使用一个读取命令简单地加载文件:
File f = new File(path);
int size = (int) g.length();
byte[] fileData = new byte[size];
try (DataInputStream in = new DatInpuStream(FileInputStream(f)))) {
in.readFully(fileData);
}
无论如何,当您将其完全加载到内存中时,这仅适用于 "small" 个文件。如果您的 AudioWaveView 支持它,您应该使用流式处理方法:将 FileInputStream 与 BufferedInputStream 包装在一起,并将其缓冲区大小设置为 512KB 左右。
在主应用程序线程上执行 I/O 会在 I/O 期间冻结您的 UI,这意味着您的 UI 将没有响应。将 I/O 移动到后台线程对于 well-behaved UI.
是必要的Android 坚持认为我们只能从主应用程序线程安全地更新 UI,这意味着您需要使用 AsyncTask
、Thread
和runOnUiThread()
、RxJava/RxAndroid 或其他安排后台工作并在后台工作完成后更新 UI 的方法。
对于您的情况,在后台线程上执行 convert()
逻辑,并在主应用程序线程上更新 waveView
应该会有所帮助。
请使用此功能提高性能---
private static byte[] readBytesFromFile(String filePath) {
FileInputStream fileInputStream = null;
byte[] bytesArray = null;
try {
File file = new File(filePath);
bytesArray = new byte[(int) file.length()];
//read file into bytes[]
fileInputStream = new FileInputStream(file);
fileInputStream.read(bytesArray);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return bytesArray;
}