How get a android asset without a activity - android

I have a non visual class that need to read some files from the assets folder.
Is totally out-of-band so don't have a activity. How I can refer to it without pass down the activity?
Also I can accept a alternative to the assets way to put files (like .sql) to be read later on the android devices.
P.D:
This is a sample of the code where is called:
//Load asset not belong to anyone. Is that radical
let loadAsset(path:string) =
#if __ANDROID__
let sr = new StreamReader(?????.Assets.Open(path.Substring(1)))
seq {
while not sr.EndOfStream do
yield sr.ReadLine ()
}
#else
File.ReadLines(path)
#endif

What you really need is a Context. If you application has an Application class, you can use its Context to retrieve asset resources.
It should look something like this:
public class App extends Application {
public static Context context;
#Override public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
}
You can then used App.context to get resources/assets.

How to get an android asset without an Activity
Try using the following code:
let sr = new StreamReader(Android.App.Application.Context.Assets.Open(path.Substring(1)))

Related

Android: Change language android N, application instance not updated

I follow Android N change language programmatically to changed language of my app in android N and above. However, I still have the problem with the application context instance.
In my Application class:
private static Application mInstance;
public static Context getApplication() {
return mInstance;
}
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
The language is changed, but Resources get from the Application context is not changed. For example:
MyApplication.getApplication().getResources().getString(stringId);
With return the wrong language string.
Can I update the application instance in this situation? I stuck to this problem for several hours. Because the MyApplication.getApplication() have used in many places throughout my app. So I can't convert to the Activity context.
Many thanks.
I have the same issue with one of my apps, because I do love my managers and utilities that doesn't require the context being passed every time.
My solution involves two separate contexts, one application context and one locale context. This doesn't solve all issues like inflating with correct locale using the correct style, for this you need to use the activity context. However, if you need to get the correct string or image from the resources based on the current locale, then this solution will work.
public class MainApplication extends Application {
private static Context applicationContext;
private static Context localeContext;
public static Context getAppContext() {
return applicationContext;
}
public static Context getLocaleContext() {
return localeContext;
}
#Override
public void onCreate() {
super.onCreate();
setTheme(R.style.AppTheme);
applicationContext = getApplicationContext();
updateLocaleContext();
}
public static void updateLocaleContext() {
localeContext = LocaleHelper.wrapContext(applicationContext);
}
}
The LocaleHelper.wrapContext should use a similar solution as the accepted answer on Android N change language programmatically and all activites need to implements attachBaseContext. Every time the language changes MainApplication.updateLocaleContext needs to be called. Note: the localeContext do not retain the style set in the onCreate function
Now you can use the MainApplication.getLocaleContext() for resources that depend on correct locale, while using MainApplication.getAppContext() for, e.g., inflating views that do not depend on the locale. Note: you could also place the localeContext in LocaleHelper to reduce the coupling

MvvmCross FilePlugin save files to SD card

We use beautiful MvvmCross framework in our app and we also utilize the FilePlugin to work with filesystem in a cross-platform way.
By default the FilePlugin stores data in some default location, like /data/data/<appname> in Android.
But what if I want to store big files, like video or 3D models? In iOS you store everything in app folder, but in Android you'll likely want to store files on SD card.
What solution would you recommend for this usecase?
I mean, should I inherit the FilePlugin and override app root directory for Android somehow?
I hade the same problem, and solved it by creating my own implementation of IMvxFileStore. My implementation allows me to specify an absolute path.
internal class CustomMvxAndroidFileStore : MvxFileStore
{
private Context _context;
private Context Context
{
get
{
if (_context == null)
{
_context = Mvx.Resolve<IMvxAndroidGlobals>().ApplicationContext;
}
return _context;
}
}
protected override string FullPath(string path)
{
if (PathIsAbsolute(path)) return path;
return Path.Combine(Context.FilesDir.Path, path);
}
private bool PathIsAbsolute(string path)
{
return path.StartsWith("/");
}
}
And then inject it during Setup of the app:
Mvx.RegisterType<IMvxFileStore, CustomMvxAndroidFileStore>();
This worked fine for me.

Why can't I use getFilesDir(); in a static context?

