I have a CropViewActivity that crops an image, saves the cropped image to the external storage. The process of decoding the bitmap and saving it to external storage is done in another thread. So the crop activity finishes, while the image processing still goes on in the background. Now I want a way to inform my other Activity, which contains an ImageView. At the end of the image processing in the background, the ImageView should then fetch the saved image from memory and load it.
How to achieve this inter-thread cum inter-activity communication? Please help..
There are several ways of doing that. I would like to refer you some.
You might consider using BroadcastReceiver when you are finished processing your image. You need to register the receiver in your activity which contains the ImageView and after processing the image in another activity, send the broadcast with the desired intent that you are listening to receive. Here's a sample implementation on how you can implement a BroadcastReceiver.
Another way of communicating between activities is starting an activity for a result. See developers documentation to see how you can use startActivityForResult and then get the result from the activity which is processing the image and getting the result back to the calling activity which contains the ImageView in your case.
You might pick any of these two which is best suited according to your use-case. Hope that helps.
AsnycTask?
typealias Callback = () -> Unit
class BitmapWorker: AsyncTask<Callback, Void, Callback?>
override fun doInBackground(vararg params: Callback): Callback? {
// work with bitmap
return params.firstOrNull()
}
override fun onPostExecute(finishTask: Callback?) {
finishTask?.invoke()
}
}
Call this like:
BitmapWorker().execute(fun() {
println("finished")
}
Related
I have a helper method for choosing images and videos, let's call it Activity B.
So, this is how it works:
// were in Activity A
// user wants to choose a video
startActivityB(callbacks);
------------------------------------
// were in Activity B now
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("video/*");
chooseVideoLauncher.launch(intent);
------------------------------------
// were in chooseVideoLauncher now
Uri videoURI = ...;
callbacks.passVideoURI(videoURI); // this way, Activity A gets the videoURI
// do some more things...
finish(); // so the helper activity B is finished now, as the video is chosen already
------------------------------------
// were in activity A again, but now we have the videoURI
// user clicked a button: "Upload video"
uploadVideo(videoURI);
This is the error I get:
java.lang.SecurityException: Permission Denial: opening provider com.miui.gallery.provider.GalleryOpenProvider from ProcessRecord{f5899ab 29899:com.xxx} (pid=xxx, uid=xxx) that is not exported from UID xxx
I have googled the error and found this SO thread: here
#CommonsWare explains the error in a comment and links his blog post: Uri Access Lifetime: Shorter Than You Might Think
So the error happens because the helper Activity B chose the file, so the access is tied to Activity B. No other activity has access, and as soon as Activity B is destroyed (what happens in my code), the access to videoURI is completely gone. So when I later try to upload the video, it throws this error.
I tried these solutions:
Create a local copy of the video and pass that copy to Activity A. This works, but is a bad solution. For longer videos the app crashes with a memory overflow. So it's not an option.
Setting the flags #CommonsWare mentioned. So the code looks like this:
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("video/*");
intent.setFlags(FLAG_GRANT_READ_URI_PERMISSION);
intent.setFlags(FLAG_GRANT_WRITE_URI_PERMISSION);
chooseVideoLauncher.launch(intent);
But this doesn't seem to change anything. The error message remains exactly the same. Am I setting them wrong?
#CommonsWare says using a service would also be a solution. I would prefer not to create a service purely for fixing this permission error. If there's no other solution, I will of course.
But is there no way to grant Activity A permission to that Uri as well?
The best solution, by far, is to combine Activity A and Activity B into a single activity. Use fragments or composables for separate screens.
Setting the flags #CommonsWare mentioned. So the code looks like this:
You would not set the flags on the ACTION_PICK Intent. Instead, Activity B needs to start Activity A (in addition to finish()). You would put the Uri into the "data" facet of the Intent (e.g., via setData()), and you would put the flags on that Intent. You would also need something like FLAG_ACTIVITY_REORDER_TO_FRONT or something to avoid having two copies of Activity A on the back stack.
For the second way Set the flags to get the long lifetime, you can try to add the following code, to get the permission, then start the activity
val contentResolver = applicationContext.contentResolver
val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
// Check for the freshest data.
contentResolver.takePersistableUriPermission(uri, takeFlags)
I am building my application using Android Studio, this app can upload an image from raspberry to my emulator. It works fine. What I want to do now is uploading this image and showing it directly to the user without searching it in the gallery. I thought about creating another class and setting this image as a background image in my xml file, but this is too much like I have to create another class every time I want to upload an image from my raspberry.
Can someone help me please. Thank you
If I'm understanding your question correctly, you'd like to load an image from the Android filesystem into your app and display it to the user.
Drawable, Android's generalized image class, allows you to load from file via Drawable#createFromPath.
This SO question suggests Drawable#createFromPath doesn't work on paths beginning with file://, so depending on your use case you may want to precede that with Uri#parse/Uri#getPath.
Once you have a Drawable, you can display it in one of two ways: put an ImageView in your app and call its setImageDrawable method, or set the Drawable as your background image via View#setBackground (note that setBackground was only added in API 16 - in prior versions, you should call View#setBackgroundDrawable).
Putting all of this together, we end up with the following (untested):
private void loadImage(String imagePath) {
Uri imageUri;
String fullImagePath;
Drawable image;
ImageView imageDisplay;
imageUri = Uri.parse(imagePath);
fullImagePath = imageUri.getPath();
image = Drawable.createFromPath(fullImagePath);
imageDisplay = (ImageView) findViewById(R.id.imageDisplay);
/*if image is null after Drawable.createFromPath, this will simply
clear the ImageView's background */
imageDisplay.setImageDrawable(image);
/*if you want the image in the background instead of the foreground,
comment the line above and uncomment this bit instead */
//imageDisplay.setBackground(image);
}
You should be able to modify this to work with any View just by replacing imageDisplay's declared type with the appropriate View type and changing the cast on findViewById. Just make sure you're calling setBackground, not setImageDrawable, for a non-ImageView View.
I'm making this netflix style app in which images are loaded into different categories. Let's say Dog videos (has 15 images), Cat videos (15 images), etc... All the images are loaded from a URL, it kind of takes a while for all to load. I was wondering if there was anything I could do to speed up the process? Or maybe show an empty container then fill it as the images load (that would be cool).
This is what I have done:
I have multiple async calls in one Activity, (1 async call per category)
JSONTask1 dogTask = new JSONTask1();
JSONTask2 catTask = new JSONTask2();
JSONTask3 pigTask = new JSONTask3();
JSONTask4 horseTask = new JSONTask4();
dogTask.execute("");
catTask.execute("");
pigTask.execute("");
horseTask.execute("");
I have all of those in a row in my actual code. Thanks.
I would use the "proxy pattern". Basically, you need to create a class that contains the minimal informations required for the display. In which, you have a preview image.
When ever you load everything you start by showing the preview content, ie : a loading gif for everypicture with the title of the movie or whatever. and basically the proxy would have a "loadImage" method that would make an ajax call or async call and the photos would load one by one. Plus, to make the loading easier, make sure the photos are not oversized.
You can see Picasso answers , in picasso i suggest you this way :
Picasso.with(getApplicationContext()).load("your url").placeholder(R.drawable.your_place_holder).error(R.drawable.showing_when_error_occured)
.into(imageView, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError() {
}
});
Also another suggestion from me : convert your thumb images to base64 format in backend, then firstly retrieve your thumbs and show them. Then start an async task and change images when successfull.
Like whatsapp. In whatsapp you have thumb images they have so low resolution and super fast. When you click image if you have internet connection they load actual thumb images, and click again they load larger image.
Picasso website :http://square.github.io/picasso/
Load them asynchronously with Picasso, you can even show a placeholder image until the real one is loaded
I am making an android application in which I am showing image from internet into a ImageView by help of these classes
MemoryCache
ImageLoader
FileCache
Utils
In my main class I am calling this method imgLoader.DisplayImage(strURL, loader, image); to show the image and It is working really very fine and I think The four classes which I have mentioned above are common may be people know about that (If you don't then here's the code)
Now I want this method to call in AsyncTask class method doInBackground()
how can I do this.
And here is what I am doing is:
protected ImageView doInBackground(String...args)
{
try
{
imgLoader.DisplayImage(strURL, loader, image);
}catch(Exception e)
{
e.printStackTrace();
} ;
return image;
}
I know that it is completely wrong we can not pass an image as ImageView please help me how can I return the image from this function.
if you're going to be loading an image in a background thread via an async, just store the image url to a string and update your views in the onPostExecute(void..) function
Honestly though, I wouldn't use imageLoader for anything. I've used it before and it has limitations. Picasso is a much better way to cache and load images. Faster as well.
http://square.github.io/picasso/
Lmk if you have anymore questions!
What I would like to have is an activity indicator, which is displayed after my app is up and running, but while GWT is making AJAX calls.
For example have a look at following site : http://www.foodtrucksmap.com/#
Any ideas on how to achieve it?
You can use an activity indicator from here, they are animated gifs so you can display one like this:
<g:Image ui:field="activityImage"/>
MyResources resources = GWT.create(MyResources.class);
this.activityImage.setResource(resources.activityImage());
and in your resources interface you would set the image:
public interface MyResources extends ClientBundle{
// use the actual path to your image
#Source("../resources/images/activityImage.gif")
ImageResource activityImage();
}
When you make your async calls:
loadingImage.setVisible(true);
and in the callback:
loadingImage.setVisible(false);
I had to deal with the same kind of stuff few days back. The way I did was, created an Icon and Overlayed on the map.
Icon icon = Icon.newInstance("loading.gif"); // load you gif as icon
MarkerOptions options = MarkerOptions.newInstance();
options.setIcon(icon);
Marker indicator = new Marker(point, options);
So before the Async call and after you map is up, just add the icon to the map using
map.addOverlay(indicator);
and after the Async call remove the overlay using
map.removeOverlay(indicator);
I am not sure how correct this approach is, but this is what I did and it worked.