In my Android project, I have a 2M-bytes raw data file. Since my application is a long-life app, I don't want it to always seize 2M memory. The data file has been formatted, once I need to some data from the data file, I just need to seek to some position and read several bytes.
The Resource class can only return an InputStream on raw file, but InputStream cannot do random read.
Is there a way on Android to random read some bytes from the raw data file? Or I have to read the entire file into memory when I only need a few bytes.
InputStream can skip bytes with skip() can also mark an offset with mark(), on reset() it can go back to marked position. All that can be used to do random IO.
You can store byte offsets in a separate lookup file as well.
Android is built upon Java so take a look at this tutorial:
http://docs.oracle.com/javase/tutorial/essential/io/rafs.html
Related
EDIT: This question is about using AssetBundle, while that question (List of files in flutter) was about using Directory. They are different because of different classes. ALSO: I removed one section, that can be similar to previous question.
I don't understand how to use AssetBundle for accessing files...
For example, my assets in pubspec.yaml
assets:
- assets/images/
- assets/texts/
AssetBundle has methods: loadString(key, ...) and loadStructuredData(key, ...) - what is a key and how to use this methods?
I need to load data from text files and others files. I know that there is a rootBundle (or DefaultAssetBundle.of(context))... But how to use it to load files?!
Thanks!
Let's assume that you have an image clock.png in assets/images and a UTF-8 encoded text file distances.json in assets/texts.
The key is really just the path to the asset, so you might load the whole file as a String and decode the json like this:
String distancesText = await rootBundle.loadString('assets/texts/distances.json');
Map distances = json.decode(distancesText);
loadString takes care of the UTF-8 decode for you, and also caches the String for faster access next time.
loadStructuredData takes loadString one step further - it loads the String then calls your provided callback to parse the String and returns the result. This time it caches the decoded result - now saving the reading and decoding step the next time.
Map distances2 = await rootBundle
.loadStructuredData('assets/texts/distances.json', (String s) async {
return json.decode(s);
});
So, this is great for text files; what about binary files? You can read the whole asset as a byte array.
ByteData clockData = await rootBundle.load('assets/images/clock.png');
Uint8List clockBytes = clockData.buffer.asUint8List());
Now you can do whatever you need to do with the binary contents of the file. Note that unlike Strings, binary data isn't cached.
Of course, for a PNG, you would most likely not read it as bytes, but instead load it as an Image Widget with AssetImage. (Also asset images should have multiple resolutions for different DPI devices.) See Assets and Images.
I think that earlier you wanted to obtain a complete list of all the assets available. In some ways this makes no sense. You know which assets you provided at build time, so you could keep the list of assets somewhere yourself - in code or in your own manifest. If you really want to enumerate them at runtime, I think you can load an asset called AssetManifest.json, but this seems to be an implementation detail, so possibly subject to change.
In my app, I receive some files. At the beginning I just have the size of this file. So I create an empty file (filled of 0). After creating this file, I will receive 1024 bytes per seconds. Thoses bytes chunks correspond to file parts.
So I need to replace the current content of the file by the bytes I'm receiving.
This means I have to read/write the file every seconds. For small files, it's not a problem, but sometimes I'm having big files (>2Mo).
I searched but I couldn't find a way to replace a part of file at a given index without reading and reaching the while file everytime. Is there any simple solution and performance friendly?
After trying so much things with OuputStream, FileChannel, etc... and post this question. I finally found the "RandomAccessFile" class that solves my problem.
https://docs.oracle.com/javase/7/docs/api/java/io/RandomAccessFile.html
I am in no way a seasoned programmer. I have been successful at getting AudioRecord to write microphone data directly to file (as a readable .wav file) as it comes in from the mic, with the help of many code snippets from the internet.
However, for what I want to do with my app, I need to save only portions of what comes in from the mic, and I thought I would be able to do that by saving the byte data into some sort of an array first so I could selectively use what I want and save to file. Like many examples do, my class for reading microphone data reads the data into a byte array defined as:
byte data[] = new byte[audioBuffer];
and is read in with
read = audio.read(data, 0, audioBuffer);
My idea was to save each byte data array after it is read in to some sort of another array, and then read back each individual byte data array later to save to file when the user requests it. I tried an ArrayList to hold the data arrays:
private ArrayList<byte[]> grabArray = new ArrayList<byte[]>(grabArraySize);
but I am apparently only getting the last byte data array from the microphone for the whole .wav file. I am guessing I am misusing the ArrayList, but it's description sounded like the best chance of being able to do what I need. I have tried to find another way to do what I want including ByteBuffer, but that does not seem to provide the type of control that an array provides, where I can overwrite old data with new, and then at any point retrieve any or all of the data.
Basically, I know how to do this if it were simple primitives like integers or floats, but byte arrays are apparently throwing me for a loop. On top of that, there is a byte primitive, then there is the Byte class which can be wrapper... all a bunch of ??? to someone who doesn't make a living programming in Java. What is the best way to manhandle byte arrays (or just bytes for that matter) like you would do with just plain numbers?
Some more code to show how I save the audio data (in my AudioRecord thread) to a temporary holding array, then try to retrieve the data (in another class) so I can save to file: (My code is a big mess right now with comments and me trying various methods, commenting out things I'm not currently using... it would be too much to put it all here and I don't have the time to clean it up. I'm hoping this description of how I am trying to handle byte arrays will be enough to the help I need.)
Reading audio data and saving to my temporary holding array:
while(recordState){
read = audio.read(data, 0, audioBuffer);
if(AudioRecord.ERROR_INVALID_OPERATION != read){
if(i_read == grabArraySize){
i_read = 0; // reset index to 0 if hit end of array size
}
grabArray.set(i_read, data);
i_read += 1;
}
}
When asked to, reading audio data back from temporary holding array so I can save to file:
while(i < grabArraySize - 1){ // not writing the whole array - leaving out the last chunk
if(i_write == grabArraySize){
i_write = 0;
}
os.write(tempArray.get(i_write));
i += 1;
i_write += 1;
}
My FileOutputStream os works fine - I am successfully writing to file with the .wav header. I need to figure out how to store the data[ ] byte arrays from the AudioRecorder somewhere other than directly to a file, so that I can then retrieve them whenever I want, and then write them to file. I am successfully getting audio data, but the whole file is repeating one piece of that audio data (of size audiobuffer) over and over into whole file. The file is the correct length; everything else seems to be working; I can even recognize the sound I was making in the little bit that gets saves over and over...
Update again - It appears that ArrayLists are just pointers, as opposed to holding values like a normal array of values. I am now defining grabArray and tempArray both as byte[ ][ ]. Example - if I want to hold 10 separate byte arrays, with each byte array of size audioBuffer, I would define my array as such:
byte[][] grabArray = new byte[10][audioBuffer];
Now, in my AudioRecord thread, I am looping through my grabArray, setting each index = to the incoming audio byte array:
grabArray[i] = data;
Then, when I'm ready to write out to file, (after setting tempArray = grabArray ; I do this in case the AudioRecord thread writes a new audio chunk to the grabArray before I get to write to file) I loop through my tempArray:
os.write(tempArray[i]);
I am still getting only one instance of data[ ] (the audio chunks) repeated all throughout the file. Am I at least on the right track?
My app currently requests a JSON file with some text and other data from my server. I want to add functionality so that it also downloads a very small image (like an icon) through the same file [without creating an additional request]. Is it possible to do so, and how would I go about it (base64?)
Should be eminently reasonable: look at http://developer.android.com/reference/android/util/Base64.html. All you'd need to do is:
Read your icon into a byte[] array on the server.
(Assuming your server is in java) Use something like http://iharder.sourceforge.net/current/java/base64/ to write the byte[] array into a StringOutputStream through http://iharder.sourceforge.net/current/java/base64/api/index.html?Base64.OutputStream.html.
Add the contents of the String to the JSON file.
On the android device call http://developer.android.com/reference/android/util/Base64.html#decode%28java.lang.String,%20int%29 to convert the JSON attribute into a byte[] array.
You can then pass the byte array to http://developer.android.com/reference/android/graphics/BitmapFactory.html#decodeByteArray%28byte[],%20int,%20int,%20android.graphics.BitmapFactory.Options%29 or one of its brethren functions (you may have to play with image formats/encodings to get it to swallow your byte array correctly).
Voila! You have a Bitmap you can use.
Let me know how that works out.
I recently created a program that gets medi-large amounts of xml data and converts it into arrays of Strings, then displays the data.
The program works great, but it freezes when it is making the arrays (for around 16 seconds depending on the size).
Is there any way I can optimize my program (Alternatives to string arrays etc.)
3 optimizations that should help:
Threading
If the program freezes it most likely means that you're not using a separate thread to process the large XML file. This means that your app has to wait until this task finishes to respond again.
Instead, create a new thread to process the XML and notify the main thread via a Handler when it's done, or use AsyncTask. This is explained in more detail here.
Data storage
Additionally, a local SQLite database might be more appropriate to store large amounts of data, specially if you don't have to show it all at once. This can be achieved with cursors that are provided by the platform.
Configuration changes
Finally, make sure that your data doesn't have to be reconstructed when a configuration change occurs (such as an orientation change). A persistent SQLite database can help with that, and also these methods.
You can use SAX to process the stream of XML, rather than trying to parse the whole file and generating a DOM in memory.
If you find that you really are using too much memory, and you have a reason to keep the string in memory rather than caching them on disk, there are certainly ways you can reduce the memory requirements. It's a sad fact that Java strings use a lot of space. They require two objects (the string itself and an underlying char array) and use two bytes per char. If your data is mostly 7-bit ASCII, you may be better of leaving it as a UTF-8 encoded byte stream, using 1 byte per character in the typical case.
A very effective scheme is to maintain an array of 32k byte buffers, and append the UTF-8 representation of each new string onto the first empty space in one of those arrays. Your reference to the string becomes a simple integer: PTR = (buffer index * 32k) + (buffer offset). "PTR/32k" yields the index of the desired byte buffer, and "PTR % 32k" yields the location within the buffer. Use either an initial length byte or a null terminator to keep track of how long the string is. When you need to access one of the strings, don't allocate a new String object: unpack it into a mutable StringBuilder or work directly with the UTF-8 byte representation.
The above approach is obviously a lot more work, but can save you between a factor of 2 and 6 in memory usage (depending on the length of your strings). However, you should beware of premature optimization. If your problem is with the processing time to parse your input, or is somewhere else in your program, you could find that you've done a lot of work to fix something that isn't your bottleneck and thus get no improvement at all.