Filling A ScrollView with many items takes TOO long - android

I am currently working on a simple mp3 player as an app on my android phone. I am going through all the files on my sd card and my internal storage to find everything with the extension: ".mp3".
Simple and works fine.
I then fill out a list with all the resulting song names and when clicked, they start playing. Working fine as well BUT
I now tried this on my personal phone with 700+ songs on it and the lists are done in less than a second but now the lists are to populate a ScrollView in a foreach loop with the results. And this takes for ever:
private void PopulateScrollView(List<string> content)
{
LinearLayout root = (LinearLayout)FindViewById(Resource.Id.scrollview);
mp3 = new List<MP3object>();
foreach (string obj in content)
{
WriteMetaDataToFileList(obj);
TextView txt = new TextView(this);
reader.SetDataSource(obj);
txt.Text = reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyTitle);
txt.TextSize = 20;
txt.Gravity = Android.Views.GravityFlags.Center;
root.AddView(txt);
txt.Click += delegate
{
PlayMusic(Android.Net.Uri.Parse(obj));
firstStart = false;
txt_CurrentSong.Text = CurrentActiveSongUri.ToString();
btn_StartOrPause.Text = Resources.GetString(Resource.String.Pause);
};
}
}
So, I am wonderin. What am I doing differently then my "normal" music player on my phone? I open it, and all the songs are already filled inside a ScrollView, almost NO waiting time. Appearently, going through the loop 700+ times to fill it up with the songs is way too much work, but it has to be done, right? Or am I seeing something wrong here? Some help would be AWESOME! :)
Thank you.
*** EDIT:
Also, I noted that every app that lists my files on my phone is quick as hell listing even 1000+ files in a scrollview. Clearly, my way is the incorrect way to fill a scrollview with static items from my phone. Any other ways of doing this? thank you :)

The problem you're hitting is that ScrollView is not made to be used with long lists of data. You're forcing Android to generate, lay out, and maintain a huge number of views. Instead you should look into the RecyclerView.
RecyclerView is made to handle long lists of data elements, like your use-case of mp3 files. It handles the large amount of data by only creating the elements needed to display items that are currently on the screen (plus a couple additional items to help with smooth scrolling). This greatly reduces the memory and cpu pressure on the system and allows for the responsiveness you see in other apps. Those other apps are most likely using RecyclerView or a similar pattern.
I recommend reading through Google's guide on the RecyclerView (linked above, but also here for convenience) to learn how to use it. I'd also recommend using RecyclerView's built-in list-item selection functionality to handle user taps instead of your TextView.click event. Both can work, but the selection functionality will likely be more convenient as RecyclerView handles the hard parts for you.

Related

How to add multiple images + text, save it as a single object so that it can be viewed by the user from a list?

