Reputation: 8768
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?
Upvotes: 2
Views: 5608
Reputation: 4117
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.
Upvotes: 1
Reputation: 2047
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:
sharedUserID
tag from the manifest (possibly optional); It then ran perfectly.
Upvotes: 1
Reputation: 8768
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.
Upvotes: 1
Reputation: 1007624
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
, orcontext
, oropenFileOutput()
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.
Upvotes: 2
Reputation: 15847
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);
}
Upvotes: 0