# Bild aus dem Internet in View bzw. ImageView laden (Fragment)



## wer112 (28. Apr 2021)

Ich programmiere erneut an eine neue App. Um den User den Spaß nicht zu verderben, möchte ich Bilder(300 - 2000 Stück) aus dem Interent in einem View anzeigen lassen. Wenn ich die ganzen Bilder in die App packe, dann braucht ja die App paar GB an Speicherplatz.

Ich möchte, dass es im View angezeigt wird. Wenn das unnmöglich ist, dann werde ich die Views in ImageViews umwandeln wollen.
Am besten, wie das mit der Aktuelle Flasche....

Das was ich im Internet gefunden habe, hat nicht funktioniert. Wenn dieser Schritt kommt(aktuelleFlasche.setImageDrawable(view1); Siehe Code. Habe es zurzeit als Kommentar gemacht....), dann stürtzt die App ab.

Ich suche ein Code, der aus dem Internet ein bestimmtes Bild holt und als ImageRessource bzw. ImageDrawable anzeigt.

Hier der Code:



[CODE lang="java" highlight="96"]package ..........................................;

import android.graphics.drawable.Drawable;
import android.media.Image;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

public class FlaschenFragment  extends Fragment {

    ImageView aktuell_view;
    View  view1, view2, view3, view4, view5, view6, view7, view8, view9, view10;


    int flaschenauswahlnummer = 1;

    int view_1 = 0;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        View fragmentlayout_FlaschenFragment = inflater.inflate(R.layout.fragment_flaschen, null);

        aktuell_view = (ImageView)fragmentlayout_FlaschenFragment.findViewById(R.id.aktuelle_flasche_view);

        aktuelleFlascheCheck();
        BildImport();



        view1 = (View)fragmentlayout_FlaschenFragment.findViewById(R.id.flasche_view_1);
        view1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (view_1 == 1){
                    aktuell_view.setImageResource(R.drawable.coin);
                }
            }
        });



        view2 = (View)fragmentlayout_FlaschenFragment.findViewById(R.id.flasche_view_2);
        view3 = (View)fragmentlayout_FlaschenFragment.findViewById(R.id.flasche_view_3);
        view4 = (View)fragmentlayout_FlaschenFragment.findViewById(R.id.flasche_view_4);
        view5 = (View)fragmentlayout_FlaschenFragment.findViewById(R.id.flasche_view_5);
        view6 = (View)fragmentlayout_FlaschenFragment.findViewById(R.id.flasche_view_6);
        view7 = (View)fragmentlayout_FlaschenFragment.findViewById(R.id.flasche_view_7);
        view8 = (View)fragmentlayout_FlaschenFragment.findViewById(R.id.flasche_view_8);
        view9 = (View)fragmentlayout_FlaschenFragment.findViewById(R.id.flasche_view_9);
        view10 = (View)fragmentlayout_FlaschenFragment.findViewById(R.id.flasche_view_10);

        return fragmentlayout_FlaschenFragment;
    }

    private void BildImport() {
        Thread thread = new Thread(new ThreadImport());
        thread.start();

    }

    class ThreadImport implements Runnable{
        @Override
        public void run() {


            Drawable dView1 = null, dView2, dView3, dView4, dView5, dView6, dView7, dView8, dView9, dView10 = null;

            try {
                URL url1 = new URL("https://firebasestorage.googleapis.com/v0/b/flaschen-drehen.appspot.com/o/flasche2.png?alt=media&token=a9b6944c-434f-4304-a26b-c6157cd6efc4");

                InputStream is1 = (InputStream) url1.getContent();
                dView1 = Drawable.createFromStream(is1, "src");


            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

      /*      aktuell_view.setImageDrawable(dView1);*/
        }
    }



    private void aktuelleFlascheCheck() {

        switch (flaschenauswahlnummer){
            case 1:

              /*  aktuell_view.setBackgroundResource(R.drawable.gesperrt_style);*/
                aktuell_view.setImageResource(R.drawable.bierflasche);


                break;

            case 2:

                break;

            case 3:

                break;

            case 4:

                break;

            case 5:

                break;

            case 6:

                break;

            case 7:

                break;

            case 8:

                break;

            case 9:

                break;

            case 10:

                break;


        }
    }




}
[/CODE]


----------



## Robertop (1. Jun 2021)

Hallo wer112. Ohne jetzt einen StackTrace zu haben würde ich Sagen, dass die App bei der Zeile *aktuell_view.setImageDrawable(dView1); *abstürzt, weil du sie in deinem ThreadImport aufrufst.

Auf die UI kann kan nur im UI-Thread zugreifen. Ich habe das jetzt aus dem Kopf getippt, aber so, oder zumindest so ähnlich, sollte es funktionieren:
Die Funktion kommt direkt in das Fragment und dein Aufruf im Thread wird zu *setAktuellmage(dView1)*.


```
private void setAktuellImage(final Drawable drawable) {
    getActivity().runOnUiThread(new Runnable() {
        @Override
        public void run() {
            aktuell_view.setImageDrawable(drawable);
        }
    });
```


----------



## kneitzel (1. Jun 2021)

Ich möchte an dieser Stelle einfach einmal kurz auf die Möglichkeit von Lambda Expressions und Methoden Referenzen hinweisen, da diese es ermöglichen, kürzeren und besser lesbaren Code zu erstellen. (Und diese sind relativ unkompliziert, so dass diese auch sehr früh angewendet werden können.)

Lambda-Ausdrücken kann man nutzen, wenn man noch einen Parameter mitgeben muss. Also in dem Beispiel wurde noch ein drawable mit übergeben:

```
private void setAktuellImage(final Drawable drawable) {
    getActivity().runOnUiThread(() -> aktuell_view.setImageDrawable(drawable));
}
```

So wird es doch deutlich kürzer und ich finde auch übersichtlicher.

Direkt beim TE hat man das nicht - da kann man dann direkt eine Methodenreferenz angeben. Also aus sowas:

```
view1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (view_1 == 1){
                    aktuell_view.setImageResource(R.drawable.coin);
                }
            }
        });
```

kann man dann zu sowas machen:

```
view1.setOnClickListener(this::einSinnvollerMethodenName);

// Dann an anderer Stelle in der Klasse die Methode:
    public void einSinnvollerMethodenName(View v) {
        if (view_1 == 1) {
            aktuell_view.setImageResource(R.drawable.coin);
        }
    }
```

Als Lambda Ausdruck wäre es dann übrigens etwas wie:


```
view1.setOnClickListener(v -> einSinnvollerMethodenName(v));

// Dann an anderer Stelle in der Klasse die Methode:
    public void einSinnvollerMethodenName(View v) {
        if (view_1 == 1) {
            aktuell_view.setImageResource(R.drawable.coin);
        }
    }
```

Das hat den Vorteil, dass man da einen sinnvollen Namen hat, der beschreibt, was die Methode macht und dann kann man direkt lesen a.la.:
quitButton.setOnClickListener(this::quitApplicationAction);

Da liest man dann genau: der quit Button soll die quitApplication Aktion starten. (Über das Naming kann man sich gerne streiten. Ich habe da gerne in meinem Controller Action Methoden, die dann von der View angesteuert werden können. Aber bezüglich Naming soll sich jeder das überlegen, was er für gut findet.
Der Verzicht auf entsprechende anonyme Klassen macht den Code kürzer und aus meiner Sicht deutlich besser lesbar (weil halt ein klarer Bezeichner angibt, was getan wird).


----------