I have looked everywhere for an answer and every time I see someone else use the method:
getFilesDir();
But when I try and use that method in any way, especially:
File myFile = new File (getFilesDir();, filename );
Eclipse just says, "Cannot make static reference to non-static method getFilesDir from tye ContextWrapper"
I am trying to use it to get the internal directory to write a file for my application.
Thanks!
That is because in the static method you have not got the object of the class and getFilesDir is not a static method that means it will only be accessible via the object of class Context.
So what you can do is store the reference to the object in a static variable of your class and then use that in your static method.
for example:
static YourContextClass obj;
static void method(){
File myFile = new File (obj.getFilesDir(), filename );
}
also you will have to store the reference to the object in your onCreateMethod()
obj = this;
The best way to achieve this is
static void method(YourContextClass obj){
File myFile = new File (obj.getFilesDir(), filename );
}
I'm gonna talk about what happened to me. I'm developing a log system files, so i created a new class and i wanted to was for all my application and having many instances of this class doing different logs. So i thougth to create protected or public objects of my class on the application class that is similar to a singleton class.
So i had something like that:
public class MyApp extends Application {
protected LogApp logApp = new LogApp(getFilesDir());
When i called it from my main class to get the list files for example:
public class LogApp {
public File dirFiles;
//file parameter can't be null, the app will crash
public LogApp(File file){
dirFiles = file;
}
public File[] getListFiles(){
return dirFiles.listFiles()
}
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
MyApp myApp = (MyApp)getApplicationContext();
File file[] = myApp.logApp.getListFiles();
}
This was getting me an nullPointException error.
The solution in this case was so easy that i felt stuoid and proud at the same time.
I couldn't call to getFilesDir in MyApp's declaration space because at that moment there isn'r a context to get that Dir. The order of execute in an Android App is: Application --> Activity. Like it's said in Manifest file.
Solution? Create my object in onCreate event of my MyApp Class, it looks like this:
public class MyApp extends Application {
protected LogApp logApp;
void onCreate(){
logApp = new LogApp(getFilesDir());
So now i can use it in my main class in the same way i did it because exist an instance of my MainActivity that extends in last instance from Context Class.
Maybe i'm wrong with may explanation and this is not what is really happening in meanings of terminology and how works android. If someone understand better than me why this works i invite you to clear up our doubts.
I hope this will help you.

Why is Context "becoming" null on Application class?

Problem using Application
I'm rewriting an app (first 'version' had little-to-nothing in terms of analysis and it ended up piling a bunch of problems I wanted to get rid of) and I'm bumping my head against a problem that never showed up in the first version.
Thing is: I have a Class for geographical data. It just supplies String arrays that I can tuck into spinners adapters. Since I used a values xml file, the class needs access to Context to get the proper resources.
Since I use this geographical data in several points of the app, I thought I could create a Class to extend Application and, in onCreate, instantiate the Geography Class, I thought it would be more efficient to load it just once and use it as many times as I wanted. This worked on my first version:
This is MyApplication class
private static Context context;
public void onCreate(){
super.onCreate();
MyApplication.context = getApplicationContext();
geografiaEspana = GeographyClass.getInstance(context);
}
public static GeographyClass getGeografiaEspana() {
if(ctx==null){
Log.w("TAPABOOK", "Tapabook.context nulo");
}
if (geografiaEspana==null){
Log.w("TAPABOOK", "Tapabook.geografiaEspana nula, instanciando");
geografiaEspana = GeographyClass.getInstance(ctx);
}
Log.i("TAPABOOK", "Tapabook.geografiaEspana instanciada");
return geografiaEspana;
}
And this is my GeographyClass
private static GeographyClass instance = null;
public static GeographySpain getInstance(Context context){
if(instance== null){
instance = new GeographySpain(context);
}
return instance;
}
public GeographySpain(Context context){
Resources res = context.getResources();
// load resources data
}
This worked, as I said, ok in my first version. However, in my new version I'm getting a NullPointerException on this line "Resources res = context.getResources();" I've checked and it turns out that the context I'm supplying it's null... And I don't get to understand why or what I'm doing wrong
Ok, I solved it (I'd swear I already commented on this, but since it's gone...).
Thing is, I'm not used to use Application classes and I had forgotten to declare MyApplication in the Manifest file. Noob mistake. As soon as I declared it, the app ran OK

SharedPreferences and Application class

I have many shared preference for my app (mostly relating to color customization) and I'm unsure what the best method is to store/use them at runtime.
Currently I am doing something like this (with more or less preferences depending on the view) in every activity/fragment:
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getActivity());
int buttonbg = settings.getInt("buttonmenu_bg", 0);
int buttontxt = settings.getInt("buttonmenu_txt", 0);
int headerclr = settings.getInt("header", 0);
And then using those to set the various colors in the display. This seems like a lot of overhead to have to call the PreferenceManager each time and go through all that.
So I started looking at creating an application class, reading the preferences in once and using static variables from the application class in the activities/fragment to set the display.
My question is, are there any drawbacks or gotchas to doing this that I should consider before I venture further down the Application class path?
If you are not using so many static variables so this may not affect your application.But the problem with static variable may arise when your app goes to background and the app running on front requires memory so it may clear your static data,so when you will go to your app you may find nothing (null) in place of static data.
The purpose of the Application class is to store global application state or data (in memory of course), so your approach is correct. I've used it multiple times and it works like a charm.
What I usually do is to create a Map member variable and provide methods for getting and putting values into it, looks like this:
package com.test;
...
...
public class MyApp extends Application{
private Map<String, Object> mData;
#Override
public void onCreate() {
super.onCreate();
mData = new HashMap<String, Object>();
}
public Object get(String key){
return mData.get(key);
}
public void put(String key,Object value){
mData.put(key, value);
}
}
Then from my activities, I just do ((MyApp) getApplication()).get("key") or ((MyApp) getApplication()).put("key",object). Also, don't forget to set the android:name attribute in your manifest file, under the application tag:
<application
...
...
android:name="com.test.MyApp">
</application>
Is there any particular reason why you are not setting the display colors in res/values/styles.xml?

Categories

Resources