2

I have an Activity with an ImageView, which, if it is empty and clicked, should load an image from Internet and save it to internal storage. So the activity looks like this:

public class PlaceCreate extends Activity {
Context context;

@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.create);
  context = this;

  ImageView img = (ImageView) findViewById(R.id.imageView);
  img.setOnClickListener(new OnClickListener() {
    public void onClick(View v) {
        EditText edit = (EditText)findViewById(R.id.editTextName);
        Download(edit.getText().toString());
    }
  });
}

private boolean Download(String Name)
{
  try
  {
    URL u = new URL("http://example.com/img.png");
    HttpURLConnection c = (HttpURLConnection)u.openConnection();
    c.setRequestMethod("GET");
    c.setDoOutput(true);
    c.connect();
    FileOutputStream f = context.openFileOutput(Name, Context.MODE_PRIVATE);
    InputStream in = c.getInputStream();
    byte[] buffer = new byte[1024];
    int len1 = 0;
    while((len1 = in.read(buffer)) > 0 )
    {
      f.write(buffer, 0, len1);
    }
    f.close();

    FileInputStream is = openFileInput(Name);
    Bitmap bitmap = BitmapFactory.decodeStream(is);
    is.close();
    ImageView img = (ImageView) findViewById(R.id.imageViewPlan);
    img.setImageBitmap(bitmap);
  }
  catch(IOException e)
  {
    return false;
  }
  return true;
}}

The problem is that I get NullPointerException on the line with openFileOutput. I found a couple of similar questions, but all answers imply that null is a missing context. As it's an activity in this case, it obviously has a context (this), and it is not null. I tried to call openFileOutput (with this implied) and via the context member. Either approach fails. Also I tried to pass v.getContext() from onClick into Download as an additional parameter, and this value was not null, yet produced the same exception as well. (If it is important, the name of the file requested is a valid filename, for example "abc".)

Could someone shed some light on this?

Here is an example of the stack:

04-22 00:45:10.659: W/dalvikvm(330): threadid=1: thread exiting with uncaught exception (group=0x40015560)
04-22 00:45:10.909: E/AndroidRuntime(330): FATAL EXCEPTION: main
04-22 00:45:10.909: E/AndroidRuntime(330): java.lang.NullPointerException
04-22 00:45:10.909: E/AndroidRuntime(330):  at android.app.ContextImpl.openFileOutput(ContextImpl.java:420)
04-22 00:45:10.909: E/AndroidRuntime(330):  at android.content.ContextWrapper.openFileOutput(ContextWrapper.java:158)
04-22 00:45:10.909: E/AndroidRuntime(330):  at com.example.scanner.PlaceCreate.Download(PlaceCreate.java:93)
04-22 00:45:10.909: E/AndroidRuntime(330):  at com.example.scanner.PlaceCreate.access$0(PlaceCreate.java:84)
04-22 00:45:10.909: E/AndroidRuntime(330):  at com.example.scanner.PlaceCreate$3.onClick(PlaceCreate.java:67)
04-22 00:45:10.909: E/AndroidRuntime(330):  at android.view.View.performClick(View.java:2485)
04-22 00:45:10.909: E/AndroidRuntime(330):  at android.view.View$PerformClick.run(View.java:9080)
04-22 00:45:10.909: E/AndroidRuntime(330):  at android.os.Handler.handleCallback(Handler.java:587)
04-22 00:45:10.909: E/AndroidRuntime(330):  at android.os.Handler.dispatchMessage(Handler.java:92)
04-22 00:45:10.909: E/AndroidRuntime(330):  at android.os.Looper.loop(Looper.java:123)
04-22 00:45:10.909: E/AndroidRuntime(330):  at android.app.ActivityThread.main(ActivityThread.java:3683)
04-22 00:45:10.909: E/AndroidRuntime(330):  at java.lang.reflect.Method.invokeNative(Native Method)
04-22 00:45:10.909: E/AndroidRuntime(330):  at java.lang.reflect.Method.invoke(Method.java:507)
04-22 00:45:10.909: E/AndroidRuntime(330):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
04-22 00:45:10.909: E/AndroidRuntime(330):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
04-22 00:45:10.909: E/AndroidRuntime(330):  at dalvik.system.NativeStart.main(Native Method)

And here is some more findings. According to the stack, the error occures inside ContextImpl file, and I see that parent local variable is null inside this method. Here is the code:

public FileOutputStream openFileOutput(String name, int mode)
  throws FileNotFoundException {
  final boolean append = (mode&MODE_APPEND) != 0;
  File f = makeFilename(getFilesDir(), name);
  try {
     FileOutputStream fos = new FileOutputStream(f, append);
     setFilePermissionsFromMode(f.getPath(), mode, 0);
     return fos;
  } catch (FileNotFoundException e) {
 }

 File parent = f.getParentFile();
 parent.mkdir();
 FileUtils.setPermissions(
     parent.getPath(),
     FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
     -1, -1);
 FileOutputStream fos = new FileOutputStream(f, append);
 setFilePermissionsFromMode(f.getPath(), mode, 0);
 return fos;
}

