2010-12-07 9 views
5

Mein Code ist grundsätzlich frei Zuteilung, aber der GC läuft alle 30 Sekunden oder so bei 60fps. Wenn Sie die App mit DDMS für die Zuweisung überprüfen, wird ALOT SimpleListIterator zugewiesen. Es gibt auch einige Sachen, die zugeteilt werden, weil ich Exchanger verwende.Zuteilung kostenloses Spiel

Der SimpleListIterator kommt für jede Schleife for (T obj : objs) {}. Ich hatte den Eindruck, dass der Compiler/Übersetzer diejenigen optimieren würde, die keine Iteratoren für Typen verwenden, die ihn unterstützen (ich benutze grundsätzlich nur ArrayList), aber das scheint nicht der Fall zu sein.

Wie kann ich die Zuweisung all dieser SimpleListIterators vermeiden? Eine Lösung wäre, regelmäßig zu wechseln für Schleifen for (int i = 0; i < size; ++i) {} aber Ich mag für jeden Schleifen :(

Ein anderer Weg wäre Arraylist zu verlängern, die eine Iterator zurückgibt, die nur einmal vergeben wird.

Eine dritte Art, wie ich zusammen gehackt eine statische Hilfsfunktion verwendet, die ein Collection gibt, die ein Iterator ist die Wiederverwendung ich so etwas wie diese zusammen gehackt aber das Gießen fühlt sich sehr hackish und unsicher Es sollte jedoch Thread-sicher sein, wie ich ThreadLocal verwenden Siehe unten:..?

public class FastIterator { 
    private static ThreadLocal<Holder> holders = new ThreadLocal<Holder>(); 

    public static <T> Iterable<T> get(ArrayList<T> list) { 
     Holder cont = holders.get(); 

     if (cont == null) { 
      cont = new Holder(); 

      cont.collection = new DummyCollection<T>(); 
      cont.it = new Iterator<T>(); 

      holders.set(cont); 
     } 

     Iterator<T> it = (Iterator<T>) cont.it; 
     DummyCollection<T> collection = (DummyCollection<T>) cont.collection; 

     it.setList(list); 
     collection.setIterator(it); 

     return collection; 
    } 

    private FastIterator() {} 

    private static class Holder { 
     public DummyCollection<?> collection; 
     public Iterator<?> it; 
    } 

    private static class DummyCollection<T> implements Iterable { 
     private Iterator<?> it; 

     @Override 
     public java.util.Iterator<T> iterator() { 
      return (java.util.Iterator<T>) it; 
     } 

     public void setIterator(Iterator<?> it) { 
      this.it = it; 
     } 
    } 

    private static class Iterator<T> implements java.util.Iterator<T> { 
     private ArrayList<T> list; 
     private int size; 
     private int i; 

     @Override 
     public boolean hasNext() { 
      return i < size; 
     } 

     @Override 
     public T next() { 
      return list.get(i++); 
     } 

     @Override 
     public void remove() { 

     } 

     public void setList(ArrayList<T> list) { 
      this.list = list; 
      size = list.size(); 
      i = 0; 
     } 

     private Iterator() {} 
    } 
} 
+1

Uh, also, wenn ich Sie richtig verstehe, Hacker Iteratoren ist besser als die eine zusätzliche Zeile benötigt, um den Wert in einer 'for' Schleife zu bekommen? ... –

+0

Punkt genommen. Ratet mal ich sollte nur beissen und für jede Loops abgraben? :( – alexanderblom

+0

Ich habe die "extend ArrayList, die eine Iterator, die nur einmal" Version zurückgegeben zurückgegeben. Eine Sache zu beachten (mit allen Iteration Stile, die Sie erwähnen) ist verschachtelte Iteration. In meiner Version fügte ich eine explizite " release "-Methode und könnte überprüfen, dass der Iterator nicht bereits in Verwendung war ... einen fiesen Fehler auf diese Weise. Ein weiterer Hinweis: Es ist legal, Iterator.remove eine UnsupportedOperationException zu werfen. – Darrell

Antwort

4

Sie sollten nicht für jedes in Android-Spielen verwenden. Ich denke, das official video spricht darüber auch.

+0

Ich habe beschlossen, nur alle Schleifen in reguläre for-Schleifen zu konvertieren. – alexanderblom

2

Wahrscheinlich wäre der beste Ansatz, ein Dekorator-Design zu verwenden. Erstellen Sie eine Klasse, die eine Auflistung im Konstruktor übernimmt und die Iterable-Schnittstelle implementiert, indem Sie die Wrapped-Klasse aufrufen und den zurückgegebenen Iterator erneut verwenden.

+1

Ich glaube, das Herz dieses Vorschlags ist auch eine reset() -Methode, die den Iterator an den Anfang zurückgibt. –

0

Zwei zusätzliche Ansätze, um die Zuweisung von Iteratoren zu vermeiden. Zunächst ist ein Callback-Idiom zu verwenden:

public interface Handler<T> { 
    void handle(T element); 
} 

public interface Handleable<T> { 
    void handleAll(Handler<T> handler); 
} 

public class HandleableList<T> extends ArrayList<T> implements Handleable<T> { 
    public void handleAll(Handler<T> handler) { 
    for (int i = 0; i < size(); ++i) { 
     handler.handle(get(i)); 
    } 
    } 
} 

Dieser Ansatz noch eine Instanz eines Handler erfordert den Rückruf zu erhalten, aber dies kann auf jeden Fall Zuweisungen reduzieren, wenn zum Beispiel Sie versuchen, die Elemente von mehrer zu besuchen Listen.

Zweiter Ansatz ist es, ein Cursor Idiom zu verwenden:

public interface Cursor<T> { 
    void reset(); 
    boolean next(); 
    T current(); 
} 

public class CursoredList<T> extends ArrayList<T> implements Cursor<T> { 
    private int _index = -1; 

    public void reset() { 
    _index = -1; 
    } 

    public boolean next() { 
    return ++_index >= size(); 
    } 

    public T current() { 
    return get(_index); 
    } 
} 

Sicher, das ist der gleiche wie Iterable und Iterator auf dem Subtyp der Arraylist der Umsetzung, aber dies zeigt deutlich die Cursorposition als Zustand auf der Sammlung selbst .

Verwandte Themen