Glide loading same image given diferent urls in android recyclerview - Java - android-recyclerview

I have implemented glide very well but the problem is that it loads same image for different imageviews with different urls in recyclerview.
The main question is how can I load the required images and still keep local caching to save user data? Here is my code:
Glide.with(context).load(objects.get(position)).apply(new RequestOptions().fitCenter().error(R.drawable.logo).placeholder(R.drawable.logo).diskCacheStrategy(DiskCacheStrategy.ALL)).into(new SimpleTarget<Drawable>() {
#Override
public void onResourceReady(#NonNull Drawable resource, #Nullable Transition<? super Drawable> transition) {
imageView.setImageDrawable(resource);
progressBar.setVisibility(View.GONE);
}
});

Instead of doing something like this:
.into(new SimpleTarget<Drawable>() {
#Override
public void onResourceReady(#NonNull Drawable resource, #Nullable Transition<? super Drawable> transition) {
imageView.setImageDrawable(resource);
progressBar.setVisibility(View.GONE);
}
});
Just simply put into the into function your imageView. If you still want to be notified whenever loading has been done you can use listener function. Your code should look like this:
Glide
.with(context)
.load(objects.get(position))
.apply(new
RequestOptions()
.fitCenter()
.error(R.drawable.logo)
.placeholder(R.drawable.logo)
.diskCacheStrategy(DiskCacheStrategy.ALL)
)
.listener(new SimpleTarget<Drawable>() {
#Override
public void onResourceReady(#NonNull Drawable resource, #Nullable
Transition<? super Drawable> transition) {
progressBar.setVisibility(View.GONE);
}
})
.into(imageView);
Glide should handle the RecyclerView lifecycle by its own. The only thing that you need to do is to hide progress bar. You do not need to set the drawable into the ImageView by yourself.
UPDATE:
The mentioned approach is the best however it gives me some lint errors when using SimpleTarget<?>() inside .listener(), maybe be due to possible version difference and has forced me to use RequestListener<Drawable>() and it works:
Glide.with(holder.service_image.getContext()).load(imageArray.get(0)).apply(new RequestOptions().fitCenter().error(R.drawable.logo).placeholder(R.drawable.logo).diskCacheStrategy(DiskCacheStrategy.ALL)).listener(new RequestListener<Drawable>() {
#Override
public boolean onLoadFailed(#Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
return false;
}
#Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
holder.progressBar.setVisibility(View.GONE);
return false;
}
}).into( holder.service_image);

Related

Eclipse Plugin: How can I tell the plugin to open a new Editor every time instead of switching the focus to an existing Editor?

In my Plugin there is an action to open an Editor (extends EditorPart). When I try to open it a second time, its init method isn't called. Instead the focus is shifted to the editor that is already open.
The Editor is associated with a filetype. Here is the excerpt from the plugin.xml:
<extension point="org.eclipse.ui.editors">
<editor
class="de.blub.tool.ide.editors.GRASPEditor"
default="true"
extensions="grasp"
filenames="*.grasp"
icon="icons/newGraspFile.png"
id="de.blub.tool.ide.editors.GRASPEditor"
name="GRASP File Editor">
</editor>
</extension>
I have an Action to open a new Editor. When I try to click that Action twice it reuses the first Editor. I also tried to use an EditorMatcher that implements IEditorMatchingStrategy and always returns false in its matches() method. Even that doesn't change the behavior.
This seems to be a desired/default behavior in eclipse. How can I change that so that the user can initialize a new Editor each time?
Eclipse looks for the equals method of the IEditorInput instance. The Editor somewhere in its code (in my case in the doSave method) uses a setInput method like this:
#Override
public void init(IEditorSite site, IEditorInput input) throws PartInitException {
// Initialize the editor input
this.input = new MyInputClass(resource);
...
}
#Override
public void doSave(IProgressMonitor monitor) {
...
setInput(input);
}
MyInputClass is the class that extends IEditorInput. The logic for eclipse to reuse an Editor or create a new one is in its equals method. The following example checks the path of an IResource field:
public class MyInputClass implements IEditorInput {
private IResource resource;
public MyInputClass(IResource resource) {
this.resource = resource;
}
public IResource getResource() {
return resource;
}
public void setResource(IResource resource) {
this.resource = resource;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj instanceof MyEditorClass) {
MyEditorClass other = (MyEditorClass) obj;
if (getResource().getFullPath().equals(other.getResource().getFullPath())) {
return true;
}
}
return false;
}
}
Of course one can define another logic inside the equals method. Make sure to not create a chaos, which is very well possible, as greg-449 pointed out in a comment.

Scrollable Layout in Vaadin Flow

