Loading all files from the content folder instead of one by one.

I’m having some difficulty doing that. When I deploy this code on Windows it works fine:

public static void LoadContent(ContentManager theContentManager)
{
   DirectoryInfo dir = new DirectoryInfo(theContentManager.RootDirectory + "/Music");               
   FileInfo[] files = dir.GetFiles("*.xnb"); 
   ...
}

However when I deploy it on an Android device, I get the exception

System.IO.DirectoryNotFoundException: Could not find a part of the path '/Content/Music'

when GetFiles is called.

Any ideas what I may be missing?

Thanks

System.IO.DirectoryNotFoundException: Could not find a part of the path

Is a system io error and means directly that the path isn’t there it doesn’t exist as given.

In this case theContentManager.RootDirectory just returns “Content”
So dir.GetFiles("*.xnb"); is searching for the files in…

Content/Music/somefile.xnb

not

C://users/whatever/ect/myapp/Content/Music/somefile.xnb

Grab the Enviroment.CurrentDirectory at the start of the app and stick it in front of that,
or use AppDomain.CurrentDomain.BaseDirectory

They are slightly different current directory can change or be changed like by a file dialog ect.
You can use Path.Combine(…) to concencate these paths and probably should also use Path.AltDirectorySeparatorChar ‘/’ or Path.DirectorySeparatorChar .

Thanks for your reply. I tried your suggestions but they didn’t work for me.
AppDomain.CurrentDomain.BaseDirectory returns null when you deploy for Android. It returns a valid path for Windows though.
Enviroment.CurrentDirectory returns ‘/’ for Android and the whole path for Windows.

So it seems these functions only work for Windows.

Just FYI, this is the whole code I had so far to load all the content automatically that works on Windows.
Thanks for your help.

        Song song;

        try
        {
            DirectoryInfo dir = new DirectoryInfo(theContentManager.RootDirectory + "/Music");               
            FileInfo[] files = dir.GetFiles("*.xnb"); 

            foreach (FileInfo file in files)
            {
                string key = Path.GetFileNameWithoutExtension(file.Name);

                song = theContentManager.Load<Song>("Music/" + key);
                mSongList.Add(song);
            }
        }
        catch (Exception)
        {
        }

This person was trying to do exactly the same thing, and apparently found the solution here:

However I still don’t know how I can call that function and what parameter I should pass.

Try TitleContainer.OpenStream on Android. I’ve never worked with it before, but try the same path you’re using now. The comments for the name parameter mention that it’s relative to the “title storage area,” which may be the Content folder on Android? Hopefully playing around with it a bit will get you to load your content.

1 Like

You may try this solution which works on my end, first off, if you open your apk it’s a zip file you can open it on 7zip you will notice the the 3 directory in there res,lib and assets. working in MG on android you get the the content file information from it’s context assets and there a lot of method out there.

This will give you the list of all files you want in your particular content directory e:g:

var m_ListOfMusicFiles = Android.App.Application.Context.Assets.List(“Content/Music”);

Problem solved here? right ? ok…

But I don’t think it’s a good idea to load everything on a content directory path, specially if you have multiple levels. what you can do is to have a text file which describe all you files you wanted to load for a center level and with your implementation you cannot show LOADING STATUS to the end users, load that text file using TitleContainer.OpenStream.

Discussion from How to load text file on Android?:

Also check this simple content loading with PROGRESS STATUS, you can enhanced it by using async and wait.

Discussion from [SOLVED] Texture loading during splash screen display:

Cheers ^_^y

2 Likes

DexterZ,

Thanks so much! That works fine. And you are right, you kept me thinking and I agree it’s not a good idea to load everything from the beginning, especially because I have multiple levels.

Just one more thing, if I want to unload a specific song that has been loaded using

song = theContentManager.Load<Song>("Music/" + key);

all I have to do is

song.Dispose()

Right?

Thanks!

1 Like

There isn’t currently a way to unload a single item from a ContentManager to my knowledge. If you load the song from it and dispose it, the next time you load that same song, it’ll be unsuitable for use since it was already disposed and ContentManager will return that same reference, as it caches the objects it loads until you call Unload. You can try using multiple ContentManagers if you need to unload specific assets at specific times.

1 Like

Thanks Kimimaru,

I was about to edit my last message to ask about that, because that’s the problem I was just facing!
Glad to see your answer.

Basically what I was just doing was to load the music for the level the player is playing, and disposing it after that.
If I don’t end up using multiple ContentManagers as you suggested, does it mean the memory will keep growing as the user moves through different levels? Maybe not a good idea?

Thanks

Glad it also works on your end ^_^y

In my engine I implemented 3 content manager content manager for the assets System Content manager assets that needs to stay the whole application life time, and Scene content manager that will be unload every level, and Self for big assets that needs to be dispose after usage. implment something like below:

   _ClickSnd    = _Device.AudioMngr.Load("Sounds\Click",      StorageType.System  );
   _LevelMusik  = _Device.AudioMngr.Load("Sounds\MBG_Level1", StorageType.Scene   );
   _Musik       = _Device.AudioMngr.Load("Sounds\Whatever",   StorageType.Self    ); 

   _Device.AudioMngr.Unload( StorageType.System );
   _Device.AudioMngr.Unload( StorageType.Scene   );
   
   _Musik.Dispose(); // self unloading

Internally I have only two content manager …

But for simplicity you can just use TWO content manager to store your assets

__SystemContentMngr << Store all assets that will stay the whole apps lifetime eg. fonts etcc.
__SceneContenrMngr << Store all assets that you will only need the specific level

At the end of every level just unload only __SceneContentMngr.Unload() and load again another contents to __SceneContentMngr for the next level assets.

Cheers ^_^y

2 Likes

Sounds good. I will do that. I like your solution.

Just a quick question that I wasn’t able to find the right way. In order to create a new ContentManager, the constructor requires a serviceprovider. Should I pass Content.ServiceProvider from the main Game class or do I have another alternative? It’s just I don’t like to use a global variable for that so maybe there’s a better way of doing it.

Try this bru ^_^Y

_SystemContentMngr = this.Content;
_SceneContentMngr  = new this.Content.ContentManager( this.Content.ServiceProvider, "Content" );
1 Like

Awesome! Thanks, DexterZ

And thanks to Kimimaru and everybody else helping on these forums. You guys are great!