AsyncTask: What to use when doInBackground busy? - android

I have to share an image in my app.
Glide.with(PhotoFullScreenActivity.this)
.asBitmap()
.load(getBestDownscaledAlternative(mPhotoList.get(mCurrentPosition)))
.into(new SimpleTarget<Bitmap>() {
#Override
public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
startShareImageTask(resource);
}
#Override
public void onLoadFailed(#Nullable Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
Log.e("Check","error");
}
});
I'm using the above snippet to convert the URL into a bitmap and after the resource is ready I call the startShareImageTask to create a file.
The startShareImageTask looks like this:
private void startShareImageTask(Bitmap resource){
new AsyncTask<Bitmap, Void, Uri>(){
#Override
protected void onPreExecute() {
super.onPreExecute();
mShareLoadingPB.setVisibility(View.VISIBLE);
Log.d("ShareImageTask", "onPreExecute: " + System.currentTimeMillis());
}
#Override
protected Uri doInBackground(Bitmap... bitmaps) {
Uri bmpUri = null;
try {
// Use methods on Context to access package-specific directories on external storage.
// This way, you don't need to request external read/write permission.
File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "share_image_" + System.currentTimeMillis() + ".png");
FileOutputStream out = new FileOutputStream(file);
resource.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.close();
// wrap File object into a content provider. NOTE: authority here should match authority in manifest declaration
bmpUri = ImageFileProvider.getUriForFile(PhotoFullScreenActivity.this, getApplicationContext().getPackageName() + ".fileprovider", file); // use this version for API >= 24
} catch (IOException e) {
e.printStackTrace();
mShareLoadingPB.setVisibility(View.GONE);
}
return bmpUri;
}
#Override
protected void onPostExecute(Uri uri) {
super.onPostExecute(uri);
mShareLoadingPB.setVisibility(View.GONE);
mShareIntent = new Intent();
mShareIntent.setAction(Intent.ACTION_SEND);
mShareIntent.putExtra(Intent.EXTRA_STREAM, uri);
mShareIntent.setType("image/*");
startActivity(Intent.createChooser(mShareIntent, "Share image"));
}
}.execute();
}
All works out great but my app needs to record something in a background task and when it does, my doInBackground method is not called until I finish the recording...I want to share the image while I'm recording something.
What can I do when my background thread is busy with another task?
Is there any workaround to this?

I was able to make this work by changing the AsyncTask to RxJava. I'll leave the code difference here in case anyone bumps into this issue.
mShareLoadingPB.setVisibility(View.VISIBLE);
Log.d("ShareImageTask", "onPreExecute: " + System.currentTimeMillis());
Observable.fromCallable(() -> {
Uri bmpUri = null;
try {
// Use methods on Context to access package-specific directories on external storage.
// This way, you don't need to request external read/write permission.
File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "share_image_" + System.currentTimeMillis() + ".png");
FileOutputStream out = new FileOutputStream(file);
resource.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.close();
// wrap File object into a content provider. NOTE: authority here should match authority in manifest declaration
bmpUri = ImageFileProvider.getUriForFile(PhotoFullScreenActivity.this, getApplicationContext().getPackageName() + ".fileprovider", file); // use this version for API >= 24
} catch (IOException e) {
e.printStackTrace();
mShareLoadingPB.setVisibility(View.GONE);
}
return bmpUri;
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DefaultObserver<Uri>() {
#Override
public void onNext(Uri uri) {
mShareLoadingPB.setVisibility(View.GONE);
mShareIntent = new Intent();
mShareIntent.setAction(Intent.ACTION_SEND);
mShareIntent.putExtra(Intent.EXTRA_STREAM, uri);
mShareIntent.setType("image/*");
startActivity(Intent.createChooser(mShareIntent, "Share image"));
}
#Override
public void onError(Throwable e) {
Log.e("Error","Error");
}
#Override
public void onComplete() {
}
});

Related

How to upload file by content uri in WebView