In Vaadin Flow, there exists no Component that is essentially a Scrollable Layout.
In Vaadin 8, this was done by the Panel.
Is there a way to achieve a scrollable Component in Vaadin Flow?
Edit: I have now published an add-on here that provides the class VerticalScrollLayout, and also the class HorizontalScrollLayout. If there are suggestions for improvements, feel free to contact me or comment here.
Yes it is possible, although there is no existing Component that does it automatically.
The way to go is placing a VerticalLayout (for a vertical scroll bar) inside another component, and setting the display property of that VerticalLayout from flex to block. (credits to Diego Sanz Villafruela in the vaadin forum)
I have made my own VerticalScrollLayout class that does it all for you, so that using it in a view is as easy as using a simple VerticalLayout
public class VerticalScrollLayout extends VerticalLayout {
private VerticalLayout content;
public VerticalScrollLayout(){
preparePanel();
}
public VerticalScrollLayout(Component... children){
preparePanel();
this.add(children);
}
private void preparePanel() {
setWidth("100%");
setHeight("100%");
getStyle().set("overflow", "auto");
content = new VerticalLayout();
content.getStyle().set("display", "block");
content.setWidth("100%");
content.setPadding(false);
super.add(content);
}
public VerticalLayout getContent(){
return content;
}
#Override
public void add(Component... components){
content.add(components);
}
#Override
public void remove(Component... components){
content.remove(components);
}
#Override
public void removeAll(){
content.removeAll();
}
#Override
public void addComponentAsFirst(Component component) {
content.addComponentAtIndex(0, component);
}
}
There is now an official component for scrolling:
https://vaadin.com/docs/latest/components/scroller

NullPointerException on Google Banner Ads

my app get crashing frequently due to NullPointerException and Native crash and thus I am losing my play store rank day by day. someone please help me on this.. is there any way if banner ad is not ready, can I show native ad (optional question)?
NullPointerException at: mAdView.loadAd(new AdRequest.Builder().build());
My app build version 26.0.1 and using Android Studio 3.0 Beta 2.
my code:
public class B1 extends Fragment {
public B1() {
// Required empty public constructor
}
private AdView mAdView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_b1, container, false);
//Banner
mAdView = rootView.findViewById(R.id.adView);
mAdView.loadAd(new AdRequest.Builder().build());
mAdView.setAdListener(new AdListener() {
#Override
public void onAdLoaded() {
mAdView.setVisibility(View.VISIBLE);
}
#Override
public void onAdFailedToLoad(int error) {
mAdView.setVisibility(View.GONE);
}
});
return rootView;
}
}
The banner is ready. Your findViewById is returning null. Make sure rootView actually contains the AdView R.id.adView

JavaFX, List to ObservableList to ListView

