I Have a multithreaded environment in android app. I use a singleton class to store data. This singleton class contains a arraylist that is accessed using a synchronized method.
The app uses this arraylist to render images in app.
Initial problem : Concurrent modification error use to come so I made the get arraylist function syncronized.
Current Problem:Concurrent modification error not coming but in between empty arraylist returned (maybe when there is concurrent access).
Objective : I want to detect when Concurrent modification so that Instead of empty arraylist being return I can return last state of the arraylist.
public synchronized List<FrameData> getCurrentDataToShow() {
List<FrameData> lisCurrDataToShow = new ArrayList<FrameData>();
//for (FrameData fd : listFrameData) {//concurrent modification exception
//todo iterator test
Iterator<FrameData> iterator = listFrameData.iterator();
while (iterator.hasNext()) {
FrameData fd = iterator.next();
long currentTimeInMillis = java.lang.System.currentTimeMillis();
if ((currentTimeInMillis > fd.getStartDate().getTime() && currentTimeInMillis < fd.getEndDate().getTime()) || (fd.isAllDay() && DateUtils.isToday(fd.getStartDate().getTime()))) {
if (new File(ImageFrameActivity.ROOT_FOLDER_FILES + fd.getFileName()).exists()) {
lisCurrDataToShow.add(fd);
}
}
}
if (lisCurrDataToShow.size() == 0) {
lisCurrDataToShow.add(new FrameData(defaultFileName, null, null, null, String.valueOf(120), false));
}
return lisCurrDataToShow;
}
Referred to Detecting concurrent modifications?
Please help!
EDIT1:
This problem occurs rarely not everytime.
- If a threads is accessing getCurrentDataToShow() and another thread tries to access this function what will the function return?? I'm new to multithreading , please guide
Edit 2
in oncreate following methods of singleton are called periodically
DataModelManager.getInstance().getCurrentDataToShow(); DataModelManager.getInstance().parseData(responseString);
Complete singleton class
public class DataModelManager {
private static DataModelManager dataModelManager;
private ImageFrameActivity imageFrameAct;
private String defaultFileName;
public List<FrameData> listFrameData = new ArrayList<FrameData>();
// public CopyOnWriteArrayList<FrameData> listFrameData= new CopyOnWriteArrayList<FrameData>();
private String screensaverName;
private boolean isToDownloadDeafultFiles;
private String tickerMsg = null;
private boolean showTicker = false;
private boolean showHotspot = false;
private String hotspotFileName=null;
public String getDefaultFileName() {
return defaultFileName;
}
public boolean isToDownloadDeafultFiles() {
return isToDownloadDeafultFiles;
}
public void setToDownloadDeafultFiles(boolean isToDownloadDeafultFiles) {
this.isToDownloadDeafultFiles = isToDownloadDeafultFiles;
}
private String fileNames;
private DataModelManager() {
}
public static DataModelManager getInstance() {
if (dataModelManager == null) {
synchronized (DataModelManager.class) {
if (dataModelManager == null) {
dataModelManager = new DataModelManager();
}
}
}
return dataModelManager;
}
private synchronized void addImageData(FrameData frameData) {
//Log.d("Frame Data","Start date "+frameData.getStartDate()+ " " +"end date "+frameData.getEndDate());
listFrameData.add(frameData);
}
public synchronized void parseData(String jsonStr) throws JSONException {
listFrameData.clear();
if (jsonStr == null) {
return;
}
List<String> listFileNames = new ArrayList<String>();
JSONArray jsonArr = new JSONArray(jsonStr);
int length = jsonArr.length();
for (int i = 0; i < length; i++) {
JSONObject jsonObj = jsonArr.getJSONObject(i);
dataModelManager.addImageData(new FrameData(jsonObj.optString("filename", ""), jsonObj.optString("start", ""), jsonObj.optString("end", ""), jsonObj.optString("filetype", ""), jsonObj.optString("playTime", ""), jsonObj.optBoolean("allDay", false)));
listFileNames.add(jsonObj.optString("filename", ""));
}
fileNames = listFileNames.toString();
}
public void setDefaultFileData(String jsonStr) throws JSONException {
JSONObject jsonObj = new JSONObject(jsonStr);
defaultFileName = jsonObj.optString("default_image", "");
screensaverName = jsonObj.optString("default_screensaver ", "");
}
@Override
public String toString() {
return fileNames.replace("[", "").replace("]", "") + "," + defaultFileName + "," + screensaverName;
}
public FrameData getFrameData(int index) {
return listFrameData.get(index);
}
public synchronized List<FrameData> getCurrentDataToShow() {
List<FrameData> lisCurrDataToShow = new ArrayList<FrameData>();
// for (FrameData fd : listFrameData) {//concurrent modification exception
//todo iterator test
Iterator<FrameData> iterator = listFrameData.iterator();
while (iterator.hasNext()) {
FrameData fd = iterator.next();
long currentTimeInMillis = java.lang.System.currentTimeMillis();
if ((currentTimeInMillis > fd.getStartDate().getTime() && currentTimeInMillis < fd.getEndDate().getTime()) || (fd.isAllDay() && DateUtils.isToday(fd.getStartDate().getTime()))) {
if (new File(ImageFrameActivity.ROOT_FOLDER_FILES + fd.getFileName()).exists()) {
lisCurrDataToShow.add(fd);
}
}
}
if (lisCurrDataToShow.size() == 0) {
lisCurrDataToShow.add(new FrameData(defaultFileName, null, null, null, String.valueOf(120), false));
}
return lisCurrDataToShow;
}
public String getCurrentFileNames() {
String currFileNames = "";
List<FrameData> currFrameData = getCurrentDataToShow();
for (FrameData data : currFrameData) {
currFileNames += "," + data.getFileName();
}
return currFileNames;
}
public ImageFrameActivity getImageFrameAct() {
return imageFrameAct;
}
public void setImageFrameAct(ImageFrameActivity imageFrameAct) {
this.imageFrameAct = imageFrameAct;
}
}