If you are interested in how to load image from gallery to your activity, you almost certainly know, that you have to use Intent.ACTION_PICK and startActivityForResult. You probably know, that the result intent, which you will obtain by onActivityResult contains Uri of the selected image and you can get the Uri by the getData method. Maybe you have learned, that Uri got by the getData is not Uri of actual file, but only a kind of "database key".
Commonly used (wrong) approach uses ContentResolver query, which is supposed to return cursor, that holds the image file path in the MediaStore.Images.Media.DATA column.
This method will work well for local files. For files stored remotely, i.e. in Picasa gallery this method will work only on some (older) versions of Android. I have learned, that my Android 2.3 on my LG P350 downloads remote images which I select in gallery to Downloads folder, so they become local. But Android 3.2 on my PackardBell tablet does not do any download automatically and therefore above mentioned approach fails and I get Null pointer error when I try to work with remotely stored images.
Following code shows another approach, which seems to work with both local and remote images well. It uses ContentProviderClient and ParcelFileDescriptor. It loads Image to temp file and works with this local copy. Note, thet _path[0] holds Uri got by getData method from the result Intent.
@Override protected Drawable doInBackground(Uri... _path) { file = null; // This is the key line. Content provider client gives us access to // file no matter if it is a local or a remote one ContentProviderClient client = getContentResolver() .acquireContentProviderClient(_path[0]); try { // Here we save copy of the file to temporary ParcelFileDescriptor descriptor = client.openFile(_path[0], "r"); AutoCloseInputStream is = new AutoCloseInputStream(descriptor); file = File.createTempFile("image", ".jpg", getDir(null, MODE_PRIVATE)); OutputStream outS = new FileOutputStream(file); byte[] buf = new byte[1024]; int len = 0; while ((len = is.read(buf)) > 0) { outS.write(buf, 0, len); } is.close(); outS.close();Complete code of test activity follows. To make it work, you have to create activity_galery_get.xml which will provide ImageView and Button.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/previewFrame" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/imagePreview" android:layout_width="match_parent" android:layout_height="match_parent" android:contentDescription="Image to share" > </ImageView> <Button android:id="@+id/bFromGallery" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left" android:onClick="handleFromGallery" android:text="Select image from gallery" /> </FrameLayout>
Here is the complete activity code:
public class GaleryGet extends Activity { private final String LOGTAG = getClass().getName(); private final int REQUEST_IMAGE = 33; private ProgressDialog progressDialog; private File file = null; private ImageView imagePreview; private Context mContext; /** * Usual onCreate - nothing special there */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mContext=this; setContentView(R.layout.activity_galery_get); imagePreview = (ImageView) findViewById(R.id.imagePreview); } /** * Button handler. Also very common one. Just create Intent and run it. */ public void handleFromGallery(View _view) { Intent i = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(i, REQUEST_IMAGE); } /** * Get result from gallery. Well we extract URI from intent and run * ImageDisplayer */ @Override public void onActivityResult(int requestCode, int resultCode, Intent _intent) { if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_IMAGE) { ImageDisplayer displayer = new ImageDisplayer(); if(_intent.getData()!=null){ displayer.execute(_intent.getData()); } } } /** * This is it. here we can see, how to process Uri from gallery result * in a proper way to get image displayed. * */ private class ImageDisplayer extends AsyncTask<Uri, Drawable,Drawable> { @Override protected void onPreExecute(){ progressDialog = ProgressDialog.show(mContext, "Loading", ""); } @Override protected Drawable doInBackground(Uri... _path) { file = null; // This is the key line. Content provider client gives us access to // file no matter if it is a local or a remote one ContentProviderClient client = getContentResolver() .acquireContentProviderClient(_path[0]); try { // Here we save copy of the file to temporary ParcelFileDescriptor descriptor = client.openFile(_path[0], "r"); AutoCloseInputStream is = new AutoCloseInputStream(descriptor); file = File.createTempFile("image", ".jpg", getDir(null, MODE_PRIVATE)); OutputStream outS = new FileOutputStream(file); byte[] buf = new byte[1024]; int len = 0; while ((len = is.read(buf)) > 0) { outS.write(buf, 0, len); } is.close(); outS.close(); } catch (RemoteException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (FileNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // And finally, we display the image String filePath = file.getAbsolutePath(); return Drawable.createFromPath(filePath); } @Override protected void onPostExecute(Drawable _drawable) { imagePreview.setImageDrawable(_drawable); progressDialog.dismiss(); } } }Hope this will work for you.
No comments:
Post a Comment