JSONObject.toString() returns OutOfMemoryError - java

I have an Android app.
First, the app do sync process. In this process, the server sends to the device an JSON object as String by which it can build the available questionnaires.
GetQuestionnairesResponse.java:
public class GetQuestionnairesResponse extends ResponseHandler
{
public GetQuestionnairesResponse(String result, AsyncRequest request)
{
super(result, request);
}
#Override
public void handleResponse()
{
DataSyncActivity caller = (DataSyncActivity) request.getCaller();
BackgroundManager bckMng = BackgroundManager.getInstance(caller);
PreferencesManager preference = PreferencesManager.getInstance(null);
boolean status = true;
int numOfWrongJsonVer = 0;
int totalNumOfQuestionnaires = 0;
// Handle data from server
// Creating JSON Parser instance
try
{
QuestionnaireDataSource questionnaireDS = new QuestionnaireDataSource(caller);
questionnaireDS.open();
JSONArray jArr = new JSONArray(result);
JSONObject j = null;
totalNumOfQuestionnaires = jArr.length();
for (int i = 0; i < jArr.length(); i++)
{
j = jArr.getJSONObject(i);
long questId = j.getLong("questionnaireId");
long surveyId = j.getLong("surveyId");
String questName = j.getString("name");
String desc = j.getString("description");
int version = j.getInt("questionnaireVersion");
int jsonVersion = j.getInt("jsonVersion");
if (jsonVersion == PreferencesManager.jsonVersion)
{
// Save the pages part
String filename = questId + "_" + version + "_" + jsonVersion + ".json";
HelpFunctions.writeJSON(filename, j.toString());
Questionnaire quest = questionnaireDS.createQuestionnaire(questId, questName, desc, surveyId, version, jsonVersion, filename);
if (quest == null)
throw new RuntimeException("Cant save the questionnaire: " + questName);
}
else
{
numOfWrongJsonVer ++;
}
}
questionnaireDS.close();
}
catch (Exception e)
{
status = false;
if (e.getMessage() != null)
Log.e(TAG, e.getMessage());
}
caller.setInSync(false);
...
}
The result i get from the server i parse it to Json array.
The result in some cases can bee 3 megabytes.
The solution I found was to add an attribute in manifest.xml:
android:largeHeap="true"
It solved the problem. I don't know why but the problem returned again in the last day.
I will be happy to get suggestions how to solve the problem.
The problem is that the json object not parsed as expected so it

If the JSON was originally 3 MB and you call toString() on the JSONObject parsed from it, the JSONObject is still taking up memory, plus it's going to need to do a 3 MB allocation to hold the String. You may not have that much memory available.
But the thing about OutOfMemoryError is that the allocation that uses up the last bit of RAM isn't necessarily to blame for there being so little RAM available. Big allocations are just more likely to be the thing that pushes it over the edge. It's likely that you have a memory leak somewhere else in your app, and you'll need to use a tool like Eclipse MAT to find it.

Related

I have problems when submitting data from an RSS in my App

First of all I apologize for the translation, I speak Spanish.
My problem is the following:
I use the RSS of my own website to show data in my App, the bad thing is that they do not show up immediately, I need you to do it as it is necessary.
I think the problem may be in the XMLParser class:
public class XMLParser {
private URL url;
private Context contextor;
public XMLParser(String url) {
try {
this.url = new URL(url);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
#SuppressLint("SimpleDateFormat")
public void parse() {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
Document dom = builder.parse(this.url.openConnection().getInputStream());
Element root = dom.getDocumentElement();
NodeList itema = root.getElementsByTagName("item");
for (int i = 0; i < 1; i++) {
Node item = itema.item(i);
NodeList properties = item.getChildNodes();
for (int j = 0; j < properties.getLength(); j++) {
Node property = properties.item(j);
String name = property.getNodeName();
if (name.equalsIgnoreCase("content:encoded")) {
Log.i("XMLParser", "GUARDO " + property.getFirstChild().getNodeValue());
int star = (property.getFirstChild().getNodeValue().indexOf("<table class=\"tg0\">"));
int fiinal = (property.getFirstChild().getNodeValue().indexOf("</table>"));
String cadena = (property.getFirstChild().getNodeValue().substring(star, star+fiinal+8));
MyBus.setDomincal(cadena);
star = (property.getFirstChild().getNodeValue().indexOf("<table class=\"tg1\">"));
String parteCadena = (property.getFirstChild().getNodeValue().substring(star));
fiinal = parteCadena.indexOf("</table>");
cadena = (property.getFirstChild().getNodeValue().substring(star, star+fiinal+8));
Log.i("XMLParser", "GUARDO " + url);
Log.i("XMLParser", "GUARDO " + cadena);
//Log.i("XMLParser", "GUARDO " + MyBus.getIntermedio());
MyBus.setIntermedio(cadena);
star = (property.getFirstChild().getNodeValue().indexOf("<table class=\"tg2\">"));
parteCadena = (property.getFirstChild().getNodeValue().substring(star));
fiinal = parteCadena.indexOf("</table>");
cadena = (property.getFirstChild().getNodeValue().substring(star, star+fiinal+8));
MyBus.setZodiacal(cadena);
star = (property.getFirstChild().getNodeValue().indexOf("<table class=\"tg3\">"));
parteCadena = (property.getFirstChild().getNodeValue().substring(star));
fiinal = parteCadena.indexOf("</table>");
cadena = (property.getFirstChild().getNodeValue().substring(star, star+fiinal+8));
MyBus.setExtraordinario(cadena);
//MyBus.setSeguro(1);
}
}
}
} catch (Exception e) {
//MyBus.setSeguro(1);
//Esto solo es para lanzar un error y para que la app haga un cierre forsozo
//throw new RuntimeException(e);
}
}}
I do not know what I'm doing wrong, because when I check the link in the browser it is updated. Please, if someone can help me, I would really appreciate it.
An example would be: on the website I create a post or simply edit one, I change certain data that I have or there, let's say it said 'red' but now I edited it and put it 'blue'. In the link that I see of the RSS in the browser appears updated, but if I go to my app keeps saying red or does not appear the new post that I created until several hours later or the next day, and that is wrong because the information given my application must be updated every so often and it does not do me any good to do it many hours later.
At first I thought it could be the webview cache but the problem comes before it was shown in that webview.
Thanks in advance.

onPostExecute is called twice and showing double result

I am trying to download some files in background, for that I used download manager and I made this method:
/*** media download ***/
public long mediaDownload(ArrayList<DownloadedFile> arrayList, String foldPathName) {
long downloadReference = 0;
// Create request for android download manager
downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
for (int i = 0; i < arrayList.size();i++){
DownloadManager.Request request = new DownloadManager.Request(arrayList.get(i).getUri());
request.setTitle("Data Download");
request.setDescription("New media");
//Set the local destination for the downloaded file to a path
//within the application's external files directory
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS + "/" + folder_main + "/" + foldPathName, arrayList.get(i).getName());
File f = new File(Environment.DIRECTORY_DOWNLOADS + "/" + folder_main + "/" + foldPathName + "/" + arrayList.get(i).getName());
Log.e("File:",f.toString());
//Enqueue download and save into referenceId
downloadReference = downloadManager.enqueue(request);
}
return downloadReference;
}
I have a picture and a Video to download for test, and when checking downloaded file in Explorer I find 2 videos and 2 picture, debug that I found that onPostExecute method is called twice and I can't figure out why.
Here is my onPostExecute method:
protected void onPostExecute(String s) {
try {
JSONObject jsonObject = new JSONObject(s);
JSONArray region = null;
region = jsonObject.getJSONArray("regions");
Log.e("Regions:", String.valueOf(region.length()));
for (int i = 0; i < region.length(); i++) {
try {
JSONObject json_data = region.getJSONObject(i);
int height_view = Integer.parseInt(json_data.getString("height"));
int width_view = Integer.parseInt(json_data.getString("width"));
int left_view = Integer.parseInt(json_data.getString("left"));
int top_view = Integer.parseInt(json_data.getString("top"));
int right_view = Integer.parseInt(json_data.getString("right"));
int bottom_view = Integer.parseInt(json_data.getString("bottom"));
/**** Media in region ***/
JSONObject media = json_data.getJSONObject("media");
String type_media = media.getString("type");
url = media.getString("url");
name = media.getString("name");
uri = Uri.parse(url);
} catch (JSONException e) {
e.printStackTrace();
}
downloadedFiles.add(new DownloadedFile(name, uri));
}
Toast.makeText(MainActivity.this, "Layout Created with" + height + "x" + width, Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
Log.e("Downloaded Files:",downloadedFiles.toString());
mediaDownload(downloadedFiles, folderName); // region media's download
}
On my logcat I see that my arrayList has 2 elements, but displayed twice, which means files are downloaded twice so the onPostExecute method called 2 times, thanks for help.
I figured out after passing my time debugging all the code, when the activity is created it changes the screen orientation and so it creates a second instance, so my AsyncTask is called twice and thats why i thought onPosteExecute is called twice, thanks for everyone who tried to help.

Inserting multiple videos to a playlist using multithreading results in videos missing

When I insert the videos serially, all the videos get inserted to the playlist but it takes a long time. When I use multithreading more than half of the videos are missing in the end. How can I insert multiple videos quickly without losing any videos?
// Insert videos. 5 videos per asyncTask
List<List<YTVideo>> chunks = Lists.partition(videos, 5);
for (int i = 0; i < chunks.size(); i++) {
videoAndPlaylistContainer container = new videoAndPlaylistContainer();
container.playlistId = playlistId;
List<YTVideo> chunk = chunks.get(i);
container.videos = chunk;
InsertPlayListItemTask insertPlaylistItemsTask = new InsertPlayListItemTask();
runningTasks.add(insertPlaylistItemsTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,container));
}
.
private class InsertPlayListItemTask extends AsyncTask<videoAndPlaylistContainer, Void, Void>{
#Override
protected Void doInBackground(videoAndPlaylistContainer... params) {
videoAndPlaylistContainer container = params[0];
List<YTVideo> videosChunk = container.videos;
String playlistId = container.playlistId;
for (int i = 0; i < videosChunk.size(); i++) {
YTVideo video = videosChunk.get(i);
String videoId = video.getId();
long pos = video.getPosition();
try {
ResourceId resourceId = new ResourceId();
resourceId.setKind("youtube#video");
resourceId.setVideoId(videoId);
PlaylistItemSnippet playlistItemSnippet = new PlaylistItemSnippet();
// playlistItemSnippet.setTitle("First video in the test playlist");
playlistItemSnippet.setPlaylistId(playlistId);
playlistItemSnippet.setResourceId(resourceId);
playlistItemSnippet.setPosition(pos);
PlaylistItem playlistItem = new PlaylistItem();
playlistItem.setSnippet(playlistItemSnippet);
YouTube.PlaylistItems.Insert playlistItemsInsertCommand =
youtube.playlistItems().insert("snippet", playlistItem);
playlistItemsInsertCommand.execute();
System.out.println("Inserted video: " + video);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
edit: videos.size() to chunks.size(). Removed insertedCount++;
This line doesn't look right...
for (int i = 0; i < videos.size(); i++) {
The i variable will grow based on the size of the videos collection, but you only ever use the i variable to access an element within the chunks collection here...
List<YTVideo> chunk = chunks.get(i);
I can't imagine why you don't (eventually) get an ArrayIndexOutOfBounds exception, except maybe you're testing your code (so far) with fewer than 5 videos.

JnetPcap: reading from offline file very slow

I'm building a sort of custom version of wireshark with jnetpcap v1.4r1425. I just want to open offline pcap files and display them in my tableview, which works great except for the speed.
The files I open are around 100mb with 700k packages.
public ObservableList<Frame> readOfflineFiles1(int numFrames) {
ObservableList<Frame> frameData = FXCollections.observableArrayList();
if (numFrames == 0){
numFrames = Pcap.LOOP_INFINITE;
}
final StringBuilder errbuf = new StringBuilder();
final Pcap pcap = Pcap.openOffline(FileAddress, errbuf);
if (pcap == null) {
System.err.println(errbuf); // Error is stored in errbuf if any
return null;
}
JPacketHandler<StringBuilder> packetHandler = new JPacketHandler<StringBuilder>() {
public void nextPacket(JPacket packet, StringBuilder errbuf) {
if (packet.hasHeader(ip)){
sourceIpRaw = ip.source();
destinationIpRaw = ip.destination();
sourceIp = org.jnetpcap.packet.format.FormatUtils.ip(sourceIpRaw);
destinationIp = org.jnetpcap.packet.format.FormatUtils.ip(destinationIpRaw);
}
if (packet.hasHeader(tcp)){
protocol = tcp.getName();
length = tcp.size();
int payloadOffset = tcp.getOffset() + tcp.size();
int payloadLength = tcp.getPayloadLength();
buffer.peer(packet, payloadOffset, payloadLength); // No copies, by native reference
info = buffer.toHexdump();
} else if (packet.hasHeader(udp)){
protocol = udp.getName();
length = udp.size();
int payloadOffset = udp.getOffset() + udp.size();
int payloadLength = udp.getPayloadLength();
buffer.peer(packet, payloadOffset, payloadLength); // No copies, by native reference
info = buffer.toHexdump();
}
if (packet.hasHeader(payload)){
infoRaw = payload.getPayload();
length = payload.size();
}
frameData.add(new Frame(packet.getCaptureHeader().timestampInMillis(), sourceIp, destinationIp, protocol, length, info ));
//System.out.print(i+"\n");
//i=i+1;
}
};
pcap.loop(numFrames, packetHandler , errbuf);
pcap.close();
return frameData;
}
This code is very fast for the first maybe 400k packages, but after that it slows down a lot. It needs around 1 minute for the first 400k packages and around 10 minutes for the rest. What is the issue here?
It's not that the list is getting too timeconsuming to work with is it? the listmethod add is O(1), isnt it?
I asked about this on the official jnetpcap forums too but it's not very active.
edit:
turn out it slows down massively because of the heap usage. Is there a way to reduce this?
As the profiler showed you, you're running low on memory and it starts to slow down.
Either give more memory with -Xmx or don't load all the packets into memory at once.

How can I get a Javascript variable value in Java?

In my current project I have to read a JavaScript file from the web and extract an object from it. The variable can vary from time to time, so I have to read it instead of hard coding it into my android app.
Say I want to extract the following variable (and parse the string using JSONObject after that, which is trivial):
var abc.xyz = {
"a": {"one", "two", "three"},
"b": {"four", "five"}
}
I have a problem with this. Do I have to implement some compiler-like scanner just to look for the name and get its value, or there is some existing tool I can use?
The JavaScript file is not as simple as this example. It contains a lot of other code. So a simple new JSONObject() or something will not do.
There are many libraries in Java to parse the JSON. There is a list on JSON.org
Read the file with Java
import org.json.JSONObject;
URL url = new URL("http://example.com/foo.js");
InputStream urlInputStream = url.openStream();
JSONObject json = new JSONObject(urlInputStream.toString());
Finally code it myself.
//remove comments
private String removeComment(String html){
String commentA = "/*";
String commentB = "*/";
int indexA, indexB;
indexA = html.indexOf(commentA);
indexB = html.indexOf(commentB);
while(indexA != -1 && indexB != -1 ){
html = html.substring(0, indexA) + html.substring(indexB + commentB.length());
indexA = html.indexOf(commentA);
indexB = html.indexOf(commentB);
}
return html;
}
//find variable with name varName
private String findVar(String varName, String html, char lBrace, char rBrace){
String tmp = html.substring(html.indexOf(varName));
tmp = tmp.substring(tmp.indexOf(lBrace));
int braceCount = 0;
int index = 0;
while(true){
if(tmp.charAt(index) == lBrace){
braceCount ++;
}else if(tmp.charAt(index) == rBrace){
braceCount --;
}
index ++;
if(braceCount == 0){
break;
}
}
return tmp.substring(0, index);
}

Categories

Resources