im trying to save an arraylist of drawable to a file.
Here is my class.
public class SeccionItem implements Serializable{
String name;
String text;
ArrayList<Drawable> img;
SeccionItem()
{
img = new ArrayList<Drawable>();
}
}
I have an arraylist of that class and i want to write it to a file using objectoutputstream, but i think that drawable cant be serialized, so can i use another type to store the images? like bitmap?. or is there any other way to store that arraylist? overwriting writeObject method?.
Im using this method to download the images
public static Drawable getBitmap(String image_url) {
try {
URL url = new URL(image_url);
InputStream is = (InputStream)url.getContent();
Drawable b= Drawable.createFromStream(is, " ");
if(b==null){
Log.d("this","null");
}
return b;
}catch(Exception ex) {
ex.printStackTrace();
return null;
}
}
neither Bitmap or Drawable are serializable. You could serialize the information to rebuild your Drawable. For instance you could serialize an ArrayList<Integer> where the Intever is the Drawable's id.
that drawables are downloaded from internet, i want to store it so
next time i dont have to download it again.
So you can store it on the sdcard, and nex time you can check if the file exists or not.
To write a file
public static void copy(InputStream is, File out) throws IOException {
byte[] buffer = new byte[BUFFER_LEN];
FileOutputStream fos = new FileOutputStream(out);
try {
int read = 0;
while ((read = is.read(buffer, 0, BUFFER_LEN)) >= 0) {
fos.write(buffer, 0, read);
}
fos.flush();
} finally {
close(fos);
}
fos = null;
buffer = null;
}
Related
I have images in my drawables folder. Activity opens them, I choose the needed images and click on button. They must be saved on my SD Card through ImageSavingTask class instance execution which extends AsyncTask.
Here is my onClick code:
#Override
public void onClick(View v) {
for (int i = 0; i < 26; i++)
if (checkBoxes[i].isChecked()) {
imageIndex = new ImageIndex(); //ImageIndex-a class with single index field which reserves the checked checkbox indexes.
imageIndex.index = i;
Bitmap bitmap = ((BitmapDrawable) (images[i].getDrawable())).getBitmap();
SaveImageTask saveImageTask = new SaveImageTask();
saveImageTask.execute(bitmap); //The class SaveImageTask extends AsyncTask<Bitmap, Void, Void>
}
}
Then the selected images are handled in doInBackground method.
#Override
protected Void doInBackground(Bitmap... params) {
FileOutputStream outStream = null;
try {
Bitmap bitmap = params[0];
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] imageBytes = stream.toByteArray();
File sdCard = Environment.getExternalStorageDirectory();
Drawable drawable = new BitmapDrawable(getResources(), bitmap);
File dir = new File(sdCard.getAbsolutePath());
dir.mkdirs();
String fileName = "Saved image " + imageIndex.index; //The reserved index of checkbox creates a name for the new file.
File outFile = new File(dir, fileName);
outStream = new FileOutputStream(outFile);
outStream.write(imageBytes);
outStream.flush();
outStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
The <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> line is added in my manifest.
After I connect the USB to my phone, no error happens, but no images are saved to my SD Card. And I can't find images on my phone using windows search. Debugging doesn't give any answer. What kind of problem this could be?
It seems you have not asked runtime permissions for writing file on SD Card. From Android M and above you need to ask write permission at runtime to save any file on external sd card.
Check this link on how to request runtime permissions- https://developer.android.com/training/permissions/requesting.html
Also you can use google library - https://github.com/googlesamples/easypermissions
to request permissions.
I add the selected indexes into 2 ArrayLists of indexes and bitmaps. In the doInBackground method I created a loop.
For appearing the images on the card immediately I used the MediaScannerConnection.scanFile method.
for (int i = 0; i < 26; i++)
if (checkBoxes[i].isChecked()) {
index.add(i);
bitmap.add(bitmaps[i]);
}
if (bitmap.size() > 0)
new SaveImageTask().execute();
The doInBackground method:
protected Void doInBackground(Void... params) {
for (int i = 0; i < bitmap.size(); i++) {
try {
fname = "Saved image " + (index.get(i)) + ".jpg";
file = new File(myDir, fname);
if (file.exists()) file.delete();
FileOutputStream out = new FileOutputStream(file);
bitmap.get(i).compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
MediaScannerConnection.
scanFile(getApplicationContext(), new String[]{file.getPath()}, new String[]{"image/jpeg"}, null);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
I left the ImageSavingTask without fields and parameters.
I think problem where you try to write bytes.
Use Following Solution..
#Override
protected Void doInBackground(Bitmap... params) {
Bitmap bitmap = params[0];
saveToInternalStorage(bitmap, "MyImage"); // pass bitmap and ImageName
return null;
}
//Method to save Image in InternalStorage
private void saveToInternalStorage(Bitmap bitmapImage, String imageName) {
File mypath = new File(Environment.getExternalStorageDirectory(), imageName + ".jpg");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mypath);
// Use the compress method on the BitMap object to write image to the OutputStream
bitmapImage.compress(Bitmap.CompressFormat.JPEG, 100, fos);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
NOTE : Make sure you have added storage read/write permission and don't forget to ask permission on Marshmallow and higher version.
Let me just start by saying I have a rather unusual source of images. I'm getting the bitmaps that need to be loaded from ID3 tags on an mp3 file.
Whenever I load the cover art and save it to the SD storage I get lagg. The odd thing is that all the loading and saving is happening on a background thread so it should not influence the UI thread. + I'm only running one operation at a time and it still laggs.
Once I have saved all the images to disk and I construct an array with all path names to the saved files it scrolls like butter and all images load without any delay. So the issue clearly is the caching to SD which is not happening on the UI thread. (I might be wrong about it though, so that is where you guys come in) The image loading from file is done using Universal Image Loader btw, but that is not causing any problems :)
Here is a snippet of my code that stores the cover art:
public ExecutorService executor = Executors.newFixedThreadPool(1);
//this is where I schedule tasks for all mp3 files to be executed using the threadpool,
//it is interrupted as soon as the user interacts with the listview (which should not be
//nessecary as it is not running any code on the UI thread)
public void preloadImages(){
for(int i = 0; i < items.length; i++){
if(scrolling){
return;
}
if(items[i].type.equalsIgnoreCase("music") && imagePathArray[i] == null){
ImageRunnable imgr = new ImageRunnable(items[i].pathname, null, i);
executor.execute(imgr);
}
if(scrolling){
return;
}
}
}
custom runnable
//the custom runnable used to call the getCover method on separate thread
private class ImageRunnable implements Runnable {
private String url;
private final WeakReference<ImageView> imageViewReference;
private boolean running = true;
private int position;
public ImageRunnable(String path, ImageView img, int pos) {
url = path;
imageViewReference = new WeakReference<ImageView>(img);
position = pos;
}
public void terminate() {
running = false;
}
#Override
public void run() {
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
final String coverPath = getCover(url, position);
}
}
The getcover method
private String getCover(String filepath, boolean refresh, int pos){
Log.d(LOG_TAG, "BEGIN function");
File file = new File(filepath);
Log.d(LOG_TAG, "File read");
MusicMetadataSet meta = null;
try {
meta = new MyID3().read(file);
Log.d(LOG_TAG, "id3 read");
} catch (IOException e) {
Log.d(LOG_TAG, "error reading id3 tag of file");
return null;
}
if(meta != null) {
try {
MusicMetadata metasimple = (MusicMetadata) meta.getSimplified();
Log.d(LOG_TAG, "simplified");
int length = filepath.length();
String albumname = filepath.substring(length-15, length-5).replaceAll("[^a-zA-Z0-9.-]", "_");
String path = Environment.getExternalStorageDirectory().toString();
OutputStream fOut = null;
Log.d(LOG_TAG, "album string");
File fileo = new File(path, "id3tag/"+albumname+"_icon.jpg");
Log.d(LOG_TAG, "file created");
File dir = new File(path, "id3tag/");
if(!dir.isDirectory()){
dir.mkdirs();
}
if(!fileo.exists() || refresh){
try {
fileo.createNewFile();
fOut = new FileOutputStream(fileo);
Vector<ImageData> fileList = metasimple.getPictureList();
Log.d(LOG_TAG, "got pic list");
ImageData data = fileList.lastElement();
if(fileList.size() == 0){
imagePathArray[pos] = "error";
return imagePathArray[pos];
}
byte[] rawimage = data.imageData;
Log.d(LOG_TAG, "got raw");
Bitmap bitmap = BitmapFactory.decodeByteArray(rawimage, 0, rawimage.length);
Log.d(LOG_TAG, "decoded bmp");
bitmap = bitmap.createScaledBitmap(bitmap, 64, 64, false);
Log.d(LOG_TAG, "scaled bmp");
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
Log.d(LOG_TAG, "compr bmp");
fOut.flush();
fOut.close();
bitmap.recycle();
Log.d(LOG_TAG, "recycled");
meta = null;
rawimage = null;
fileList = null;
options = null;
metasimple = null;
bitmap = null;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
imagePathArray[pos] = Uri.decode(fileo.toURI().toString().replace("file:/", "file:///"));
return imagePathArray[pos];
}catch (NoSuchElementException e){
return null;
}
}
return null;
}
I'm currently dealing with the same issue right now as well.
For me it appears to be multiple GC calls which pause all threads, including the UI thread in order to find resources to free up!
Check your LogCat messages to confirm, look for entries with the tag dalvikm
Try to minimize allocation of new bitmaps. First you can make one bitmap 64x64 and draw in it instead of using creatScaledBitmap.
Second you can reuse bitmap for decoding by passing it to decodeByteArray through BitmapFactory.Options
Ok I have found the issue, but no solution yet. Thanks everyone who helped so far! The bottleneck seems to be the read operation on the ID3 object. Why and how it is blocking the main thread I do not know but I'm going to try and minimize the usage of that object and see where it leads me :)
After doing this it only lags on the initial caching which happens only once for every file so no big deal.
I have to display thumbnails of contacts of my contacts in a listview which has a custom cursor adapter implementation. First I did it using asynctask and in the doInBackground method, I used the following snippet to get the bitmap of thumbnail.
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI,
Long.parseLong(params[0]));
InputStream input = ContactsContract.Contacts
.openContactPhotoInputStream(
mContext.getContentResolver(), uri);
if (input != null) {
mThumb = BitmapFactory.decodeStream(input);
} else {
mThumb = defaultPhoto;
}
It gives me correct bitmap.
Later, I came to know about Universal Image Loader. I implemented a custom BaseImageDownlaoder as in the following snippet. `public class ContactImageDownloader extends BaseImageDownloader{
private static final String SCHEME_CONTACT_IMAGE = "content";
private static final String DB_URI_PREFIX = SCHEME_CONTACT_IMAGE + "://";
private Context mContext;
public ContactImageDownloader(Context context) {
super(context);
mContext = context;
}
#Override
protected InputStream getStreamFromOtherSource(String imageUri, Object extra) throws IOException {
if (imageUri.startsWith(DB_URI_PREFIX)) {
InputStream input = ContactsContract.Contacts
.openContactPhotoInputStream(
mContext.getContentResolver(), Uri.parse(imageUri));
ByteArrayOutputStream output = new ByteArrayOutputStream();
if (input!=null) {
IoUtils.copyStream(input, output);
} else {
//default image
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.wiresimage);
bitmap.compress(CompressFormat.JPEG, BUFFER_SIZE, output);
}
byte[] imageData = output.toByteArray();
input.close();
return new ByteArrayInputStream(imageData);
} else {
return super.getStreamFromOtherSource(imageUri, extra);
}
}`
}
But it doesn't retrieve the image. In the log, it shows java.io.FileNotFoundException: File does not exist; URI: content://com.android.contacts/contacts/567, calling user: com.c
So, now in order to verify my implementation (to check if my custom BaseImageDownloader is wrong), I put the snippet I used in asynctask's doInBackground method to bindView method of cursor adapter. But still, the InputStream is null i.e. FileNotFoundException. But everything works right in Asynctask. Please help. Thanks!
public class TestButton extends Activity {
/** Called when the activity is first created. */
ImageButton imgBtn;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imgBtn = (ImageButton) findViewById(R.id.image);
//String url = "http://thenextweb.com/apps/files/2010/03/google_logo.jpg";
String url1 = "http://trueslant.com/michaelshermer/files/2010/03/evil-google.jpg";
Drawable drawable = LoadImage(url1);
imgBtn.setImageDrawable(drawable);
}
private Drawable LoadImage(String url) {
try {
InputStream is = (InputStream) new URL(url).getContent();
Drawable d = Drawable.createFromStream(is, "src");
return d;
} catch (Exception e) {
return null;
}
}
}
Above is the code snippet which I use to load image from web into ImageButton. Most of the images get displayed , but certain urls like the one above i.e. url1 , Drawable.createFromStream returns null !! What is the reason and how to avoid it or overcome this problem ?
I've stumbled upon same problem today. And found an answer, luckily :) There is a bug in SDK, described more or less on that google groups thread.
Workaround that worked for me is:
private static final int BUFFER_IO_SIZE = 8000;
private Bitmap loadImageFromUrl(final String url) {
try {
// Addresses bug in SDK :
// http://groups.google.com/group/android-developers/browse_thread/thread/4ed17d7e48899b26/
BufferedInputStream bis = new BufferedInputStream(new URL(url).openStream(), BUFFER_IO_SIZE);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(baos, BUFFER_IO_SIZE);
copy(bis, bos);
bos.flush();
return BitmapFactory.decodeByteArray(baos.toByteArray(), 0, baos.size());
} catch (IOException e) {
// handle it properly
}
}
private void copy(final InputStream bis, final OutputStream baos) throws IOException {
byte[] buf = new byte[256];
int l;
while ((l = bis.read(buf)) >= 0) baos.write(buf, 0, l);
}
And make sure not to set buffers size to more than 8k, because OS will use default size instead of the one you set (logging that of course, but it took me a while to notice that ;) ).
One more solution is using FlushedInputStream http://code.google.com/p/android/issues/detail?id=6066
in my android application,I want to save some photos uploaded from a server on my database and then reuse them later. I think I should save them in a binary format and save their links into the database. Is it the better solution? Can you give some code or an example? Thanks.
PS: now I only uploaded the image and display it directly using an ImageView but I want to make it available in my application when the user is offline.
for my experience the best way to do achieve this is savin my images from internet to the sdcard cause the file access is faster.
function to create my images directory in my sdcard...
public static File createDirectory(String directoryPath) throws IOException {
directoryPath = Environment.getExternalStorageDirectory().getAbsolutePath() + directoryPath;
File dir = new File(directoryPath);
if (dir.exists()) {
return dir;
}
if (dir.mkdirs()) {
return dir;
}
throw new IOException("Failed to create directory '" + directoryPath + "' for an unknown reason.");
}
example:: createDirectory("/jorgesys_images/");
I use this functions to save my images from internet to my own folder into the sdcard
private Bitmap ImageOperations(Context ctx, String url, String saveFilename) {
try {
String filepath=Environment.getExternalStorageDirectory().getAbsolutePath() + "/jorgesys_images/";
File cacheFile = new File(filepath + saveFilename);
cacheFile.deleteOnExit();
cacheFile.createNewFile();
FileOutputStream fos = new FileOutputStream(cacheFile);
InputStream is = (InputStream) this.fetch(url);
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap bitmap = BitmapFactory.decodeStream(is);
bitmap.compress(CompressFormat.JPEG,80, fos);
fos.flush();
fos.close();
return bitmap;
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public Object fetch(String address) throws MalformedURLException,IOException {
URL url = new URL(address);
Object content = url.getContent();
return content;
}
you will use this Bitmpap into your imageView, and when you are offline you will get the images directly from your sdcard.