openFileOutput not working properly inside a singl

2020-03-31 06:54发布

As a novice Android developer, I've faced a bit strange problem. I want to create a class, which methods other classes-activities-whatever could use for working with files in some special way. Let`s say for simplicity we would be logging some stuff. If I do following within an activity (in OnClick listener for example), everything works just fine:

FileOutputStream fOut = openFileOutput("somefile", MODE_PRIVATE);
OutputStreamWriter osw = new OutputStreamWriter(fOut);
osw.write("Very important foobar");
osw.flush();
osw.close();

But when I try to enclose that into some class and create singleton like that:

public class Logger extends BaseActivity {
//BaseActivity is the "init" class which extends Activity

public static final Logger INSTANCE = new Logger();
private Logger() { 
// singleton
}

public boolean doLog (String whatToLog) {
 try {
     FileOutputStream fOut = openFileOutput("somefile", MODE_PRIVATE);
 OutputStreamWriter osw = new OutputStreamWriter(fOut);
 osw.write(whatToLog);
 osw.flush();
 osw.close(); }
     catch (IOException ioe) { ioe.printStackTrace(); }  
     return true; }

and call it from other activity like that

Logger.INSTANCE.doLog("foobar");  

app chrashes with NullPointerException (at line with openFileOutput). I suppose it`s because of improper use of singleton/activity here and now rewriting the code to run as a service. But maybe there are some better ideas to solve an issue? Or some workarounds?

Thanks for your contributions in advance!

标签: java android
5条回答
家丑人穷心不美
2楼-- · 2020-03-31 07:38

You based your singleton on an Activity that you didn't start as an Activity. Therefore, it doesn't have a valid Context, which is necessary for the IO calls. See Blundell's answer for better singleton, with one change: As per android.app.Application javadoc, your singleton should get the application context from the given context via Context.getApplicationContext(). See why does AndroidTestCase.getContext().getApplicationContext() return null for another example.

查看更多
闹够了就滚
3楼-- · 2020-03-31 07:42

You're using your class properly I don't think that it is doing what you intend. Your call to openFileOutput is failing because your singleton doesn't have a context. It will not have gone through the initialization life cycle phases and no context will have been established.

I would recommend that you create a service to allow for log writing and bind to that service in a "static" context on the objects you want to log with making sure that log requests are atomic.

查看更多
够拽才男人
4楼-- · 2020-03-31 07:42

You should call doLog in OnCreate method, not in constructor of your Activity. Before that, it doesn't have a context as @Dave G said.

Regards, stéphane

查看更多
啃猪蹄的小仙女
5楼-- · 2020-03-31 07:54

You should write a singleton class like this:

 import android.content.Context;
 import android.util.Log;

 public final class SomeSingleton implements Cloneable {

private static final String TAG = "SomeSingleton";
private static SomeSingleton someSingleton ;
private static Context mContext;    

/**
 * I'm private because I'm a singleton, call getInstance()
 * @param context
 */
private SomeSingleton(){
      // Empty
}

public static synchronized SomeSingleton getInstance(Context context){
    if(someSingleton == null){
        someSingleton = new SomeSingleton();
    }
    mContext = context.getApplicationContext();
    return someSingleton;
}

public void playSomething(){
    // Do whatever
            mContext.openFileOutput("somefile", MODE_PRIVATE); // etc...
}

public Object clone() throws CloneNotSupportedException {
    throw new CloneNotSupportedException("I'm a singleton!");
}
 }

Then you call it like this (depending on where you call it from):

 SomeSingleton.getInstance(context).playSomething();
 SomeSingleton.getInstance(this).playSomething();
 SomeSingleton.getInstance(getApplicationContext()).playSomething();

Edit: Note that this singleton works because it is not based on Activity and it gets a valid Context from whoever instantiates it (like another properly started Activity). Your original singleton failed because it never got started as an Activity, so it didn't have a valid Context. -cdhabecker

查看更多
\"骚年 ilove
6楼-- · 2020-03-31 07:59

I am pretty sure your error doesn't come from the line you mention.

A null pointer exception happens in a statement of the form

A.B or A.B()

where A is null. And there is no such thing in your class at this line.

Please double check stack trace, send it and indicate line numbers.

Don't forget to save your files before all that.

Regards, Stéphane

查看更多
登录 后发表回答