Android - Getting, saving and retrieving images from URL - android

I have a database of recipes, each of which has an image.
The database can be updated from a JSON feed. I then need to retrieve any new images for a newly added recipe. I'm having issues getting an image from a URL, saving it and then updating a recipe with that image.
There are a lot of different answers on Stack Overflow and other sites. Often I can get to what I would expect to be a working point. Where images appear to be getting saved, and any debug print outs I add in show what I expect, but I cannot update my ImageView. By that I mean it remains blank.
I'm not sure if my issue is simply a poor attempt to update the ImageView, or a problem when saving the images. This code is a bit sloppy and inefficient at the moment. I've tried 10-15 variations on this from suggested other posts and have had no luck. Any help would be greatly appreciated.
Manifest
/* I have these two set (Not sure both are necessary) */
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Main frontend class
/* Create databaseHelper */
DatabaseHelper db = new DatabaseHelper(getApplicationContext());
/* ImageView to update image of */
ImageView foodpic = (ImageView)findViewById(R.id.foodpic);
/* Check if image is already available in drawable folder */
int resID = this.getResources().getIdentifier(filename, "drawable", "mypackage.name");
if (resID == 0) {
/* If not, call function to retrieve from external storage */
newPic = db.getOutputMediaFile(origFilename);
if(newPic.exists()) {
myBitmap = BitmapFactory.decodeFile(newPic.getAbsolutePath());
foodpic.setImageBitmap(myBitmap);
foodpic.invalidate(); /* Tried with and without this */
}
}
DatabaseHelper function to retrieve image saved from URL
public File getOutputMediaFile(String filename){
/* Dir I'm (attempting) to save and retrieve images from */
File mediaStorageDir = new File(Environment.getExternalStorageDirectory() + "/Android/data/mypackage.name/Files");
/* Create the storage directory if it does not exist */
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
return null;
}
}
/* Get file extension */
String[] fileNameSplit = filename.split("\\.");
String extension = fileNameSplit[(fileNameSplit.length-1)];
/* Get filename, remove special chars & make lowercase */
int extensionIndex = filename.lastIndexOf(".");
filename = filename.substring(0, extensionIndex);
filename = filename.toLowerCase(Locale.getDefault());
filename = filename.replaceAll("[^a-z0-9]", "");
/* Re-make filename to save image as */
String mImageName="r"+filename+"."+extension;
/* Get file
mediaFile = new File(mediaStorageDir.getPath() + File.separator + mImageName);
return mediaFile;
}
DatabaseHelper function to save image from URL
- Called per recipe/image added to the database, if image not found in drawable folder.
public static void saveImage(String imageUrl, String destinationFile, String extension) throws IOException {
URL url = new URL (imageUrl);
InputStream input = url.openStream();
try {
File storagePath = Environment.getExternalStorageDirectory();
OutputStream output = new FileOutputStream (new File(storagePath,destinationFile));
try {
byte[] buffer = new byte[2048];
int bytesRead = 0;
while ((bytesRead = input.read(buffer, 0, buffer.length)) >= 0) {
output.write(buffer, 0, bytesRead);
}
} finally {
output.close();
}
} finally {
input.close();
}
*Formatting.

Store URL as string in DB and display it with Image Loader is more easy, but doesn't work off line ,if ur apps need internet to work, the image loader could be better.
android-loading-image-from-url-http

I ended up using this library.
It's not an ideal solution as I'd have preferred to look through this library, understand it fully and explain it for others who may need a similar answer. But for now, people attempting to do something similar should be able to use this too.
https://code.google.com/p/imagemanager/

Related

How to get Path of image which is shared from whatsapp in android [duplicate]

I'm successfully implementing a method for retrieving the real path of an image from gallery by the Uri returned from ACTION_PICK intent. Here's a sample:
// getRealPathFromURI(intent.getData());
private String getRealPathFromURI(Uri contentURI) {
String result;
Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
if (cursor == null) { // Source is Dropbox or other similar local file path
result = contentURI.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
result = cursor.getString(idx);
cursor.close();
}
return result;
}
Just like this answer.
Recently updated the compileSdkVersion to 29 and apparently the DATA attribute everyone's using is deprecated.
In the official docs, they recommend to use FileDescriptor instead, problem is i don't know exactly how.
Only thing i found is this question. Didn't find a proper answer there though.
Please help me overcome that deprecation issue with a solution using the suggested way or any other way.
Thank you.
Update:
Followed #CommonsWare's answer and copied the returned Uri (of an image the user picked) to a local directory, using context.getContentResolver.openInputStream(Uri).
Even tried retrieving a file from Google Drive - and it worked. Only problem was the long time it took (about 20 sec for 5MB file).
As a bonus, i was cleared to remove external storage permissions, which one doesn't need for using app's local directories.
No more externals paths for me!
This question came up for me too a week ago.
My solution was to create an InputStream from the URI and then, from this, create an OutputStream by copying the contents of the input stream.
Note: You could call this method using an asynchronous call because copying extremely large files could have some delays and you won't want to block your UI
#Nullable
public static String createCopyAndReturnRealPath(
#NonNull Context context, #NonNull Uri uri) {
final ContentResolver contentResolver = context.getContentResolver();
if (contentResolver == null)
return null;
// Create file path inside app's data dir
String filePath = context.getApplicationInfo().dataDir + File.separator
+ System.currentTimeMillis();
File file = new File(filePath);
try {
InputStream inputStream = contentResolver.openInputStream(uri);
if (inputStream == null)
return null;
OutputStream outputStream = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len;
while ((len = inputStream.read(buf)) > 0)
outputStream.write(buf, 0, len);
outputStream.close();
inputStream.close();
} catch (IOException ignore) {
return null;
}
return file.getAbsolutePath();
}
I'm successfully implementing a method for retrieving the real path of an image from gallery by the Uri returned from ACTION_PICK intent.
That code may not work for all images. There is no requirement for DATA to point to a filesystem path that you can access.
Just like this answer.
FWIW, this was my answer to that question.
Only thing i found is this question. Didn't find a proper answer there though.
That technique wasn't particularly good and will no longer work, as Android has locked down /proc.
In the official docs, they recommend to use FileDescriptor instead, problem is i don't know exactly how.
The more general concept is that you use ContentResolver to work with the Uri, whether you get an InputStream (openInputStream()), OutputStream (openOutputStream()), or FileDescriptor. Consume the content using those things. If you have some API that absolutely needs a file, copy the content (e.g., from the InputStream) to a file that you control (e.g., in getCacheDir()).
As a bonus, now your code is also in position to use the Storage Access Framework (e.g., ACTION_OPEN_DOCUMENT) and the Internet (e.g., OkHttp), if and when that would be useful.

Xamarin Android Sqlite Db browser

I have my first smartphone since one week and try make a App with Xamarin.
I use SQLite with EntityFrameworkCore to store data.
It is work fine, but to debug easier I want use a SQLite browser.
The database file path is 'data/data/{AppName}/Database.db'.
I debug from a physic device by USB, but when I explore the device with Windows Explorer I cannot find the SQLite DB file. The 'data/data' folder is not available. Then I can not use a SQLite browser to see the data.
In this post, the author use a Android emulator and can see 'data/data' folder :
https://blog.xamarin.com/building-android-apps-with-entity-framework/
But I prefer use a real device.
Have you a solution?
A solution from the MikeT, in development store the db file in available folder like this :
public static string DatabasePath
{
get
{
var dbFolder = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath;
var fileName = "database.db";
var dbFullPath = Path.Combine(dbFolder, fileName);
return dbFullPath;
}
}
In production, copy the db file to a available folder.
One a real device you would, I believe, need to root the device to directly access the data.
However, what you could do is to copy the database file elsewhere e.g. to external storage. In following is the core process that I use:-
try {
FileInputStream fis = new FileInputStream(dbfile);
OutputStream backup = new FileOutputStream(backupfilename);
//byte[] buffer = new byte[32768];
int length;
while((length = fis.read(buffer)) > 0) {
backup.write(buffer, 0, length);
}
backup.flush();
backup.close();
fis.close();
catch (IOException e) {
e.printStackTrace();
confirmaction = false;
}
I use the following to get the pathname for backupfilename:-
File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),subdirectory);
this.directory = dir.getPath();
I then add the actual filename (which is user input).
Note! I do checks to determine that EXTERNAL storage is mounted etc.
To get the database path i use:-
String dbfilename = this.getDatabasePath(
DBConstants.DATABASE_NAME).getPath();
dbfile = new File(dbfilename);
This is of course Java, but I'd assume that it could be converted/adapted to suit. The crux of the answer is to get the database file into a place from which you can access it.
Call the ExtractDb method from your activity
public void ExtractDB()
{
var szSqliteFilename = "databasename.db3";
var szSourcePath = new FileManager().GetLocalFilePath(szSqliteFilename);
var szDatabaseBackupPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/databasename_Backup.db3";
if (File.Exists(szSourcePath))
{
File.Copy(szSourcePath, szDatabaseBackupPath, true);
Toast.MakeText(this, "Copied", ToastLength.Short).Show();
}
}
Get path to the android device storage as shown below
public class FileManager
{
public string GetLocalFilePath(string filename)
{
string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
return Path.Combine(path, filename);
}
}
you need to add the android.permission.WRITE_EXTERNAL_STORAGE permission in your manifest file.

Can't write to SD card

My app allows user to take a picture and I want that picture to be stored in the app's external files directory (getExternalFilesDir(null)). It all works except for the call to renameTo(), this call returns false and I don't know why.
The src file is:
/storage/extSdCard/DCIM/Camera/20140424_154458.jpg
Dest file is:
/storage/emulated/0/Android/data/com.myapp.myapp/files/20140424_154458.jpg
I also have specified the WRITE_EXTERNAL_STORAGE permission.
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
if (item.getItemId() == R.id.action_take_picture)
{
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, TAKE_PICTURE_REQUEST_CODE);
return true;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (requestCode == TAKE_PICTURE_REQUEST_CODE && resultCode == RESULT_OK)
{
File dest = new File(
getExternalFilesDir(null),
new SimpleDateFormat("yyyyMMdd_hhmmss", Locale.getDefault()).format(new Date()) + ".jpg");
File src = new File(convertMediaUriToPath(data.getData()));
if (src.renameTo(dest)) // Always returns false
{
mAdapter.add(dest);
mAdapter.notifyDataSetChanged();
}
}
}
private String convertMediaUriToPath(Uri uri)
{
String[] proj = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(uri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String path = cursor.getString(column_index);
cursor.close();
return path;
}
I have ran into this problem previously - unfortunately, you are not allowed to use renameTo to move files and/or directories between different mount points (for example, internal and external storage). Consider using a different way of moving files, such as the one outlined here:
http://www.mkyong.com/java/how-to-copy-directory-in-java/
public static void copyFolder(File src, File dest) throws IOException{
if(src.isDirectory()){
//if directory not exists, create it
if(!dest.exists()){
dest.mkdir();
System.out.println("Directory copied from "
+ src + " to " + dest);
}
//list all the directory contents
String files[] = src.list();
for (String file : files) {
//construct the src and dest file structure
File srcFile = new File(src, file);
File destFile = new File(dest, file);
//recursive copy
copyFolder(srcFile,destFile);
}
}else{
//if file, then copy it
//Use bytes stream to support all file types
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
int length;
//copy the file content in bytes
while ((length = in.read(buffer)) > 0){
out.write(buffer, 0, length);
}
in.close();
out.close();
System.out.println("File copied from " + src + " to " + dest);
}
}
The problem is with the method renameTo, the renameTo doesn't create subdirectories,
Reason being The current File API isn't very well implemented in Java. There is a lot of functionality that would be desirable in a File API that isn't currently present such as move, copy and retrieving file metadata.
I don't think anyone will be able to give you an answer as to why the API is written as is. Probably a poor first draft that went live and couldn't be changed due to backwards compatibility issues.
These issue have been addressed in the Java 7. A entirely new API has been created to deal with files java.nio.file.Files.
To Solve this issue, try to get directory path of destination file
e.g /storage/emulated/0/Android/data/com.myapp.myapp/files/20140424_154458.jpg
Destination Directory is
/storage/emulated/0/Android/data/com.myapp.myapp/files/
Use mkdirs() , it will create all sub directories for you
If you want to add a file or folder or move application into your SD Card just do the following:
steps:
1) Open your Android application's source code file with a text or programming editor. 2) Browse to the location in the source code where you wish to call the function that writes a file to the device's external storage. 3) Insert this single line of code to check for the SD card:
File sdCard = Environment.getExternalStorageDirectory();
4) Insert these lines of code to set the directory and file name:
File dir = new File (sdcard.getAbsolutePath() + "/folder1/folder2");
dir.mkdirs();
File file = new File(dir, "example_file");
// The mkdirs function will create the directory folder for you, use it only you want to create a new one.
5) Replace "/folder1/folder2" in the above code with the actual path where you intend to save the file. This should be a location in which you normally save your application files. Also, change the "example_file" value to the actual file name you wish to use.
6) Insert the following line of code to output the file to the SD card:
FileOutputStream f = new FileOutputStream(file);
Finally step 7:
Save the file, then compile it and test the application using the Android emulator software or the device.
This will work!!! ;-)

android copy /dev/log/* to SD card failer

GUYS
I'm new to android and this is my first post in StackOverflow.English as my second language,I'm not that good at it.I just looked for some answers here before,Now I think it's time for me to get involved in it.
There have been a problem occured when I try to copy the system log which located in /dev/log/* to my SD card.After some search on the answers here,I came across Copy file (image) from CacheDir to SD Card.So I had my code below:
private final String srcLocation = "/dev/log/radio";
private final String desLocation = "/mnt/sdcard/radio";
FileInputStream src;
FileOutputStream dst;
FileChannel mFCsrc;
FileChannel mFCdst;
public boolean copyFile(String sourceLocation, String destLocation) throws IOException {
try {
File sd = Environment.getExternalStorageDirectory();
if(sd.canWrite()){
File source=new File(sourceLocation);
File dest=new File(destLocation);
if(!dest.exists()){
dest.createNewFile();
}
if(source.exists()){
src = new FileInputStream(source);
dst = new FileOutputStream(dest);
mFCsrc = src.getChannel();
mFCdst = dst.getChannel();
mFCsrc.transferTo(0, mFCsrc.size(), mFCdst);
}
}
return true;
} catch (Exception ex) {
ex.printStackTrace();
return false;
} finally {
if (mFCsrc != null) {
mFCsrc.close();
}
if (mFCdst != null) {
mFCdst.close();
}
}
}
I do have the file in my SD card which I can see it from my DDMS window,but it's size is 0.So,anyone gets a clue? Thanks in advance.(I try to give you a picture of my DDMS window,but since my reputation is not enough,I cann't use a picture.I'm sorry about that!!)
You should debug. Step trough your code with the debugger and check what is happening.
Random thing that might be happening, but we have no way of knowing for sure: If "source" doesn't exist, you will create dest, but because source.exists() will return false,you don't do anything after that. You'll end up with the current behaviour, a newly created file without contents.

Reading an .xml file from sdcard

I have one xml file called bkup.xml stored inside sdcard "/sdcard/bkup.xml".
For creating bkup.xml I have used xmlSerialization.
I want to retrieve data from that bkup.xml file.
I have seen many examples but almost most of them are using resource file and using URL as a resource. But no one have example of giving a path of sdcard file.
I don't know how to fetch data from that file and parse it.
Thanks in advance.
Any suggestion will be appreciated
Here is an complete example with source. You just to get the File using
File file = new File(Environment.getExternalStorageDirectory()
+ "your_path/your_xml.xml");
Then do the further processing.
UPDATE
If you need example for different types of XML Parsers you can download complete example from here.
Use the FileReader Object like this :
/**
* Fetch the entire contents of a text file, and return it in a String.
* This style of implementation does not throw Exceptions to the caller.
*
* #param aFile is a file which already exists and can be read.
* File file = new File(Environment.getExternalStorageDirectory() + "file path");
*/
static public String getContents(File aFile) {
//...checks on aFile are elided
StringBuilder contents = new StringBuilder();
try {
//use buffering, reading one line at a time
//FileReader always assumes default encoding is OK!
BufferedReader input = new BufferedReader(new FileReader(aFile));
try {
String line = null; //not declared within while loop
/*
* readLine is a bit quirky :
* it returns the content of a line MINUS the newline.
* it returns null only for the END of the stream.
* it returns an empty String if two newlines appear in a row.
*/
while (( line = input.readLine()) != null){
contents.append(line);
contents.append(System.getProperty("line.separator"));
}
}
finally {
input.close();
}
}
catch (IOException ex){
ex.printStackTrace();
}
return contents.toString();
}
Also you need to add permission to access the SDCard on the device.

Categories

Resources