I've read about one trillion answers to this question that don't involve using a vector of strings. I need a function that will read words from a text file one by one into a data structure that I can call later on. Or, I need a function that can read words from a text file one by one and store them in three separate lists in one data structure.
private Vector<String> getLetters(String chapter, int t) throws IOException {
InputStream is = getResources().openRawResource(com.example.android.myprojecte.R.raw.aa);
Vector<String> letters = null;
InputStreamReader isReaded = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(isReaded);
String line = null;
while ((line = reader.readLine()) != null) {
letters.add(line);
}
return letters;
}
Basically, I just need to read a text file into a vector string, but my emulator keeps crashing. It could be something with my fragments, but the error code is signifying it's an I/O problem? So is this wrong above please and thank you
edit: i am pretty sure that the error is a null pointer exception
edit2: i restarted eclipse and i have a ton of errors in other parts of my code... i think this part is fine.
answer: I created a new blank project, added is.close() and br.close() statements, and declared the variable inside a different function since i had no idea what i was doing. Not sure which of these worked but declaring right after main activity didn't work like the guy suggested below
You need to allocate letters. letters = new Vector<String>();
Related
Block Array or multidimensional array Variables. For some reason my app is throwing out of memory on my loading of my pub vars class. This started happening when I started using Block Arrays. It works on actual devices but not on the emulators. Any thoughts? Should I set my block arrays to actual needs?
Current Block Arrays:
public static String[][] Name = new String[1000][1000];
however I only use maybe 10 or so. Is the device allocating space for the potential of the 1000 and is that why it is errors out? If so, how can I use these as the need may grow and I do not want to put a small limit on it. Thanks in advance for any thoughts.
With
public static String[][] Name = new String[1000][1000];
you are allocating 1 million strings (1000x1000) which is quite a bunch. If the information on this page is correct each string at least takes 40 bytes, so that would be around 39 Mbytes in your case and this can easily be too much memory on the heap for 1 activity. I would start there to refactor if you are only using 10. There is probably a better solution than your approach but without any more details on your code it's hard to give them. But of the top of my head, why not use a Set<String> or List<String> ?
Edit: So it's seems to me that you just want a Collection that scales dynamically. For that array is not the best choice. There are many of datatypes for that but one simple example whould be an ArrayList which also uses a array as backing datatype but by default will be instanciated with a capacity of 10 and expands dynamically if you continue to add elements
List<String> stringList = new ArrayList<String>();
stringList.add("string1");
stringList.add("string2");
...
If you want each element to have its own list of strings just create an object for that:
public class CompoundString {
private String key;
private List<String> stringList;
...
}
and use it like this
List<CompoundString> compoundStringList = new ArrayList<CompoundString>();
compoundStringList.add(new CompoundString("string1", new ArrayList<String>());
or just use a map:
Map<String,List<String>> stringMap = new HashMap<String,List<String>>();
stringMap.put("string1", new ArrayList<String>());
This is pretty basic concept in most programming languages and I would start to read some docs about the various collections:
http://docs.oracle.com/javase/7/docs/api/java/util/List.html
http://docs.oracle.com/javase/7/docs/api/java/util/Set.html
http://docs.oracle.com/javase/7/docs/api/java/util/Map.html
http://www.mkyong.com/java/what-is-the-different-between-set-and-list/
I want to populate listview with catalog names which are inside other specific catalog that my application is creating in other activities.
Here's the doInBackground method:
#Override
protected ArrayList<String> doInBackground(Void... arg0) {
ArrayList<String> wynik = new ArrayList<String>();
File katalog = new File(Environment.getExternalStorageDirectory().getPath()+"/DBConnector/Projekty/");
File[] projekty = katalog.listFiles();
for (File projekt : projekty) {
if (projekt.isDirectory()) {
wynik.add(projekt.getName());
}
}
return wynik;
}
It's throwing NullPointerException. As far as I know, even if there were no folders there it just should leave the ArrayList empty and pass it on (I'm using if(result.isEmpty()) later in onPostExecute to give info to user about that or actually populate listview if it's not empty - very similar code worked in other place, where I populated listview with data from resultset). Still, there are multiple folders there. I'm afraid I made some stupid mistake, but I just can't see it. I would appreciate some help.
EDIT: The thing that helped was restarting eclipse. Should have thought about it first though I still have no idea how it could have happened.
Without the logcat it's quite difficult to say for sure.
Are you sure you can access external storage? (Manifest Permission)
Is File Katalog a valid? or just null?
Is File[] projekty returning an empty array?
Use breakpoints and check those points above.
I am creating an app that involves reading in data from a file. The file is relatively large (1.8 MB) and is being read from an async thread in onCreate. The very first time the app is started up, it loads just fine. However, if you click the back button and then load it again, it runs out of memory and crashes (throwing the OutOfMemory error).
How do I get it to use the lowest amount of memory possible and/or free that memory when it is done?
File Reading Code (executed in the doInBackground() method of the async class):
public ArrayList<String> createDataList() {
dataList = new ArrayList<String>();
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(getAssets().open(
"text.txt")));
String data;
while ((data = br.readLine()) != null) {
dataList.add(data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close(); // stop reading
} catch (IOException ex) {
ex.printStackTrace();
}
}
return dataList;
}
EDIT*
Async Class:
private class loadData extends AsyncTask<Void, Void, ArrayList<String>> {
#Override
protected ArrayList<String> doInBackground(Void... arg0) {
dataList = createDataList();
return dataList;
}
protected void onPostExecute(ArrayList<String> result) {
super.onPostExecute(result);
// display first element in ArrayList in TextView as a test
}
}
I have tried splitting up the file based on how I want to organize the data and store the data from each text file into a separate ArrayList but I had memory problems with that as well. I have also stored all of the data into one "master" ArrayList and then invoked a method on that "master" to add the data to the appropriate ArrayList (removing/clearing the data from the "master" as soon as it copied).
Any ideas on how to streamline and reduce memory impact?
EDIT**
Logcat:
That is from when you click the back button and then load the activity again. The following is just one of the messages produced (in verbose):
You can try adding android:largeHeap="true" in your manifest but it is not supported in Android API-8. To my understanding, you are reading and storing the data onto heap memory, which is usually quite limited and its size depends on the device your running your app on.
You might also want to investigate here: android - out of memory
First, make sure you don't have two copies of the data in memory. You can null out the reference to the old ArrayList before starting to create the new one, though you have to do that carefully -- calling ArrayList.clear() first would be more thorough.
Second, figure out how much memory that ArrayList is eating up by using a tool like hprof or Eclipse MAT. If it's using a ton of space, you may want to consider a more compact data representation.
So... from the code snippet, it looks like you're just reading a bunch of text strings in from a file, using a byte-to-char conversion. If the source material is plain UTF-8 (i.e. essentially ASCII), you've got a 2x expansion to UTF-16, plus allocation of the char[] object to hold it, plus the size of the String object that wraps that, plus the overhead of the entry in the ArrayList. Depending on how long an average string in the file is, this can be a significant multiple on your 1.8MB.
One way to avoid this would be to read the file into memory as byte[], scan it to figure out where each string starts, and just keep an array of integers with the start offset of each string. When you need string N, decode it from the byte[] into a String and return it. This reduces your overhead significantly. You could reduce it further by not loading the file and just reading individual strings out as needed (using a RandomAccessFile), but this may slow things down.
Seems to be you might have a bit of trouble with the immutability of Strings .
Why don't you try changing your code so you use StringBuilder for instance? Of course, you'll have to change more than one thing but it would be similar enough to your code and wouldn't fill your memory up as fast.
Ok my pattience is gone now...I tried for 30 minutes to make this simple thing work but I failed so bad.Maybe it is because I started directly with android,no java...I studied c++ before,and in c++ this was so easy to do...
I have a button in a xml file:
<Button android:text="Button"
android:layout_width="wrap_content"
android:id="#+id/button1"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="108dp">
</Button>
And in my java file I have a string like this:
String test = new String();
test = "google";
I 've already set up the onclick listener for the button so there is no problem.
My question is if:
Button buttonx = (Button)findViewById(R.id.button1);
How can I compare if onClick(onclick code is already made) buttonx's text = the string test that is "google".
I tried with getText,setText...but nothing...
OK. First things first: Strings are completely different in Java to C++. In fact, Objects are pretty different all-round.
String test = new String();
test = "google";
does not do what you think it does.
What this does is create a new empty String object and store a reference to it in test. The next line stores a reference to a constant String "google" in test and makes the empty String you constructed in the previous line eligible for garbage collection. This is completely different to C++, where the second line would actually call the = operator on the String class. You can kinda think of everything in Java being a pointer (but not really), so assignment in Java behaves like pointer assignment in C++ (but not really).
Back to your question.
Something like this might work:
String test = "google";
Button b = ...;
if (test.equals(b.getText()) {
// whatever
}
Remember that although Java and C++ share some syntax similarities they are really completely different languages. Java references kinda behave like pointers, but not really.
Really.
String test = new String();
test = "google";
Button buttonx = (Button)findViewById(R.id.button1);
if (test.equals(buttonx.getText())) {
// it's equal
}
if (button.getText().toString().equalsIgnoreCase(test))
Toast.makeText(this, "Button text equals!", Toast.LENGTH_SHORT).show();
else
Toast.makeText(this, "Button text is not the same.", Toast.LENGTH_SHORT).show();
I have a ListView in my app, and I've over-ridden the getView() method so I can change the row's ImageView src depending on the row's text.
The problem is, I've noticed the ListView scrolling is lagging, and when I check DDMS, it seems the Garbage Collector is being called everytime the ListView is being scrolled, thus slowing the scrolling.
I've also noticed the Garbage Collector being called in a different part of my app, when reading lines from a BufferedReader, which makes opening a 2,000 line file take ~47 seconds, where as a file exporer I have installed on my phone opens that same file in about 2 seconds.
So my question is, what could be causing the constant Garbage Collection every 200ms or so, and how do I prevent it? It's really slowing my app down and I fear it will put some users off if I don't solve it.
Thanks,
Alex.
ListView getView():
class IconicAdapter extends ArrayAdapter<String> {
IconicAdapter(){
super(FileBrowser.this, R.layout.filebrowser_listview_row, R.id.listtext, directoryEntries);
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
View row = super.getView(position, convertView, parent);
TextView text = (TextView) row.findViewById(R.id.listtext);
ImageView icon = (ImageView) row.findViewById(R.id.listicon);
entryFullFileName = directoryEntries.get(position).toString();
if(entryFullFileName.contains(".") && !entryFullFileName.matches("^\\.+$")){
String[] parts = entryFullFileName.split("\\.");
lastIndex = parts.length - 1;
fileType = parts[lastIndex];
}else{
fileType = "";
}
if(fileIsDir.get(position) == true){
icon.setImageResource(R.drawable.folderlightblue);
}else if(fileType.equals("html")){
icon.setImageResource(R.drawable.filehtml);
}else if(fileType.equals("css")){
icon.setImageResource(R.drawable.filecss);
}else if(fileType.equals("js")){
icon.setImageResource(R.drawable.filejs);
}else if(fileIsDir.get(position) == false){
icon.setImageResource(R.drawable.fileplain);
}
return(row);
}
}
Code To Open File
I removed the code the other day that logged how many seconds it took to open the file, but it took 47 seconds and definitely took too long, and again while the while loop is doing it's thing, there's constant calls to the Garbage Collector, which I'm guessing in the cause of the slow file reading - and yes, this function is called in a thread with progressDialog showing while the file is being read
private String getLocalFileContents(String fileUri){
try{
String contents = "";
BufferedReader in = new BufferedReader(new FileReader(fileUri));
String line;
while((line = in.readLine()) != null){
contents += line + "\n";
}
in.close();
return contents;
}catch(Exception e){
toast.setText("Failed to open sdcard file, try again.");
}
return null;
}
UPDATE:
The file reading problem is solved, turns out the String concatenation made the Garbage Collector get called after each loop, dramatically slowing the file reading down. As suggested by an answer I used StringBuilder instead and it now opens in a second - hooray!
2ND UPDATE:
I know what the cause of the constant GC calls when scrolling my ListView is, it's the ListView attribute android:cacheColorHint="#android:color/transparent" - but I don't know a work-around!
In general, garbage collection is happening because you're creating too many objects unnecessarily. It'd be easier to help with your code, but I'll give it a shot anyway.
In the case of your list, you're probably recreating your view in every call to getView. You should instead re-use convertView when appropriate. See my answer to this other SO question for an idea of how to structure your getView method.
Your file reading problem is a bit harder to guess at, but 47s seems ridiculously long for 2,000 lines. Are you also creating objects in that loop?
Update:
So apparently your problem isn't really with your View objects themselves, but it's all the work you do every time you get a View. You're doing quite a bit of work every time: a RegEx match, string splitting (and associated string object creation), etc. You should at minimum cache the results of this so that you don't have to redo the work for each item every time it comes back into view.
One optimization would be to stop splitting the entire string to get the filetype. You could use something like
String fileType = "";
int lastDot = entryFullFileName.lastIndexOf(".");
if(lastDot!=-1) {
fileType = entryFullFileName.substring()
}
That certainly shouldn't take 47s though.
Look at EfficientAdapter here is link
And explained more about efficient adapter and getView method in other thread have a look at it, here is link
Hope this help!!!
Yes, android:cacheColorHint="#android:color/transparent" is causing excessive calling of the garbage collector on some OS versions (not sure if the newest ones this is fixed).
Well, just try to not use it. For example, I spoke with my designers, explained them the problem about the cause of the lags, and they agreed to not use the transparent background.