I wrote the following code:
Glide.with(this).asBitmap().load(userImageURL).into(new CustomViewTarget<ImageView, Bitmap>(userAvatarImage) {
#Override
protected void onResourceCleared(#Nullable Drawable placeholder) {
progressBarUserAvatar.setVisibility(View.GONE);
userAvatarImage.setImageBitmap(null);
}
#Override
public void onLoadFailed(#Nullable Drawable errorDrawable) {
progressBarUserAvatar.setVisibility(View.GONE);
final Bitmap circleLetterTile = tileProvider.getCircularLetterTile(userFullName);
userAvatarImage.setImageBitmap(circleLetterTile);
}
#Override
public void onResourceReady(#NonNull Bitmap resource, #Nullable Transition<? super Bitmap> transition) {
progressBarUserAvatar.setVisibility(View.GONE);
final Bitmap circleAvatarBitmap = tileProvider.getCircularImage(resource);
userAvatarImage.setImageBitmap(circleAvatarBitmap);
userAvatarImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent showProfilePictureIntent = new Intent(UserProfileActivity.this, DisplayUserImageActivity.class);
showProfilePictureIntent.putExtra("userImageURL",userImageURL);
final String transitionName = ViewCompat.getTransitionName(userAvatarImage);
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
UserProfileActivity.this, userAvatarImage, transitionName);
UserProfileActivity.this.startActivity(showProfilePictureIntent, options.toBundle());
UserProfileActivity.this.overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
}
});
}
});
It basically displays the user's image using Glide. It also set a onClick listener that opens the image in large mode with black background. Currently, UserProfileActivity is empty (just loads the layout). The problem is that I can't use getTransitionName because it's possible only for api 21. I'm have to use API 16 in my project so it's a problem. What would be the easiest way to achieve it? I looked into previous topics but they all between 2013-2015 so I thought maybe there is a way to do it.
This is not possible to do, using API >21. As you can refer to the official documentation here https://developer.android.com/reference/android/app/ActivityOptions#makeSceneTransitionAnimation(android.app.Activity,%20android.view.View,%20java.lang.String).
I'm not sure, why you don't have warning usage, but do for getTransitionName. Unfortunately it's not supported on early version. As another reference you can check https://www.programcreek.com/java-api-examples/?class=android.app.ActivityOptions&method=makeSceneTransitionAnimation about examples how to use transition animation.
Off topic
You can achieve animation you want by writing own tools with transition animation. It's not so easy, but it's pure view implementation, and you don't need new Android version. For the same reason, you can use Flutter (min version for which is Android 16) and make transition animation (hero animation) with few lines of codes. Because it's out of box implementation.
Related
I'm making an app that in many other functions, pulls images via URL and then it shows them in a PDF file. I did it on the hard way downloading them and using an asyncTask to handle all the process, but I heard that piccasso does this work better and cleaner so I decided to give it a try.
So I want to put the image loaded with piccaso within a Drawable so let's say I'm trying to do something like this:
Drawable drawable=Picasso.get().load("URL");
which of course is ridiculous and it's impossible, so I'm wondering if there is a way I can pull the image
with picasso and then transform it to a Drawable so I can then draw it on the PDF file that I need to generate
This code may help you:
Target target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
imageView.setImageBitmap(bitmap);
Drawable image = imageView.getDrawable();
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {}
};
Picasso.with(this).load("url").into(target);
Or, just look here: https://stackoverflow.com/a/25799983/11162243
I am creating a basic camera app as a small project I'm doing to get started with Android development.
When I click on the button to take a picture, there is about a 1-second delay in which the preview freezes before unfreezing again. There is no issue with crashing - just the freezing issue. Why is this happening and how can I fix it?
Below is the method where the camera is instantiated, as well as my SurfaceView class.
private void startCamera() {
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
cameraPreviewLayout = (FrameLayout) findViewById(R.id.camera_preview);
camera = checkDeviceCamera();
camera.setDisplayOrientation(90);
mImageSurfaceView = new ImageSurfaceView(MainActivity.this, camera);
cameraPreviewLayout.addView(mImageSurfaceView);
ImageButton captureButton = (ImageButton)findViewById(R.id.imageButton);
captureButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
camera.takePicture(null, null, pictureCallback);
camera.stopPreview();
camera.startPreview();
}
});
}
public class ImageSurfaceView extends SurfaceView implements
SurfaceHolder.Callback {
private Camera camera;
private SurfaceHolder surfaceHolder;
public ImageSurfaceView(Context context, Camera camera) {
super(context);
this.camera = camera;
this.surfaceHolder = getHolder();
this.surfaceHolder.addCallback(this);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
this.camera.setPreviewDisplay(holder);
this.camera.startPreview();
this.camera.setDisplayOrientation(90);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
EDIT: There is currently nothing in the pictureCallback.
Camera.PictureCallback pictureCallback = new Camera.PictureCallback() {
}
You don't need to call stopPreview() after takePicture(). And you don't need startPreview() on the next line. You do need startPreview() inside your onPictureTaken() callback (not in onClick() as in the posted code!!) if you want live preview to restart after the picture is captured into a Jpeg stream.
To keep your UI responsive while using camera, you should do all work with the camera on a background thread. But it is not enough to call Camera.open() or Camera.close() on some background thread. You must create a Handler thread and use it for Camera.open(). The same Looper will be used for all camera callbacks, including PictureCallback.onPictureTaken(). See my detailed walkthrough about the use of HandlerThread.
As I explained elsewhere, you can achieve even better performance if you use the new camera2 API on devices that fully support this API (but better use the old API with devices that provide only LEGACY level of camera2 support).
But if you want to get maximum from the camera ISP, this kind of freeze may be inevitable (this depends on many hardware and firmware design choices, made by the manufacturer). Some clever UI tweaks may help to conceal this effect.
You’ll need to enable access to the hidden “Developer options” menu on
your Android phone. To do that, simply tap the “About phone” option in
Settings. Then tap “Build number” seven times and you’re done. Now you
can just back out to the main Settings menu and you’ll find Developer
options somewhere near the bottom of the list.
==>Now that you’re done with that part, let the real fun begins. Tap the new Developer options menu you just enabled and scroll until you
see the following three settings (note that they may be located within
an “Advanced” subsection):
Window animation scale Transition animation scale Animator animation
scale
==>Did you see them? By default, each of those three options is set to “1x” but tapping them and changing them to “.5x” will dramatically
speed up your phone. This harmless tweak forces the device to speed up
all transition animations, and the entire user experience is faster
and smoother as a result
I'm mainly using mapbox in my projet, but in one instance, I need to display the map in the recyclerView. To do so, I thought of using MapSnapshotter instead of the static Map Api since the user may not have connection.
Unfortunately, when doing my testing, I can't get the MapSnapshotter.callback working properly. Sometime the image is loaded/created and other time it's not, and it does feel to be random.
Mapbox.getInstance(this, MyMapbox.getToken());
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(MapboxMap mapboxMap) {
map = mapboxMap;
MapSnapshotter.Options options = new MapSnapshotter.Options(mapView.getMeasuredWidth(),mapView.getMeasuredHeight());
options.withRegion(mapboxMap.getProjection().getVisibleRegion().latLngBounds);
options.withStyle(mapboxMap.getStyleUrl());
MapSnapshotter mapSnapshotter = new MapSnapshotter(getContext(), options);
mapSnapshotter.start(new MapSnapshotter.SnapshotReadyCallback() {
#Override
public void onSnapshotReady(MapSnapshot snapshot) {
Log.i(LOG_TAG, "onSnapshotReady");
Bitmap bitmap = snapshot.getBitmap();
imageview.setImageBitmap(bitmap);
}
}, new MapSnapshotter.ErrorHandler() {
#Override
public void onError(String error) {
Log.i(LOG_TAG, error);
}
});
}
});
So after some twisting, I finally figure it out. The issue, was that MapSnapshotter.start is a Async task and since the phone is loading 3 items in the recycler view when first launched and in turn, each one of the item is calling the MapSnapshotter.start in the same thread before the previous one is done, so canceling it. This explain why only the last item has is image loaded.
A way to solve this issue is to make the Async task become Sync, but I don't recommande this solution.
The others way is add a property MapSnapshotter in your Adapter. Doing so, each of yours items will have is own MapSnapshotter.
I have a big problem with loading images from cache on the getView of my Listadapter.
For image-loading we are using Picasso, and there I build a construct for loading images from cache and if there are no available images, THEN the images should be load from an online-URI.
(Here is a method, which is called inside of my getView of my Adapter)
#Override
protected void loadImages(final VehicleResultListItem inCurrentItem) {
// Try to load async the images from local path
Picasso.with(mContext)
.load(new File(mContext.getExternalFilesDir(null),
inCurrentItem.getVehicleId()))
.placeholder(inCurrentItem.getServiceType().getPlaceholderId())
.noFade()
.into(new Target() {
#Override
public void onBitmapLoaded(final Bitmap bitmap,
final Picasso.LoadedFrom from) {
mThumbnailImgView.setImageBitmap(bitmap);
}
#Override
public void onBitmapFailed(final Drawable errorDrawable) {
// If the local-path-loading fails, try to grab the images online.
Picasso.with(mContext)
.load(inCurrentItem.getImageURIs().get(0).getImageUriSizeM())
.placeholder(inCurrentItem.getServiceType().getPlaceholderId())
.into(new Target() {
#Override
public void onBitmapLoaded(final Bitmap bitmap,
final Picasso.LoadedFrom from) {
// On succesfully online-loading of the images, store and show them
mThumbnailImgView.setImageBitmap(bitmap);
saveToInternalSorage(bitmap, inCurrentItem);
}
#Override
public void onBitmapFailed(final Drawable errorDrawable) {
// NO interaction
}
#Override
public void onPrepareLoad(final Drawable placeHolderDrawable) {
// No interaction
}
});
}
#Override
public void onPrepareLoad(final Drawable placeHolderDrawable) {
mThumbnailImgView.setImageDrawable(placeHolderDrawable);
}
});
}
The problem is, that the image is loading correctly, but the imageView is not updating after image is loaded. In the OnImageLoaded, I am not in the UI-Thread, so ofc it does not update the view. So i tried anything:
Runnable
AsyncTask
Androids solution from (http://developer.android.com/training/displaying-bitmaps/process-bitmap.html#concurrency)
It looks like the Threads are getting confused or something like that.
Maybe there is a problem in calling Picasso inside of a Picasso-Target?
Do u have any suggestion?
Greetz and thx
Target must not be an anonymous class. Picasso keeps a WeakReference on Target that will most likely get gc'ed by the time the request completes.
Javadoc clearly states that.
Make your View implement Target instead and use that as the target or keep a reference to your target instances.
Also Picasso handles disk caching for you automatically, unless you've shipped the assets with your app, I would recommend you simply download them and then let Picasso manage the disk/memory cache for you.
I know, this question was asked maaany times, but I do not think there was a solution for this. I'm developing application which should be targeted for all devices with android system and backfacing camera. The problem is I can test application on only two devices and have to be sure that it works on all devices.I think only reasonable solution would be to to find a code samples for camera api that are quaranteed to work on nearly all devices. Does anybody can provide such sources ... but sources ... that really are tested on maaaaany (ALL) devices ? I've lost all hairs from my head ... and .. and I'm loosing my mind i think... It is all because I've released app (only for tests in my company) which was tested on only two devices, and which uses camera api in a way that should work, but it appears there are some phones like for example HTC desire HD or HTC Evo 3d (with 3d camera) where the app simply crashes (because of fu..ing camera) or freezes (also because of fu..ing camera). If there is someone who have sources for camera api (taking a picture without user gui interaction, periodically) which are really tested, please be so kind and if You can, post the source or redirect me to proper place.
Hmm maybe The question should sound like this: "Is it technically possible to use camera api on all devices ?"
Maybe I will describe how I'm currently using api.
1) Initialize cam:
public void initCam()
{
LoggingFacility.debug("Attempting to initialize camera",this);
LoggingFacility.debug("Preview is enabled:"+isPreview,this);
try {
if (camera==null)
{
camera = Camera.open();
camera.setPreviewDisplay(mHolder);
if (camera!=null)
{
Camera.Parameters parameters = camera.getParameters();
List<Size> sizes = parameters.getSupportedPictureSizes();
if (sizes!=null)
{
Size min = sizes.get(0);
for (Size size : sizes)
if (size.width<min.width) min = size;
{
parameters.setPictureSize(min.width, min.height);
}
}
camera.setParameters(parameters);
setDisplayOrientation(90);
}
}
startPreview(aps);
} catch (Throwable e){
if (exceptionsCallback!=null)
exceptionsCallback.onException(e);
}
}
2) Start preview:
private void startPreview(AfterPreviewStarted after)
{
try {
if (!isPreview)
{
LoggingFacility.debug("Starting preview",this);
//camera.stopPreview();
camera.startPreview();
isPreview = true;
LoggingFacility.debug("Preview is enabled:"+isPreview,this);
}
if (after!=null) after.doAfter();
}catch(Throwable e)
{
if (exceptionsCallback!=null)
exceptionsCallback.onException(e);
}
}
3) Take picture:
public void takePicture(final PictureCallback callback)
{
LoggingFacility.debug("Attempting to take a picture",this);
if (camera!=null)
{
if (isPreview)
{
try
{
LoggingFacility.debug("preview is enabled jut before taking picture",this);
//AudioManager mgr = (AudioManager)ctx.getSystemService(Context.AUDIO_SERVICE);
//mgr.setStreamMute(AudioManager.STREAM_SYSTEM, true);
LoggingFacility.debug("Taking picture... preview will be stopped...",this);
isPreview = false;
camera.takePicture(null, new PictureCallback(){
public void onPictureTaken(byte[] arg0, Camera arg1)
{
//LoggingFacility.debug("Picture has been taken - 1t callback",CameraPreview.this);
}
}, callback);
//mgr.setStreamMute(AudioManager.STREAM_SYSTEM, false);
} catch (Throwable e){
if (exceptionsCallback!=null)
exceptionsCallback.onException(e);
}
}
}
4) Release camera after done, or after surface is disposed.
public void releaseCam()
{
LoggingFacility.debug("Attempting to release camera",this);
if (camera!=null)
{
isTakingPictures = false;
camera.stopPreview();
isPreview = false;
camera.release();
camera = null;
LoggingFacility.debug("A camera connection has been released...",this);
}
}
In 3rd code snippet in callback method Im invoking startPreview again since after taking picture a preview is disabled, and some smartphones require preview to be started to make a picture. All above method are part of class extending SurfaceView and implementing SurfaceHolder.Callback and is a part of activity.
SurfaceHolder.Callback is implemented as follows:
public void surfaceCreated(SurfaceHolder holder) {
initCam();
}
public void surfaceDestroyed(SurfaceHolder holder) {
releaseCam();
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
}
Constructor of class
CameraPreview(Context context) {
super(context);
this.ctx = context;
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
I was also considering another approach - to overcome taking picture, and instead of this to register onPreviewFrame callback and for example in this callback check the flag if a picture has been requested, if so - convert image to bitmap and use it in further processing. I was trying this approach, but then stuck with another problem - even If I register empty callback, a gui responds much slower.
For everyone who like me have problems using android camera api please refer to this link . It seems the code from this sample works on majority of smartphones.
final int PICTURE_TAKEN = 1;
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(filename)));
startActivityForResult(intent, PICTURE_TAKEN);
This works for me, haven't had complaints sofar.