Hello Stackoverflow!
I have an Android project I'm working on, and I've found myself stuck on one of the desired features.
The idea with this specific feature is that the user can load/take 2 images, write a description and then save it as a single object. This object will then be stored in a MySQL DB and will also be shown together with all the previously created objects in an expandable list or similare. The objects themselves dont haveto be clickable, just visible, and they don't haveto be editable after their creation.
-My question is this: How can i add multiple images + text, save it as a single object so that it can be viewed by the user from a list?
This might seem like a silly question for most of you, but I am (obviously) a beginner, and after spending days trying to look for a solution without knowing what I'm even looking for I've decided to ask here!
If anyone could point me in the right direction it would be much appreciated!
I hope this helps.
There are two solutions that come to my mind.
1st one - generating new image
If you are giving the user a list of all images to choose from you can easily take all those images he selected (If you are having trouble implement this, please ask) and move on to next activity or fragment where you will give the user option to enter a description.
In that layout you can have one LinearLayout (inside a ScrollView to enable more images than a screen height) and dynamically add ImageViews that will represent those images selected before.
At the bottom you have EditText for description (but that is less important now).
Once user decides to save this selection you can create new Bitmap from the LinearLayout having all images inside it.
Here is a code below
mLinearLayout.setDrawingCacheEnabled(true);
Bitmap mBitmap = Bitmap.createBitmap(mLinearLayout.getDrawingCache());
mLinearLayout.setDrawingCacheEnabled(false);
You can even put that into the bundle for further "transport"
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
mBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
byte[] bytes = byteArrayOutputStream.toByteArray();
Bundle bundle = new Bundle();
bundle.putByteArray(TAG, bytes);
If you have any questions or maybe need some more snippets feel free to ask.
2nd solution - creating a Map or an Array for your final object
You can have something like this
class MyObject{
List<String> selectedImages;
String description;
}
This list can be list of Bitmaps or maybe even list of Strings representing the urls of images user decided to choose. (I would go with urls)
I'm not sure how you present those images to the user so I might not be able to give you precise solution.
The second solution is more flexible and optimized. It gives you possibility to modify (even though you said it doesn't need to, but just in case) and it saves a hell of space on server (due to saving only strings not whole bitmaps that are mostly repeated in some cases).
Again, I hope this helps.

Smartway to implement media in Android

I am working on an Android app, where media(audio/video/images) could be stored either internally/externally. I would be facing the following scenarios
Case I
Setting dynamically images from the random value broadcasted by the app.
Right now, I am managing it as
if(rowData.strName.equals("football")){
imageView.setImageResource(R.drawable.football);
}else if(rowData.strName.equals("chess")){
imageView.setImageResource(R.drawable.chess);
Problem As of now, I am having few records so managing else if loop in not big headache, but later it could turn out to be one.
Case II
Downloading a media from internet, saving it in external storage and loading it on an imageview as an when required
Problem Incase, the image has already been downloaded(app keeps track of downloaded image), the user ejects the card, then I plan to use
try{
}catch(FileNotFoundException e){
imageView.setImageResource(R.drawable.no_media);//media from the app
}
Case III
I will be having a listView of a category.Each Category contains certain sub-category names,their images(inbuilt & to be downloaded externally) & their description.Each sub-category has sub records with each record having its own one or image(inbuilt & to be downloaded externally),description and media files(both audio and video).
I am confused on what Collection class shall I use for this case and how to begin with? For data that is to be retrieved from the server(online), I plan to use XMLParsing. Please suggest me the best way to achieve the problem.
Wow! This is really three questions. If only I could get three times the rep :)
Case I
Use a Map to store and retrieve stuff. Saves you writing lots of if/else statements.
Map<String,Integer> drawableMap = new HashMap<String,Integer>();
drawableMap.put("football", R.drawable.football);
// Then later to retrieve...
imageView.setImageResource(drawableMap.get("football"));
Case II
OK, this seems fine. Though for most of my image loading I use existing libraries like Universal Image Loader or Volley. These may do what you need, I'm not sure.
Case III
I would take an OO approach and model the data appropriately. You don't have to choose "a" Collection class to use. Create a Category class. Create a SubCategory class. Have the Category class "have" SubCategories, etc. Take it from there.
XML parsing is fine, I'm not sure what you're expecting to be suggested. You may also like to consider JSON, a popular data format.

Android txt files v's database

My music app is referencing persistently stored data. All are currently stored as text files:
Favorites - single text file array. App starts, reads the text file, stores in memory. Array is checked when ListView is expanded. If array changes text file is rewritten.
Last Played - single text file array list. Updated every 5 seconds. Retains the history of the played songs to allow the user to return to any album and resume position.
Playlists - currently individual text files, one for each list. List of playlists generated from file names when required. Each playlist text file has array list inside it. Read Write when required.
Most Played - single text file array list. Updated once per song played.
I am wondering whether this data would warrant the need to change to a database, or whether I have taken the right approach. I don't foresee the need for adding additional data so this should be the most I would need.
Advice please!
You can store the text files in SharedPreference and it should work well.
Database if preferable if a lot of data needs to be stored. Using a database is more optimal than parsing a string.
The correct approach is to create a class for each of the things you want to represent, e.g. favourites. Each class has a save() and reload() method. The point is that you can change the underlying storage mechanism in the save() and reload() methods without having to change the rest of your code. Imagine in the future, you want to enable saving to Dropbox. You would simply change these methods and your app would just work (OK, you'd need to add stuff to get Dropbox account details but you get the idea).
You could go further and define Interfaces for loading and saving. That interface can use a single class responsible for nothing except saving and loading. As long as any consumer and provider classes adhere to the interface, you can mix and match, and even implement storage approaches yet to be invented, without recoding your app. You only have one class to work with if, and whenever, you change your storage approach.
class StorageManager(){
enum DataType {Favourites, MostPlayed, PlayList };
...
public save(DataType dataType){
if (dataType == DataType.Favourites){
saveFavouritesToDB();
...
...
}
This approach gives you maximum flexibility, maximum future proofing and better maintainability.
I think it would be better to go with Database.
The database should provide you with some optimizations, performance improvements and basically you don't have to reinvent the wheel (doing read / write operations on the disk, use some buffers before rewriting, and the like).
Plus, I think you will love the way all code will be organized and split into its own layers once you start using this way.

How to perform Redo Undo operation in EditText

I want to know is there any method or any link or tutorial to perform redo undo operation in Android edittext. If any one knows than please let me know.
Quick note on the Antti-Brax/Divers(Kidinov) solution. It works great, except if you try to use it with a TextView post-API 23, you'll run into problems, because guess-what, Google actually added a hidden UndoManager (android.content.UndoManager) and didn't document it or make it obvious it was there. But if you have a hard/bluetooth keyboard in Marshmallow or Nougat and hit ^Z or SHIFT-^Z, you'll get undo/redo.
The problem comes if you're already using Antti-Brax's class with an EditText, and you also hook it to ^Z and shift-^Z, you'll run into problems with anyone using a hard keyboard. Namely the ^Z will trigger BOTH the native and Antti-Brax's undo, leading to two undos simultaneously, which isn't good. And after a few of them, you'll probably get a Spannable out of bounds crash.
A possible solution I found is to subclass the TextView/TextEdit/whatever and intercept the undo/redo calls from the TextView so they don't run as follows:
#Override
public boolean onTextContextMenuItem(int id) {
int ID_UNDO, ID_REDO;
try {
ID_UNDO = android.R.id.undo;
ID_REDO = android.R.id.redo;
} catch (Resources.NotFoundException e) {
ID_UNDO = 16908338; // 0x1020032
ID_REDO = 16908339; // 0x1020033
}
return !((id == ID_UNDO) || (id == ID_REDO)) && super.onTextContextMenuItem(id);
}
Those magic id numbers were found here, and are used only as a backup if the android.R.id.undo values aren't found. (it also might be reasonable to assume that if the values aren't there the feature isn't there, but anyway...)
This is not the best solution because both undo trackers are still there and both are running in the background. But at least you won't trigger both of them simultaneously with ^Z. It's the best I could think to do until this gets officially documented and the getUndoManager() methods of TextView is no longer hidden...
Why they made a feature you can't turn off (or even know if it was there or not) "live" in released Android I can't say.
I just opened an issue on Android's issue tracker if anyone wants to follow this.
There is an implementation of undo/redo for Android EditText in
http://credentiality-android-scripting.googlecode.com/hg/android/ScriptingLayerForAndroid/src/com/googlecode/android_scripting/activity/ScriptEditor.java
The code works but does not handle configuration changes properly. I am working on a fix and will post here when it is complete.
My Google search was :-
android edittext onTextChanged undo
I know this is an old question, but as there is no accepted answer, and this is an issue I've tackled myself from many angles, I'd like to add my solution in case it helps anyone. My answer is probably most relevant to large (1,000words+) volumes of text editing apps that require this feature.
The simplest way to resolve this problem is to make periodic copies of all text on screen, save it to an array and call setText() every time the Undo method is called. This makes for a reliable system, but it isn't ideal for large (i.e. 1,000words+) text editing apps. This is because it:
Is wasteful. It could be that only one word changes in a two thousand word document, so that's one thousand, nine hundred and ninety nine words needlessly committed to memory.
Can lead to performance issues, as some low-tier hardware struggles with rendering large amounts of text. On some of my test devices, this method can lead to freezes of a few seconds whenever Undo is called.
The solution I currently use is comparatively complex, but I've published the results in a library here.
Essentially, this library saves a copy of text as soon as a user begins typing, and then another copy of text once they've stopped typing for a set amount of time (in my case, two seconds). The two text strings are then compared, and the altered section of text returned, the indexes where the alterations occured, and details on whether or not the change was an addition of new text, a deletion, or a replacement of old text with new text.
The net result is that only the necessary text is saved, and when Undo is called, there is only a local delete(), replace() or insert() call, which makes for much faster operations on large text fields.
Here is the undo/redo implementation that was linked to from Gary Phillips' answer extracted into a reusable and universal undo/redo plugin for any widget that descends from a TextView. I added some code for persisting the undo history.
http://code.google.com/p/android/issues/detail?id=6458#c123
Hope this helps.
To preserve EditText Styling with regards to undo:
You can create an ArrayList<EditText> or ArrayList<String> (String containing html text) to store your last 10 (for example) actions. So ArrayList [0] would contain html text from your first action and ArrayList [9] would contain html text from your very last action. Each time the user taps "undo" in your app, you would apply ArrayList [size()-1] to your EditText and then remove ArrayList [size()-1] from your Array.

Working with objects in android

I'm a flash developer with no previous Java experience, just starting to learn android development. I'm trying to make a simple kid's flash cards app, consisting of a load of images of animals, and a load of sounds that they make.
Currently I have the images in a gallery view, storing them in an array. I also have an array of the sounds. So each image and the corresponding sound are in the same position in the array, so it's easy to play the right sound for the right image.
Now I want to shuffle the cards so that they appear in a different order each time the app is started up. I managed to shuffle the arrays into a random order, but kept the images and sounds in the same positions in each array but I can feel this getting messy and I'm sure this isn't the best way to go about this problem.
If this were a flash movie, I'd use objects to link the images and sounds and stick the objects in an array. Can anyone help me with some code which would achieve the same thing for android? Bear in mind I'm a complete beginner with Java and have gotten this far with tutorials and basic concepts being the same as AS3.
I'd use objects to link the images and sounds and stick the objects in an array.
Me too. Just create a class to wrap animals and sounds:
class SomeNiceName{
private final Bitmap animal;
// I'm guessing the sound is in the resources
// folder, thus you only need an integer to reference it
private final int sound;
public Animal(Bitmap animal, int sound){
this.animal = animal;
this.sound = sound;
}
public Bitmap getAnimal(){
return animal;
}// missing getter for sound
}
In this case I'm using an immutable object which is convenient in this case. Then you can create an array of those animals, o better yet a list:
// array
SomeNiceName[] array = new SomeNiceName[blah];
array[0] = new SomeNiceName(someBitmap, theSound);
// or with lists:
List<SomeNiceName> list = new ArrayList<SomeNiceName>();
list.add(new SomeNiceName(someBitmap, theSound));
The only thing you would have to "disorder" in this case is one array.
As Christian said you can of course use class in your Android application.
But, since mobile devices haven't huge processing capabilities like desktops or laptops -yet-, I advice you to read the articles below before running your OOP habits ;)
Object Creation
Getters/Setters? Not here!
For items above and more...

Categories

Resources