So my problem is, that I have an serilized ArrayList and have to update it in my GUI to show its content in a ListView dynamically.
The serialization and deserialization works fine with the use of a DAO interface but the GUI won't refresh my ListView.
This class holds my data interaction (mostly save, load...):
public class Medienverwaltung implements Serializable, IDAO{
private static final long serialVersionUID = 1L;
private List<Medium> medienliste;
public ObservableList<Medium> obList; //public for test-reasons
public Medienverwaltung(){
medienliste = new ArrayList<Medium>();
obList = FXCollections.observableArrayList(medienliste);
}
//[...]
public List<Medium> getMedienliste(){
return this.medienliste;
}
//[...]
}
Here comes my GUI implementation snippet:
public class HauptFenster extends Application{
private Medienverwaltung medienverwaltung;
#Override
public void start(Stage stage) throws Exception{
medienverwaltung = new Medienverwaltung();
VBox root = new VBox();
ListView<String> showliste = new ListView<String>();
MenuBar menuBar = createMenuBar(stage);
root.getChildren().add(menuBar);
root.getChildren().add(showliste);
//Make Listener and refresh the shown list!
medienverwaltung.obList.addListener(new ListChangeListener<Medium>(){
#Override
public void onChanged(ListChangeListener.Change<? extends Medium> change) {
showliste.getItems().clear();
for(Medium medium : medienverwaltung.obList){
//toString() is overwritten and works, too
showliste.getItems().add(medium.toString());
}
}
});
// this adds a Medium object to the Arraylist in Medienverwaltung
medienverwaltung.aufnehmen(new Bild("Foto12", 2017, "Zuhause"));
stage.setTitle("Medien Verwaltung");
stage.setScene(new Scene(root, 800, 400) );
stage.show();
}
//[...]
I also tired to exchange the whole ArrayList from the class "Medienverwaltung" with an ObservableList, so that there is only one List remaining, which works for the GUI but not for the serialization and deserialization as I guessed before. (and tried a few other implementations)
Does anyone have an idea how to change my code so that it works?
And my second question is, what is the best way in terms of a 3 layer architecture?
The following is a reference to Fabians Answer and responds to my comment on that
Update#1.1 (addendum for explanation)
public interface IDAO {
// Save method
void speichern(List<Medium> liste) throws PersistenzException;
// Load method
List<Medium> laden() throws PersistenzException;
}
Here comes my concrete save Method:
#Override
public void speichern(List<Medium> medienliste) throws PersistenzException{
File sfile = new File("medienliste.dat");
try(FileOutputStream fos = new FileOutputStream(sfile); ObjectOutputStream oos = new ObjectOutputStream(fos)){
oos.writeObject(medienliste);
System.out.println("Serialisierung erfolgreich!");
}catch(IOException e){
e.printStackTrace();
System.out.println("Serialisierung fehlgeschlagen!");
}
}
Update#1.2 (addendum for explanation)
//[...] section of my GUI for saving
MenuItem speichern = new MenuItem("Speichern");
speichern.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent e){
try{
//Before: medienverwaltung.speichern(medienverwaltung.getMedienliste()); -> doesn't work because of serializing an ObservableList
medienverwaltung.speichern(medienverwaltung.getBackingList());
}catch(PersistenzException pe){
pe.printStackTrace();
}
}
});
//[...]
But as I guess, it's not a fine way to access the backinlist this way.
Update#2:
to respect the principle of encapsulation in a clean way I now added an overloaded Method in the class Medienverwaltung:
public void speichern() throws PersistenzException{
speichern(backingList);
}
So my GUI now only calls speichern(). This actually calls the method for saving with the backedlist which is no more accessible from the outside. I hope this is no bad coding style ^^
BTW.: If you are reading this and have a similar problem, don't use ObservableArrayList for the synchronisation with a normal List, this won't work! Use ObservableList instead.
Hide the backing list (medienliste) from other classes by removing the getter. If you modify this list using the ObservableList the ListView (or every other object that has added a listener to the list) will properly update.
Furthermore unless Medium extends Node you can simply use this kind of object as items of the ListView, since the cells set the text to the result of the toString method called for the associated item by default.
public class Medienverwaltung implements Serializable, IDAO{
private static final long serialVersionUID = 1L;
private List<Medium> backingList;
// transient field not persisted
private transient ObservableList<Medium> medienliste;
public Medienverwaltung(){
backingList = new ArrayList<Medium>();
medienliste = FXCollections.observableArrayList(backingList);
}
// make sure an ObservableList is created when reading the serialized object
private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
inputStream.defaultReadObject();
medienliste = FXCollections.observableArrayList(backingList);
}
//[...]
public ObservableList<Medium> getMedienliste(){
return this.medienliste;
}
//[...]
}
#Override
public void start(Stage stage) throws Exception{
medienverwaltung = new Medienverwaltung();
VBox root = new VBox();
ListView<Medium> showliste = new ListView<>(medienverwaltung.getMedienliste());
MenuBar menuBar = createMenuBar(stage);
root.getChildren().add(menuBar);
root.getChildren().add(showliste);
// this adds a Medium object to the Arraylist in Medienverwaltung
medienverwaltung.aufnehmen(new Bild("Foto12", 2017, "Zuhause"));
stage.setTitle("Medien Verwaltung");
stage.setScene(new Scene(root, 800, 400) );
stage.show();
}
Note that the Medienverwaltung.aufnehmen method should not work directly with the backing list - it should use the ObservableList instead to make sure changes can be observed...
EDIT
Looking at the IDAO interface it should probably be a object different to Medienverwaltung, since otherwise you'd violate the seperation of concerns design principle; also it wouldn't make sense to pass a value as parameter that's already contained as property of the object itself.
It seems that the IDAO object should be responsible for reading/writing the list data only which would make implementing Serializable with Medienverwaltung unnecessary. Probably something like this is expected solution to your excercise:
IDAO idao = new IDAOImplementation();
Medienverwaltung medienverwaltung = new Medienverwaltung(idao.laden());
public void handle(ActionEvent e){
try{
idao.speichern(medienverwaltung.getMedienliste());
}catch(PersistenzException pe){
pe.printStackTrace();
}
}
public Medienverwaltung(List<Medium> medien) {
this.medienliste = FXCollections.observableArrayList(medien);
}
The IDAO implementation should most likely not depend on the implementation of the List and therefore not expect the List to be serializable. You can simply work around non-serialized lists by a) not using ObjectOutputStream to persist the data, but some other way not relying on serializable objects or b) simply copy the contents of the list to a serializable list:
#Override
public void speichern(List<Medium> medienliste) throws PersistenzException{
File sfile = new File("medienliste.dat");
try(FileOutputStream fos = new FileOutputStream(sfile); ObjectOutputStream oos = new ObjectOutputStream(fos)){
oos.writeObject(new ArrayList(medienliste));
System.out.println("Serialisierung erfolgreich!");
} catch(IOException e){
throw new PersistenzException(e);
}
}

JavaPsiScanner doesn't see calls

I'm working on a custom Lint check and can't get all the method calls I need.
What I need: access to every add() call in lines like this:
Builder.from(arg)
.add(arg1, arg2)
.add(arg1, arg2)
.add(arg1, arg2);
What I get: visitMethod is not called at all. In such lines it's only called for 'from()'.
Detector code sample:
public class ExampleDetector extends Detector implements Detector.JavaPsiScanner {
#Override
public List<String> getApplicableMethodNames() {
return Collections.singletonList("add");
}
#Override
public void visitMethod(JavaContext context, #Nullable JavaElementVisitor visitor,
#NonNull PsiMethodCallExpression call, #NonNull PsiMethod method) {
...
}
....
}
How can I solve it? Why is it not visited at all?