AdMob Banner in ListView als Item integrieren Problem

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • AdMob Banner in ListView als Item integrieren Problem

    Nabend!

    Ich hab vor ein paar Tagen in eine ListView mit einem CustomArrayAdapter AdMob Banner als Items eingefügt. Das Ganze funktionierte alles auch reibungslos. Nach einem kleinem Wasserschaden, kompletten zerlegtem Galaxy Note, ein wenig Alkohol und einer ROM, funktioniert das nun nicht mehr, wobei davon ausgehe, dass es Anfangs nur Glück war, dass es funktioniert hat....

    Java-Quellcode

    1. @Override
    2. public View getView(int position, View convertView, ViewGroup parent) {
    3. if((position % 4) == 0){
    4. if (convertView instanceof AdView && convertView != null) {
    5. // Don’t instantiate new AdView, reuse old one
    6. return convertView;
    7. }
    8. {
    9. // Create a new AdView
    10. AdView adView = new AdView(this.context, AdSize.BANNER,AD_ID);
    11. // Convert the default layout parameters so that they play nice with
    12. // ListView.
    13. float density = context.getResources().getDisplayMetrics().density;
    14. int height = Math.round(AdSize.BANNER.getHeight() * density);
    15. AbsListView.LayoutParams params = new AbsListView.LayoutParams(
    16. AbsListView.LayoutParams.FILL_PARENT,
    17. height);
    18. adView.setLayoutParams(params);
    19. adView.loadAd(new AdRequest());
    20. return adView;
    21. }
    22. }
    23. else{
    24. View row = getView(position, convertView, parent);
    25. NewsItemsHolder newsItemsHolder = null;
    26. if(row == null)
    27. {
    28. LayoutInflater inflater = ((Activity)context).getLayoutInflater();
    29. row = inflater.inflate(layoutResourceId, parent, false);
    30. newsItemsHolder = new NewsItemsHolder();
    31. newsItemsHolder.date = (TextView)row.findViewById(R.id.date);
    32. newsItemsHolder.title = (TextView)row.findViewById(R.id.title);
    33. newsItemsHolder.content = (TextView)row.findViewById(R.id.content);
    34. row.setTag(newsItemsHolder);
    35. }
    36. else
    37. {
    38. newsItemsHolder = (NewsItemsHolder)row.getTag();
    39. }
    40. NewsListRSSItems xmlItems = newsListData[position];
    41. newsItemsHolder.date.setText(xmlItems.date);
    42. newsItemsHolder.title.setText(xmlItems.title);
    43. newsItemsHolder.content.setText(xmlItems.content);
    44. return row;
    45. }
    46. }
    Alles anzeigen



    Bei diesem Code sollte nun an jeder fünften Stelle ein Banner erscheinen, was er auch tut. Aber, ich kann nun nicht mehr Scrollen, da die App mit einer NullPointerException crashed. Erwarte ich 8 ListItems, weil ich dementsprechend ein Array übergebe, so erhalte ich, bei (position % 2) nur noch 4 Items. Ich hatte darauf Anfangs nicht geachtet....

    Wie kann ich denn am besten innerhalb meines ArrayAdapters sagen, dass zb an jeder 10. Stelle ein Banner erscheinen soll, dafür aber kein ListItem einsparen? Daran wird es ja wohl liegen, dass die App beim Scrollen crashed....

    Den Code, um Banner als ListItem zu setzen habe ich von googleadsdeveloper.blogspot.de

    Dort holen die sich aber die View anstelle von normal convertView über

    Java-Quellcode

    1. getView(position - (int) Math.ceil(position / k) - 1, convertView, parent);



    was bei mir aber auch eine NullPointerException auswirft...

    Jemand eine Idee? Stehe mal wieder auf dem Schlauch....(Immer bei den scheinbar einfachsten Sachen...)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von 3ncrypt0 ()

  • Wenn dir Items fehlen, dann musst du natürlich auch die Anzahl in getCount() entsprechend erhöhen.

    Java-Quellcode

    1. int count = array.length;
    2. // Hier nutzen wir die Eigenheit, dass die Division durch einen int einen int zurückliefert.
    3. int bannerCount = count / 4;
    4. return count + bannerCount;


    So, nun zu deinen Abstürzen.
    Vermutlich hast du Obiges bereits bedacht, dann ist allerdings dein Code bezüglich der Abfrage der Items falsch.
    Es sollte zumindest eine OutOfBound Exception geschmissen werden. ;)

    Nehmen wir mal Position 19.
    Wir haben an Position 19 deines ListViews bereits 5 Werbebanner, nämlich für die Positionen 0, 4, 8, 12 und 16.
    Deine Position ist also locker um fünf Indices zu weit hinten. Während du sagst array[19] willst du eigentlich array[14]. Du kannst dir die Sache ja mal aufmalen. ;)

    Insofern wirst du die Indizes in Abhängigkeit der aktuellen Position ändern müssen.

    Anbei ein kleines Beispielprojekt, ganz simpel mit 'javac Rechnen.java' compilieren und mit 'java Rechnen' starten.

    Java-Quellcode

    1. import java.lang.Integer;
    2. import java.lang.Exception;
    3. public class Rechnen
    4. {
    5. public static void main(String[] args)
    6. {
    7. // Standardwert für die Werbepositionierung setzen, hier: jede vierte Zeile
    8. int bannerPosition = 4;
    9. // Eingabe lesen und in eine Zahl wandeln sofern möglich.
    10. try
    11. {
    12. bannerPosition = Integer.parseInt(args[0]);
    13. }
    14. // Wenn was schief geht darauf hinweisen und den Standardwert nutzen.
    15. catch(Exception e)
    16. {
    17. System.out.println("Parameter 1 konnte nicht gelesen werden, arbeite mit "+bannerPosition+" Zeilen.");
    18. }
    19. // Um Endlosschleifen zu vermeiden sollte die Bannerposition größer 1 sein.
    20. if(bannerPosition <= 1)
    21. {
    22. bannerPosition = 2;
    23. }
    24. // Standardwert für die Durchläufe setzen, hier: 50
    25. // (Gleichbedeutend für die eigentliche Anzahl der Elemente beispielsweise in einem Array)
    26. int numberOfRuns = 50;
    27. // Wieder die Eingabe lesen und sofern möglich in eine Zahl umwandeln
    28. try
    29. {
    30. numberOfRuns = Integer.parseInt(args[1]);
    31. }
    32. // Beziehungsweise Info geben und Standardwert nutzen, wenn es nicht möglich war.
    33. catch(Exception e)
    34. {
    35. System.out.println("Parameter 2 konnte nicht gelesen werden, arbeite mit "+numberOfRuns+" Durchläufen.");
    36. }
    37. // Anzahl der gezeigten Banner speichern.
    38. int bannerAmount = 0;
    39. // Und alle Elemente durcharbeiten.
    40. for(int position = 0; position < (numberOfRuns+bannerAmount); position++)
    41. {
    42. // Wir zeigen einen Banner
    43. if(position % bannerPosition == 0)
    44. {
    45. // und erhöhen die Anzahl der gezeigten Banner und erhöhen damit auch die Anzahl der Schleifendurchläufe
    46. bannerAmount++;
    47. System.out.println(position+"\t| WERBEEINBLENDUNG |");
    48. }
    49. // Wir zeigen einen Eintrag.
    50. else
    51. {
    52. // Natürlich müssen wir schauen, dass wir die richtigen Indices unabhängig der Position zeigen.
    53. int numberOfBanners = (position / bannerPosition)+1;
    54. System.out.println(position+"\t: "+(position-numberOfBanners));
    55. }
    56. }
    57. // Ende Gelände, Aus die Maus, hier kommt nix mehr.
    58. }
    59. }
    Alles anzeigen

    Ich denke, ich sollte alle Problemfälle abgefangen haben, die sich bei diesen doch sehr begrenzten Eingabemöglichkeiten bieten. ^^

    (Nein, mir ist keine superdupertolle mathematische Formel eingefallen, mit der man ausrechnen kann, wie viele Elemente angezeigt werden müssen.
    Vielleicht via numberOfRuns+Math.ceil(numberOfRuns/(bannerPosition-1)) oder so. +schulter zuck+)
    Je mehr Käse, desto mehr Löcher.
    Je mehr Löcher, desto weniger Käse.
    Daraus folgt: je mehr Käse, desto weniger Käse.

    »Dies ist ein Forum. Schreibt Eure Fragen in das Forum, nicht per PN!«
  • Servus,

    ja das ist richtig...ich habe ersteinmal dafür gesorgt, dass meine Klasse von BaseAdapter erbt anstelle von ArrayList<t> damit ich auch auf die getCount() zugreifen kann.

    Das Problem tritt, so wie ich es sehe, immer bei der Abfrage

    Java-Quellcode

    1. if(row == null){
    2. LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    3. row = inflater.inflate(layoutResourceId, parent, false);
    4. newsItemsHolder = new NewsItemsHolder();
    5. newsItemsHolder.date = (TextView)row.findViewById(R.id.date);
    6. newsItemsHolder.title = (TextView)row.findViewById(R.id.title);
    7. newsItemsHolder.content = (TextView)row.findViewById(R.id.content);
    8. row.setTag(newsItemsHolder);
    9. }
    10. else{
    11. //HIER DERFEHLER
    12. newsItemsHolder = (NewsItemsHolder)row.getTag();
    13. }
    Alles anzeigen


    auf. Wenn ich die Abfrage if(row == null) entferne, geht es, dann allerdings erzeugt er ja immer die Row neu, anstatt eine fertige schon zu nehmen.

    Die korrekte Anzahl der Items zzgl. der Banner habe ich mit Deiner Hilfe nun umgesetzt. Ich bin mir nicht ganz sicher, aber ich glaube, dass die in dem Bsp. von dem Blog einen extra BaseAdapter für die Anzeigen verwendet haben, die ja mittels

    Java-Quellcode

    1. return delegate.getView(position - (int) Math.ceil(position / k) - 1,
    2. convertView, parent);


    sich die nichtBanner holen. Das delegate wird dann wohl deren BaseAdapter sein, wo die die Daten für die normalen Items aufbauen. Ich habe das auch versucht, aber bei mir geht es nicht.

    Habe einen BannerAdapter aufgesetzt, mit dem Code aus dem Bsp. In meiner Activty eine Instanz beider Adapter erzeugt und versucht, die Instanz meines DatenAdapters in den BannerAdapter beim instanziieren zu übergeben, bekomme aber den Fehler, dass das nicht erwartet wird...warum auch immer. Leider findet man da keine kompletten Bsp. Scheinbar ist es zu einfach, als das man es erklären müsste aber ICH hänge da schon wieder...."macht langsam keine Spass mehr :D"
  • Also 'bei mir geht es nicht' ist immer eine unzureichende Beschreibung. ;)

    Deine Worte verwirren mich.
    Du bekommst du eine NullPointerException, wenn explizit der Zweig der If-Abfrage angesprungen wird, in dem 'row' niemals nicht null sein kann?
    Das kann nicht sein. Darf es zumindest nicht. Diese Art des ViewHolderPatterns habe ich schon so unendlich oft erfolgreich benutzt...
    Je mehr Käse, desto mehr Löcher.
    Je mehr Löcher, desto weniger Käse.
    Daraus folgt: je mehr Käse, desto weniger Käse.

    »Dies ist ein Forum. Schreibt Eure Fragen in das Forum, nicht per PN!«
  • Guten morgen!

    @Lucas de Vil: Sorry, ich hatte das Thema erst einmal zur Seite geschoben und nicht gesehen, dass Du noch etwas geschrieben hast.

    So, nun will ich aber endlich das Problem lösen. Bisher habe ich ja versucht, alles in einem CustomBaseAdapter zu lösen. Das gestaltet sich aber mehr als schwierig, wenn man allein schon bedenkt, wie man später an die richtigen ListItems kommt über onItemClickListener();

    In dem Beispiel aus dem Blogbeitrag übergeben die ja in dem Konstruktor eine BaseAdapter Instanz. Leider ist nirgends wirklich beschrieben,wie genau das geschehen soll. (Oder ich habe einfach Tomaten auf den Augen...)

    Ich habe nun einfach mal ein Testprojekt angelegt. Zwei CustomBaseAdapter. Im ersten Baseadapter (nachfolgend als WeahterAdapter genannt) verarbeite ich die Daten aus einem Array mit meinen normalen Items.

    Diesen WeahterAdapter übergebe ich dann an den AdmobAdapter. In dem AdmobAdapter mache ich alles genau so, wie in dem Bsp.

    Java-Quellcode

    1. return delegate.getView(position - (int) Math.ceil(position / k) - 1, convertView, parent);



    Wenn ich versuche in dem AdmobAdapter mir eine View aus dem WeatherAdapter zu holen, crashed die app...

    Hier mal ein Logauszug, wobei ich denke, ich mache schon etwas Grundlegendes falsch:

    Quellcode

    1. 05-07 10:10:02.491: E/AndroidRuntime(24393): FATAL EXCEPTION: main
    2. 05-07 10:10:02.491: E/AndroidRuntime(24393): java.lang.NullPointerException
    3. 05-07 10:10:02.491: E/AndroidRuntime(24393): at com.example.androidwithinlistview.WeatherAdapter.getView(WeatherAdapter.java:44)
    4. 05-07 10:10:02.491: E/AndroidRuntime(24393): at com.example.androidwithinlistview.ListViewExampleListAdapter.getView(ListViewExampleListAdapter.java:53)
    5. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.widget.AbsListView.obtainView(AbsListView.java:2143)
    6. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.widget.ListView.measureHeightOfChildren(ListView.java:1246)
    7. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.widget.ListView.onMeasure(ListView.java:1158)
    8. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.View.measure(View.java:15518)
    9. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4825)
    10. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1404)
    11. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.widget.LinearLayout.measureVertical(LinearLayout.java:695)
    12. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.widget.LinearLayout.onMeasure(LinearLayout.java:588)
    13. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.View.measure(View.java:15518)
    14. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4825)
    15. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
    16. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.View.measure(View.java:15518)
    17. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.widget.LinearLayout.measureVertical(LinearLayout.java:847)
    18. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.widget.LinearLayout.onMeasure(LinearLayout.java:588)
    19. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.View.measure(View.java:15518)
    20. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4825)
    21. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
    22. 05-07 10:10:02.491: E/AndroidRuntime(24393): at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2434)
    23. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.View.measure(View.java:15518)
    24. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:1874)
    25. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1089)
    26. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1265)
    27. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:989)
    28. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4351)
    29. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
    30. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.Choreographer.doCallbacks(Choreographer.java:562)
    31. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.Choreographer.doFrame(Choreographer.java:532)
    32. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
    33. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.os.Handler.handleCallback(Handler.java:725)
    34. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.os.Handler.dispatchMessage(Handler.java:92)
    35. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.os.Looper.loop(Looper.java:137)
    36. 05-07 10:10:02.491: E/AndroidRuntime(24393): at android.app.ActivityThread.main(ActivityThread.java:5233)
    37. 05-07 10:10:02.491: E/AndroidRuntime(24393): at java.lang.reflect.Method.invokeNative(Native Method)
    38. 05-07 10:10:02.491: E/AndroidRuntime(24393): at java.lang.reflect.Method.invoke(Method.java:511)
    39. 05-07 10:10:02.491: E/AndroidRuntime(24393): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
    40. 05-07 10:10:02.491: E/AndroidRuntime(24393): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562)
    41. 05-07 10:10:02.491: E/AndroidRuntime(24393): at dalvik.system.NativeStart.main(Native Method)
    Alles anzeigen



    Laut LogCat gibt er den ersten Banner auch aus bzw. lädt diesen. Nur crashed die App eben wenn ich versuche eine View aus dem anderen BaseAdapter zu bekommen.
  • In Zeile 44 der WeatherAdapter.java (innerhalb der Methode getView(...)) greifst du auf ein Objekt zu, dass nicht initialisiert wurde, also null ist.
    Steht doch da. ;)
    Je mehr Käse, desto mehr Löcher.
    Je mehr Löcher, desto weniger Käse.
    Daraus folgt: je mehr Käse, desto weniger Käse.

    »Dies ist ein Forum. Schreibt Eure Fragen in das Forum, nicht per PN!«

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Lucas de Vil ()

  • Ein Wunder ist geschehen :D

    Mein einziges Problem lag darin, dass ich in dem WeatherAdapter abfrage:

    Quellcode

    1. if(row == null)



    Wenn das zweite Banner ausgegeben wurde, ist das nachfolgende RowItem aber nicht null, sondern eine Instance einer AdView...

    mit

    Quellcode

    1. if(row == null || row instaceof AdView)



    Kann ich die Row neu instanziieren und auch auf diese Zugreifen und einen Wert aus meinem Array hinzufügen.

    Dadurch, dass ich zwei Adapter verwende, brauche ich mir keine Gedanken mehr machen beim Abfragen des ListItemIndex in der setOnItemClickListener und es gibt beim scrollen kein Problem...super!

    Nochmal besten Dank an Lucas de Vil, ohne Deine Hilfe hätte ich wohl noch Jahre gebraucht :D

    DANKE!

    Grüße