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.
Related
I am using FirestoreRecyclerAdapter to make a chat app in java. When adding a message it works fine but I want messages to show at bottom not on top. I tried
layoutManager.setReverseLayout(true);
layoutManager.setStackFromEnd(true);
Now it reverse it's position which is good but it's not automatically scrolling to bottom position. And when I add a new message I need to scroll manually to see it.
Recyclerview automatically scroll to bottom after adding below lines
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
recyclerView.smoothScrollToPosition(0);
}
});
}
}, 1000);
above solution will not work if parent layout is horizontal scroll.
Other solution is
recyclerView.scrollToPosition(0);
Both line of code work for me. you can use any of the solution
The best way to do it is use the following piece snippet whenever there is a new message. You can use a snapshot listener for that
y = (Here you need to try 2 things. My coding laptop is not with me so I cannot test and tell but either 0 should work or the chatlist.size()-1);
layoutManager.scrollToPosition(y);
OR
layoutManager.smoothScrollToPosition(y);// I do not recommend this for chat apps since it will take time to go down if there are a lot of texts below the user
This is what I used:
#Override
public void onStart() {
super.onStart ();
adapter.startListening();
recyclerView.scrollToPosition (0);
}
Also use
#Override
public void onDataChanged() {
super.onDataChanged ();
recyclerView1.smoothScrollToPosition (0);
}
in adapter
I was using
recyclerView.scrollToPosition (0);
in onCreate and adapter was starting in onStart. Now it's working
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.
I'm trying to load image and name from Firebase database to my app in RecyclerView but when I run it it is not showing the image and name with no error, here is my code.
//Load menu
recycler_menu=(RecyclerView)findViewById(R.id.recycler_menu);
recycler_menu.setHasFixedSize(true);
layoutManager= new LinearLayoutManager(this);
recycler_menu.setLayoutManager(layoutManager);
loadMenu();
}
private void loadMenu(){
FirebaseRecyclerOptions<Category> options = new FirebaseRecyclerOptions.Builder<Category>().setQuery(category, Category.class).build();
FirebaseRecyclerAdapter<Category, MenuViewHolder> adapter= new FirebaseRecyclerAdapter<Category, MenuViewHolder>(options){
#Override
public MenuViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.menu_item, parent, false);
MenuViewHolder viewHolder = new MenuViewHolder(view);
return viewHolder;
}
#Override
protected void onBindViewHolder(MenuViewHolder holder, int position, Category model) {
holder.txtMenuName.setText(model.getName());
Picasso.with(getBaseContext()).load(model.getImage()).into(holder.imageView);
}
};
recycler_menu.setAdapter(adapter);
}
My code is running fine but image and name is not showing, blank activity is displaying. Please help.
Just add adapter.startListening() in your OnStart to start the data listener and adapter.stopListening() in your onStop to stop it by this way :
#Override
protected void onStart() {
super.onStart();
adapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
adapter.stopListening();
}
This is one of the main problems you usually face when you are using Firebase as your database. I could not see where you retrieve your data but the problem is, most probably, Firebase event listeners working asynchronous. In another way, your method returns before you retrieve the data. In my project, I solved this issue by retrieving data on onCreateView or onCreate and then use those values inside other methods. If it is not the case I just simply do the work inside the event listener, if I have to (It will make your code look extremely complicated and unreadable). It would be more helpful if you do more research about Firebase and its asynchronous working style.
If you somehow find a better way to solve this, please comment below so I can use it too. I am still seeking a better way.
When returning to an activity using the back button and
startActivity(new Intent(this, ActivityMainMenu.class));
is called, are there any methods that automatically go to a custom view?
I've noticed that when going back to the view, it's no longer invalidated.
Basically without using the activity's onResume I want to be able to resume my custom view.
For anyone else who wants to know you can use:
protected void onAttachedToWindow()
It's called every time a view is attached to the Window.
In the Android Source for TextView, it posts a Runnable.
if (ss.error != null) {
final CharSequence error = ss.error;
// Display the error later, after the first layout pass
post(new Runnable() {
public void run() {
setError(error);
}
});
}
I would like to create a CustomEventBanner but have some questions. Im not sure if I do the right things at the right place. Where should I add the Banner to my layout? Do I have to call every method of the CustomEventBannerListener? Which are those which are absolutly necessary? How do I know if there is no Ad to display (no anouncer)??
I actually can display Ad with admob but not using my CustomAd :(
Here is my code:
public class CustomAd implements CustomEventBanner, AdResponseHandler {
private CustomEventBannerListener bannerListener;
protected SASBannerView mBannerView;
#Override
public void requestBannerAd(final CustomEventBannerListener listener,
final Activity activity, String label, String serverParameter,
AdSize adSize, MediationAdRequest mediationAdRequest, Object extra) {
// Keep the custom event listener for use later.
this.bannerListener = listener;
// Determine the best ad format to use given the adSize. If the adSize
// isn't appropriate for any format, an ad will not fill.
// Create banner instance
mBannerView = new SASBannerView(activity);
// Set the listener to register for events.
this.mBannerView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
listener.onClick();
} catch (Throwable t) {
}
}
});
// Load the ad with the ad request giving an AdResponseHandler
mBannerView.loadAd(42295, "286177", 18008, true, "", this);
}
#Override
public void destroy() { // The destroy method gets called when the mediation
// framework refreshes
// and removes the custom event. Perform any necessary cleanup here.
if (this.mBannerView != null) {
this.mBannerView.onDestroy();
}
}
#Override
public void adLoadingCompleted(SASAdElement arg0) {
this.bannerListener.onReceivedAd(this.mBannerView);
}
#Override
public void adLoadingFailed(Exception arg0) {
this.bannerListener.onFailedToReceiveAd();
}
}
The code looks pretty good. Though your banner doesn't seem to be doing anything on click other than notifying onClick(). If you're banner ends up hitting an external web browser or the play store, you can also call onPresentScreen() and onLeaveApplication() in the onClickListener.
Note that this is just the Custom Event component of your app to implement the SAS network. Your main activity still needs to create an AdView (with a mediation ID set up to target your custom event) and load an ad into it.
Only the onReceivedAd and onFailedToReceiveAd are absolutely necessary for mediation to run. The others are useful so that your main AdView's AdListener can listen for these events.