So now the question is how can I make sure that the call to f.getParentFile() will not return null, and why does it work from time to time?

Stan
  • 8,683
  • 9
  • 58
  • 102

5 Answers5

2

The problem is that I get NullPointerException on the line with openFileOutput.

You are getting a NullPointerException inside the implementation of openFileOutput(). This is why you need to supply SO with a stack trace, rather than just supplying exception names. An exception on a line is different than an exception triggered by a line, particularly with NullPointerException.

Based on my reading of openFileOutput() on ContextImpl, either:

  • Name is null, or
  • you have an exceedingly strange context, or
  • there is some other possible problem on the version of Android you are running that is not visible in the current implementation of openFileOutput()

I would start by deleting context entirely, as you are inside an Activity and do not need it. Then, put in some Log statements or set breakpoints to see what Name is.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Did you see new version of the question with the stack and new findings? The line with `f.getParentFile()` in the `ContextImpl` produces `null`. – Stan Apr 21 '12 at 20:37
  • @Stan: When `f.getParentFile()` returns `null`, what does `f` contain? – CommonsWare Apr 21 '12 at 20:39
  • f File (id=830007877600) absolutePath "/a" (id=830007877752) path "a" (id=830007877784) parent null, meaning that I chose the name `a` for this time. – Stan Apr 21 '12 at 20:46
  • 1
    @Stan: What did you type into the `EditText` to generate this result? If the answer is `/a`, there's your problem -- `openFileInput()` and `openFileOutput()` only work with bare filenames, sans any paths. – CommonsWare Apr 21 '12 at 20:49
  • No, I typed `a`, of course. If I type `/a` (which I tried because I already just don't know what to do) I get another exception. – Stan Apr 21 '12 at 20:51
  • @Stan: That means `getFilesDir()` returned `null` when `f` was created, and I have no explanation for that. Try creating a separate sample project that reproduces the error. If you can, upload it somewhere and I'll take a peek at it. If you cannot create a separate sample that has the same effect, then figure out what is different between the new sample and your existing code. – CommonsWare Apr 21 '12 at 20:53
  • Ok, I'll do it (hope I'll manage to catch the exception in a simple project). Just in case, this happens under emulator with Android 2.3.3 platform. I'm trying on 4-th now. – Stan Apr 21 '12 at 20:57
1

This is proved to be a feature of Android 2.3.3 emulator installed here as a part of SDK. The problem does not occur if I use a real device with Android 2.3.3. Also the code works ok if I use Android 4.0.3 emulator. So, if some weird things happen, tests in another environment can shed some light. I hope this can help someone else in similar problem solving.

Stan
  • 8,683
  • 9
  • 58
  • 102
  • @d34th4ck3r, no, it's not clear which product is affected and/or which environment settings cause the problem. Also, I'd like to get some confirmation of the problem from other people at first. – Stan Aug 02 '12 at 21:04
  • You can count me in the confirmation. – d34th4ck3r Aug 03 '12 at 21:48
  • @d34th4ck3r, the problem is that it's about old SDK version, and seems not affecting newer version, so it should be treated as fixed, imho. – Stan Aug 04 '12 at 18:25
1

I had this same problem on my Asus TF101 running ICS - i.e. a real device rather than an emulator. It was vexing since it turned out that the problem was related to the Linux write permissions on the underlying folder.

I had been playing with using shared resources with the android:sharedUserId tag in my manifest file. Since the UID had changed, the activity no longer had write permission in the data files directory.

so anything that might change the uid will potentially cause this problem.

To solve the problem I:

  1. Removed the sharedUserID tag from the manifest (possibly optional);
  2. Manually uninstalled the app from my device.
  3. Re-installed the app.

It then ran perfectly.

CjS
  • 2,037
  • 2
  • 21
  • 29
1

By reading the code for openFileOutput() I can see one case where f.getParentFile() may return null that has not been mentioned in any other answer or comment here.

In the line

File f = makeFilename(getFilesDir(), name);

getFilesDir() can return null if the dataDir does not exist and if getFilesDir() fails to create the dataDir. If this happens the file f will only have a parent if the name is a path (such as "directory/file") and not just a file (such as "file").

I do not know under which circumstances the dataDir would be missing and when it would be impossible to create it, but it doesn't sound unlikely that it for some reason can't be created in the Android 2.3.3 Emulator.

nibarius
  • 4,007
  • 2
  • 38
  • 56
0

see this complete example

URL url = new URL (strURL);
input = url.openStream();
byte[] buffer = new byte[1500];
OutputStream output = new FileOutputStream ("/sdcard/abc.png");
int bytesRead = 0;
while ((bytesRead = input.read(buffer, 0, buffer.length)) >= 0) .
{
 output.write(buffer, 0, bytesRead);
 }
MAC
  • 15,799
  • 8
  • 54
  • 95
  • Unfortunately, I don't need external storage (such as sd card), I need internal storage. In examples for this case I saw, that single filename (without a path) is ok. – Stan Apr 21 '12 at 18:55