我有一个向Queue添加值的Listener类,我有另一个包含Queue并将其写入文件的类。这两个类都在后台线程中运行。
侦听器类
private AccelerometerQueue mLogQueue; //Queue class implements Runnable
private Thread mQueueThread; //Thread to run Runnable of Queue class
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
synchronized (this) {
mLogQueue.addToQueue(
new AccelerometerVector(
System.currentTimeMillis(),
sensorEvent.timestamp,
sensorEvent.values[0],
sensorEvent.values[1],
sensorEvent.values[2]
)
);
mQueueThread = new Thread(mLogQueue);
mQueueThread.start();
}
}
队列类imlpements可运行并且具有此LinkedList
public void addToQueue(AccelerometerVector vector) {
mQueue.add(vector);
}
public synchronized int getQueueSize(){
return mQueue.size();
}
@Override
public void run() {
try {
mLogFile = createLogFile();
mLogOutStream = new FileOutputStream(mLogFile, true);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
while (!mQueue.isEmpty()) {
try {
mLogOutStream.write(mQueue.poll().getDataStringLine().getBytes());
} catch (IOException e) {
e.printStackTrace();
}
if (mLogFile.length() > AppConstants.LOG_FILE_MAX_SIZE) {
try {
reportCurrentLogFileIsFinished(mLogFile);
mLogOutStream.flush();
mLogOutStream.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
mLogOutStream = new FileOutputStream(createLogFile(), true);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
}
private File createLogFile() {
String datePart = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss").format(new Date());
String namePart = "log_" + datePart + ".csv";
File folder = new File(Environment.getExternalStorageDirectory().toString()
+ File.separator + AppConstants.APP_LOG_FOLDER_NAME);
folder.mkdirs();
File file = new File(folder + File.separator + namePart);
if (!file.exists()) { //create the file if not exist
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "Can not create file: " + file.getName());
}
}
if (file.exists()) {
return file;
} else {
return null;
}
}
我的目标是将队列内容保存到存储中,文件的大小不应超过256Kb,当文件达到256Kb时,应该创建一个新文件。
该代码目前所做的是写入一些大小为2或3 Kb的文件,然后在createLogFile()
方法中抛出异常,抱怨无法创建文件(我在Logcat中看到了这一点)。
问题是,我做错了什么,可能的解决方案是什么?
首先,我假设您正在使用一个同步的集合:
http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#synchronizedList(java.util.List)
尝试重新打开文件可能是问题所在。假设有一个线程正在写入该文件,我建议您打开该文件并保持其打开状态。
最后,你有什么例外?
好的,我解决了这个问题。
第一个问题是我在onSensorChanged
方法中启动了mQueueThread
。这导致新线程在从onSensorChanged
方法接收更新时启动,并导致内存泄漏或其他一些严重问题。所以我把它移到了构造函数。
其次,我将队列类型更改为ConcurrentLinkedQueue
,但我没有任何解释。。。可能是另一种类型会做得更好。
最后,我将Runnable
的实现更改为:
@Override
public void run() {
while (true) {
if (mLogOutStream != null && !mQueue.isEmpty()) {
try {
mLogOutStream.write(mQueue.poll().getDataStringLine().getBytes());
} catch (IOException e) {
e.printStackTrace();
}
if (mLogFile.length() > AppConstants.LOG_FILE_MAX_SIZE) {
synchronized (this) {
reportCurrentLogFileIsFinished(mLogFile);
try {
if (mLogOutStream != null) {
mLogOutStream.flush();
mLogOutStream.close();
mLogOutStream = null;
}
} catch (IOException e) {
e.printStackTrace();
}
try {
mLogFile = createLogFile();
mLogOutStream = new FileOutputStream(mLogFile, true);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
}
这些变化解决了问题。希望这也能帮助其他人。