Typical Scenario
In order to upload a file using WebView, it's typically needed to override WebChromeClient, and start a file chooser Activity for result:
...
webView.setWebChromeClient(new WebChromeClient() {
#Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
FileChooserParams fileChooserParams) {
mFilePathCallback = filePathCallback;
Intent intent = new Intent(MainActivity.this, FilePickerActivity.class);
startActivityForResult(intent, 1);
return true;
}
});
...
Then, once file is selected (for simplicity, only a single file can be selected at a time), onActivityResult() is called with a file uri stored in a data object. So, the uri is retrieved and handed over to filePathCallback and the file gets uploaded:
...
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
if (requestCode == 1) {
mFilePathCallback.onReceiveValue(new Uri[] {data.getData()});
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
...
Basically, filePathCallback requires a uri to a file so that to upload it.
The problem
What if I have only an InputStream that contains the data I need to upload rather than a file with a URI? And I cannot save that data to a file so that to generate a URI (for security reasons). Is there a way to upload the data as a file in such case? In particular, can I convert an InputStream to a content URI and then upload it?
Approach 1
This approach works fine, if uri is generated using Uri.fromFile() as below:
...
Uri uri = Uri.fromFile(file);
...
Approach 2
If I implement my own ContentProvider and override openFile there in such a way, that it uses ParcelFileDescriptor.open() to create a ParcelFileDescriptor, then uploading a file based on a uri provided by getContentUri(...) is working without problems:
FileUploadProvider.java
public class FileUploadProvider extends ContentProvider {
public static Uri getContentUri(String name) {
return new Uri.Builder()
.scheme("content")
.authority(PROVIDER_AUTHORITY)
.appendEncodedPath(name)
.appendQueryParameter(OpenableColumns.DISPLAY_NAME, name)
.build();
}
#Nullable
#Override
public ParcelFileDescriptor openFile(#NonNull Uri uri, #NonNull String mode) throws FileNotFoundException {
List<String> segments = uri.getPathSegments();
File file = new File(getContext().getApplicationContext().getCacheDir(),
TextUtils.join(File.separator, segments));
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
}
...
}
Approach 3
However, if I create a ParcelFileDescriptor with help of ParcelFileDescriptor.createPipe(), then file upload never finishes, so it basically doesn't work:
...
public ParcelFileDescriptor openFile(#NonNull Uri uri, #NonNull String mode) throws FileNotFoundException {
List<String> segments = uri.getPathSegments();
File file = new File(getContext().getApplicationContext().getCacheDir(),
TextUtils.join(File.separator, segments));
InputStream inputStream = new FileInputStream(file);
ParcelFileDescriptor[] pipe;
try {
pipe = ParcelFileDescriptor.createPipe();
} catch (IOException e) {
throw new RuntimeException(e);
}
ParcelFileDescriptor readPart = pipe[0];
ParcelFileDescriptor writePart = pipe[1];
try {
IOUtils.copy(inputStream, new ParcelFileDescriptor.AutoCloseOutputStream(writePart));
} catch (IOException e) {
throw new RuntimeException(e);
}
return readPart;
}
...
Approach 4
To make matters worse, if I create a ParcelFileDescriptor with help of MemoryFile, then file upload never finishes as well:
...
public ParcelFileDescriptor openFile(#NonNull Uri uri, #NonNull String mode) throws FileNotFoundException {
List<String> segments = uri.getPathSegments();
File file = new File(getContext().getApplicationContext().getCacheDir(),
TextUtils.join(File.separator, segments));
try {
MemoryFile memoryFile = new MemoryFile(file.getName(), (int) file.length());
byte[] fileBytes = Files.readAllBytes(file.toPath());
memoryFile.writeBytes(fileBytes, 0, 0, (int) file.length());
Method method = memoryFile.getClass().getDeclaredMethod("getFileDescriptor");
FileDescriptor fileDescriptor = (FileDescriptor) method.invoke(memoryFile);
Constructor<ParcelFileDescriptor> constructor = ParcelFileDescriptor.class.getConstructor(FileDescriptor.class);
ParcelFileDescriptor parcelFileDescriptor = constructor.newInstance(fileDescriptor);
return parcelFileDescriptor;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
...
Why is file upload not working for Approach 3 and Approach 4?
Example
I created a sample app to showcase my issue here.
Below are steps to follow to reproduce it. First log in to your gmail account and click "create new message".
Solution
My colleagues have found a solution to this with help of StorageManager - please read more about the component here.
First, create a callback that handles file system requests from ProxyFileDescriptor in FileUploadProvider:
private static class CustomProxyFileDescriptorCallback extends ProxyFileDescriptorCallback {
private ByteArrayInputStream inputStream;
private long length;
public CustomProxyFileDescriptorCallback(File file) {
try {
byte[] fileBytes = Files.readAllBytes(file.toPath());
length = fileBytes.length;
inputStream = new ByteArrayInputStream(fileBytes);
} catch (IOException e) {
// do nothing here
}
}
#Override
public long onGetSize() {
return length;
}
#Override
public int onRead(long offset, int size, byte[] out) {
inputStream.skip(offset);
return inputStream.read(out,0, size);
}
#Override
public void onRelease() {
try {
inputStream.close();
} catch (IOException e) {
//ignore this for now
}
inputStream = null;
}
}
Then, create a file descriptor using StorageManager that will read the InputStream with help of the callback above.
...
StorageManager storageManager = (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
ParcelFileDescriptor descriptor;
try {
descriptor = storageManager.openProxyFileDescriptor(
ParcelFileDescriptor.MODE_READ_ONLY,
new CustomProxyFileDescriptorCallback(file),
new Handler(Looper.getMainLooper()));
} catch (IOException e) {
throw new RuntimeException(e);
}
return descriptor;
...
Please find the full code on github here.
Limitation
This approach is working only for Android API higher than 25.

In Android how can i share an http image to twitter as a tweet from my application

I have gone through many articles. But somehow i could not achieve what i wanted to achieve. I have a http image link in my app and i want to share this as an image attachment from Twitter application. I have tried following. But it seems not to be working as Twitter expects it to be a local url.
TweetComposer.Builder builder = new TweetComposer.Builder(context)
.text(text)
.image(Uri.parse("https://dummyimage.com/300/09f/fff.png"));
builder.show();
So now that i know it requires a local path, i tried to download the image to phone using Picasso as below.
Picasso.get().load(CONSTANT.IAMGE_URI + list.get(position).getEvent_model().getPhoto_link())
.placeholder(R.drawable.placeholder)
.error(R.drawable.placeholder)
.into(getTarget(list.get(position).getEvent_model().getPhoto_link()));
File myImageFile = new File(getFileFullPath(list.get(position).getEvent_model().getPhoto_link()));
Picasso.get().load(myImageFile).into(holder.iv_album_image);
And this is code to get the target.
private static Target getTarget(final String fileName) {
Target target = new Target() {
//This method in target is called by picasso when image downloaded
#Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
new Thread(new Runnable() {
#Override
public void run() {
try {
File file = new File(getFilename(fileName));
if (file.exists()) {
file.delete();
}
file.createNewFile();
FileOutputStream fileoutputstream = new FileOutputStream(file);
ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 60, bytearrayoutputstream);
fileoutputstream.write(bytearrayoutputstream.toByteArray());
fileoutputstream.close();
} catch (IOException e) {
Log.e("IOException", e.getLocalizedMessage());
}
}
}).start();
}
#Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
return target;
}
public static String getFilename(String fileName) {
File file = new File(Environment.getExternalStorageDirectory().getPath(), "Images");
if (!file.exists()) {
file.mkdirs();
}
return (file.getAbsolutePath() + "/" + fileName);
}
In this case photo is not loading in to imageview and also not being downloaded to local.
You need to download the image to your phone, and use a local path.
https://docs.fabric.io/javadocs/tweet-composer/2.0.0/com/twitter/sdk/android/tweetcomposer/TweetComposer.Builder.html#image(android.net.Uri)
Ultimately for image:
The Uri should be a file Uri to a local file
Uri.fromFile(someExternalStorageFile)
Can you change your getFilename to match as such:
public static String getFilename(String fileName, Context context) {
int code = context.getPackageManager().checkPermission(
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
context.getPackageName());
if (code == PackageManager.PERMISSION_GRANTED) {
File file = new File(Environment.getExternalStorageDirectory().getPath(), "Images");
if (!file.exists()) {
file.mkdirs();
}
return (file.getAbsolutePath() + "/" + fileName);
}
return "";
}
And set a breakpoint at each return. My assumption is you're returning "";

PDF File showing empty using retrofit 2

I'm working on an app where I'm downloading a PDF file, saving it to internal storage and then opening that file in other app using FileProvider.
Note: It may be a duplicate question, I've gone through most of the questions on StackOverflow, but still didn't find the solution.
The file is getting downloaded fine but when I'm opening it, it is empty.
The downlaoded file is 30 kb and it has 5 pages but all are empty.
Initially, I thought it is empty because the other app doesn't have permission to open the file, but I did another thing to check whether it is a permission issue. I've saved the file to external storage, still, it was empty. So, it means it is not a permission issue.
Please Note:
Along with pdf file, there is some .xls file as well and when I'm opening those in excel android app, it says cannot open the file. This indicates, that there is some issue while writing the byte stream.
Retrofit Interface.java
#GET(ApiConstants.END_POINT_DOWNLOAD_DOCUMENT)
#Streaming
Call<ResponseBody> downloadDocument(#Query("bucket") String bucket, #Query("filename") String fileName);
Code to Download the file: Here I'm checking if a file is already there, then return the file, otherwise download the file.
public LiveData<Resource<File>> openOrDownloadFile(String bucket, String fileName) {
MutableLiveData<Resource<File>> documentLiveData = new MutableLiveData<>();
documentLiveData.postValue(Resource.loading(null));
Context context = MyApp.getInstance();
final File file = new File(context.getFilesDir(), fileName);
if (file.exists()) {
documentLiveData.postValue(Resource.success(file));
} else {
Call<ResponseBody> call = apiService.downloadDocument(bucket, fileName);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
appExecutors.diskIO().execute(new Runnable() {
#Override
public void run() {
try {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
byte[] fileReader = new byte[4096];
inputStream = response.body().byteStream();
outputStream = new FileOutputStream(file);
while (true) {
int read = inputStream.read(fileReader);
if (read == -1) {
break;
}
outputStream.write(fileReader, 0, read);
}
documentLiveData.postValue(Resource.success(file));
outputStream.flush();
} catch (IOException e) {
documentLiveData.postValue(Resource.error("Error: Unable to save file/n"+e.getLocalizedMessage(), null));
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
} catch (IOException e) {
Log.e(AppConstants.TAG, e.getMessage(), e);
documentLiveData.postValue(Resource.error("Error: Unable to save file/n"+e.getLocalizedMessage(), null));
}
}
});
} else {
documentLiveData.postValue(Resource.error("Unable to download file", null));
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
documentLiveData.postValue(Resource.error(t.getLocalizedMessage(), null));
}
});
}
return documentLiveData;
}
Fragment Code
private void onItemClickListener(Document document) {
mDocumentsViewModel.openORDownloadFile(document.getType(), document.getName()).observe(this, new Observer<Resource<File>>() {
#Override
public void onChanged(#Nullable Resource<File> fileResource) {
binding.setResource(fileResource);
if (fileResource.status == Status.SUCCESS) {
openFile(fileResource.data);
}
}
});
}
void openFile(File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = FileProvider.getUriForFile(getContext(), BuildConfig.APPLICATION_ID, file);
intent.setDataAndType(uri, mDocumentsViewModel.getMimeType(file.getAbsolutePath()));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
PackageManager pm = getActivity().getPackageManager();
if (intent.resolveActivity(pm) != null) {
startActivity(intent);
} else {
Toast.makeText(getActivity(), "This file cannot be opened on this device. Please download some compatible app from play store", Toast.LENGTH_SHORT).show();
}
}
Following are the versions :
ext.retrofit_version = "2.4.0"
ext.okhttp_version = "3.8.0"
I'm struggling with this issue, it'll be a great help if you can point out the issue. Thank you.
Update: The problem was with the backend APIs. My code was correct. Once they've fixed the problem at there side, it started working at my side without any changes.

AsyncTask println needs a message No Exception thrown

My AsyncTask is logging an error "println needs a message" however no exception is being thrown in my class. The task is started in an Activity which implements a callback interface I wrote called TaskCallback. In the onPostExecute() it calles the callback in the Activity. From this callback, I run another AsyncTask. Below is the code:
public class SaveImageTask extends AsyncTask<byte[], String, File> {
private static final String IMAGE_DATA_PATH =
Environment.getExternalStorageDirectory().toString() + "/MyAppFolder/AppImages/";
private static final String TAG = "SaveImageTask";
private TaskCallback mTaskCallback;
private ProgressDialog mProgressDialog;
public SaveImageTask(TaskCallback taskCallback) {
mTaskCallback = taskCallback;
}
#Override
protected void onPreExecute() {
mProgressDialog = new ProgressDialog((Context) mTaskCallback);
mProgressDialog.setMessage("Saving Image...");
mProgressDialog.setCanceledOnTouchOutside(false);
mProgressDialog.setCancelable(false);
mProgressDialog.show();
}
#Override
protected File doInBackground(byte[]... data) {
File imageFile = createOutputPictureFile();
if(imageFile == null) {
return null;
}
try {
Bitmap image = BitmapFactory.decodeByteArray(data[0], 0, data[0].length);
FileOutputStream out = new FileOutputStream(imageFile);
image.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
return imageFile;
}
#Override
public void onPostExecute(File imageFile) {
if(mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
if(mTaskCallback != null) {
mTaskCallback.onTaskComplete(imageFile);
}
}
private File createOutputPictureFile() {
File imageStorageDirectory = new File(IMAGE_DATA_PATH);
// If the default save directory doesn't exist, try and create it
if (!imageStorageDirectory.exists()){
if (!imageStorageDirectory.mkdirs()){
//Log.e(TAG, "Required media storage does not exist");
return null;
}
}
// Create a timestamp and use it as part of the file name
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.UK);
String timeStamp = dateFormat.format(new Date());
String fileName = "img_"+ timeStamp + ".jpg";
return new File (imageStorageDirectory, fileName);
}
}
The onTaskComplete(File file) looks like this:
#Override
public void onTaskComplete(File file) {
if(file == null) {
Util.showToast(this, "Save Failed.", Toast.LENGTH_SHORT);
return;
}
notifyDeviceOfNewFile(file);
ProcessImageTask pit = new ProcessImageTask(this);
pit.execute(file);
}
And the error logged is:
E/SaveImageTask: println needs a message
As it says in the title, no exception is thrown and the code actually does what it is supposed to do. I've narrowed the issue down to this line of code in the callback:
pit.execute(file);
If I comment out this line the error doesn't appear. I'm a bit stumped on what's going on. If I remove all logging in my SaveImageTask it still appears so something else is logging it.
There is a reason why a exception is not thrown, because you catch it. That is the whole concept about try-catch.
try {
Bitmap image = BitmapFactory.decodeByteArray(data[0], 0, data[0].length);
FileOutputStream out = new FileOutputStream(imageFile);
image.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
// normally you do stuff here when it fails.
}
I believe "println needs a message" is what's shown if you pass a null to Log.x(). You're probably getting an IOException - e.printstacktrace() will probably give you a better idea of why.
Ok, turns out I was being an idiot and the error was from another class which for some reason had the same TAG it was logging with. Thank you for your input and suggestions, an important lesson about copy/pasting code was learned today.

how can I access Picasso' s cached image to make a share intent?

I' m using Picasso to help the cache of images.
The question is, how can I access the downloaded image to make a share intent?
any ideas? thanks!
I hope you can understand my question :-)
Sorry for my delay, I found a solution, but, not a good one...
First, I really searched for a while and looked at the code of Picasso. It seems like you should provide your own downloader and other stuff. But then, why should I use the lib...
And then, I suppose it's Picasso's design / architecture to just cache the file in the internal storage. Maybe because the external storage is not always available (like the user may plug in his SD card to his computer), or maybe because the external storage is not as fast as the internal... That's my guess. In a word, other apps cannot access the internal storage of the current app, so the share cannot be done.
Thus, I made a really ordinary solution. I just wait for Picasso to give the Bitmap, and compress it to a file in the external file, then do the share. It seems like a bad solution, but it really solves the problem, yes...
You should be aware of whether the external cache directory is available or not. If not, you cannot do the share. And you need to put the compress task in a background thread, so, waiting the external file cached... Does it seem like a bad solution? I think so...
Below is my project code, you can have a try...
private boolean mSaved; // a flag, whether the image is saved in external storage
private MenuItem mShare;
private Intent mIntent;
private ShareActionProvider mShareActionProvider;
private File mImage; // the external image file would be saved...
private Target target = new Target() {
#Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
new Thread(new Runnable() {
#Override
public void run() {
FileOutputStream os = null;
try {
String dir = CatnutUtils.mkdir(getActivity(), Constants.FANTASY_DIR); // check the exteral dir avaiable or not...
String[] paths = Uri.parse(mUrl).getPath().split("/");
mImage = new File(dir + File.separator + paths[2] + Constants.JPG); // resoleve the file name
} catch (Exception e) { // the external storage not available...
Log.e(TAG, "create dir error!", e);
return;
}
try {
if (mImage.length() > 10) { // > 0 means the file exists
// the file exists, done.
mIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(mImage));
mSaved = true;
return;
}
os = new FileOutputStream(mImage);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
mIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(mImage));
mSaved = true;
} catch (FileNotFoundException e) {
Log.e(TAG, "io error!", e);
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
Log.e(TAG, "io closing error!", e);
}
}
}
}
}).start();
mFantasy.setImageBitmap(bitmap);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
mFantasy.setImageDrawable(errorDrawable);
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
if (placeHolderDrawable != null) {
mFantasy.setImageDrawable(placeHolderDrawable);
}
}
};
#Override
public void onPrepareOptionsMenu(Menu menu) {
mShare.setEnabled(mSaved);
}
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fantasy, menu);
mShare = menu.findItem(R.id.action_share);
mShareActionProvider = (ShareActionProvider) mShare.getActionProvider();
mShare.setActionProvider(mShareActionProvider);
mShareActionProvider.setShareIntent(mIntent);
}
Finally, call Picasso.with(getActivity()).load(mUrl).into(target);
When the file is saved, the user can click the share menu do the share.
public static File getImageFile(Context context, String url)
{
final String CACHE_PATH = context.getCacheDir().getAbsolutePath() + "/picasso-cache/";
File[] files=new File(CACHE_PATH).listFiles();
for (File file:files)
{
String fname= file.getName();
if (fname.contains(".") && fname.substring(fname.lastIndexOf(".")).equals(".0"))
{
try
{
BufferedReader br=new BufferedReader(new FileReader(file));
if (br.readLine().equals(url))
{
File imgfile= new File(CACHE_PATH + fname.replace(".0", ".1"));
if (imgfile.exists())
{
return imgfile;
}
}
}
catch (FileNotFoundException|IOException e)
{
}
}
}
return null;
}
I've just found out this guide with a very good solution.
https://guides.codepath.com/android/Sharing-Content-with-Intents
The code will be like this:
// Can be triggered by a view event such as a button press
public void onShareItem(View v) {
// Get access to bitmap image from view
ImageView ivImage = (ImageView) findViewById(R.id.ivResult);
// Get access to the URI for the bitmap
Uri bmpUri = getLocalBitmapUri(ivImage);
if (bmpUri != null) {
// Construct a ShareIntent with link to image
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, bmpUri);
shareIntent.setType("image/*");
// Launch sharing dialog for image
startActivity(Intent.createChooser(shareIntent, "Share Image"));
} else {
// ...sharing failed, handle error
}
}
// Returns the URI path to the Bitmap displayed in specified ImageView
public Uri getLocalBitmapUri(ImageView imageView) {
// Extract Bitmap from ImageView drawable
Drawable drawable = imageView.getDrawable();
Bitmap bmp = null;
if (drawable instanceof BitmapDrawable){
bmp = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
} else {
return null;
}
// Store image to default external storage directory
Uri bmpUri = null;
try {
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS), "share_image_" + System.currentTimeMillis() + ".png");
file.getParentFile().mkdirs();
FileOutputStream out = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.PNG, 90, out);
out.close();
bmpUri = Uri.fromFile(file);
} catch (IOException e) {
e.printStackTrace();
}
return bmpUri;
}
It basically consists in retrieving the bitmap from the imageview and saving it to a local temp file and then using it for sharing. I've tested it and it seems to work fine.

Categories

Resources