2017-11-03 5 views
0

Ich habe eine Aktivität, die eine scrollbare Liste (sagen wir eine Spalte) von programmatisch erstellten Schaltflächen aus einer Liste, die das Ergebnis einer SQLite Tabelle gelesen wird und mein Problem ist, dass die Liste wächst (und so die Anzahl der Tasten) das erste Mal auf dem Bildschirm wird langsam (im Moment dauert 3 Sekunden mit 50 Tasten zu zeichnen), also suche ich nach einer Lösung für diese.Beschleunigen große Reihe von programmatisch erstellten Schaltflächen anzuzeigen

Zuerst dachte ich über die Verwendung eines Threads (Runnable, Handler oder was auch immer), sagen wir einen neuen Thread innerhalb der For erstellen, die über die Liste iteriert, aber es funktioniert nicht (oder zumindest nicht um es zum arbeiten zu bringen) so ist meine Frage die nächste:

Ausgehend von einer Liste <> das ist die am besten geeignete Möglichkeit, eine große Reihe von Bildlaufschaltflächen zu erstellen, so Benutzer nicht solche Verzögerung beim Zugriff auf den Bildschirm.

Paginieren könnte eine Option sein, aber ich möchte zuerst über andere Möglichkeiten wissen und diese als letzte Ressource verlassen.

Danke, und unten ist mein Code.

public static void createButtons(LinearLayout llContainer, 
            List<TestType> TestTypes, List<Test> Tests, 
            int buttonFontSize) { 

     Context oContext = llContainer.getContext(); 
     String strTheme = TMAppearance.getThemeFromPreferences(oContext); 
     testMe = ((ApplicationConfiguration)oContext.getApplicationContext()); 
     int callerActivity = TestTypes!=null ? 2 : 1; 

     if (TestTypes!=null || Tests!=null) { 
      int lCols = strTheme.equals(testMe.theme_vivid) ? 1 : 2; 

      //int sourceElementIndex = 0; 
      int originListSize = calculateOriginalListSize(callerActivity, TestTypes, Tests); 
      int lRows = (int) Math.ceil((double)originListSize/lCols); 

      List<String> aStartColors = TMUtils_ThemeVivid.generateStartColorArray(lRows, oContext); 
      List<String> aEndColors = TMUtils_ThemeVivid.generateEndColorArray(lRows, oContext); 

      for (i = 0; i < lRows; i++) { 

       LinearLayout outerButtonLayout = generateOuterButtonLayout(oContext); 

       for (j = 0; j < lCols; j++) { 

        final Thread r = new Thread() { 
         public void run() { 
          LinearLayout innerButtonLayout = generateInnerButtonLayout(oContext); 
          outerButtonLayout.addView(innerButtonLayout, j); 

          if (sourceElementIndex<originListSize){ 
           final TMButton oButton = new TMButton(oContext); 

           if (callerActivity==1) { //testMenu 
            setTestMenuButtonSettings(oButton, sourceElementIndex, Tests); 
           } else { 
            if (callerActivity==2) { //testTypeMenu 
             setTestTypeMenuButtonSettings(oButton, sourceElementIndex, TestTypes); 
            } 
           } 

           if (strTheme.equals(testMe.theme_vivid)){ 
            oButton.fontSize = buttonFontSize; 
            oButton.gradientStartColor = aStartColors.get(i); 
            oButton.gradientEndColor = aEndColors.get(i); 
           }else{ 
            if (strTheme.equals(testMe.theme_purple)){ 
             oButton.gradientStartColor = testMe.btnStartColor_purple; 
             oButton.gradientEndColor = testMe.btnEndColor_purple; 
            } 
           } 

           configureButton(oButton, callerActivity); 

           oButton.setOnTouchListener(new OnTouchListener() { 
            @Override 
            public boolean onTouch(View v, MotionEvent event) { 

             Context oContext = v.getContext(); 
             TMButton oButton = (TMButton) v; 

             int callerActivity = Integer.valueOf(v.getTag().toString().split("@")[0]); 
             String sourceId = String.valueOf(v.getTag().toString().split("@")[1]); 

             if(event.getAction() == MotionEvent.ACTION_DOWN) { //pressed 
              setButtonPressed(oButton); 
              TMSound.playButtonSound(oContext); 
             } else if (event.getAction() == MotionEvent.ACTION_UP) { //released 
              setButtonReleased(oButton); 
              startTargetActivity(callerActivity, sourceId, oContext); 
             } 

             return true; 
            } 
           }); 
           TMAppearance.doButtonAnimation(oContext, oButton, i); 
           innerButtonLayout.addView(oButton); 
           sourceElementIndex++; 
          } 
         } 
        }; 
        r.run(); 
       } 
       llContainer.addView(outerButtonLayout); 
      } 
     } 
    } 
+0

gibt es etwas, über die Verwendung von 'ListView' oder' RecycleView', die Sie gegenüberstehen? Sie können sehr flexibel sein, indem Sie benutzerdefinierte Layouts verwenden. – Barns

+0

Vielen Dank für Ihre Antwort. Barns52, nein, natürlich bin ich nicht gegen ListView und in Wirklichkeit untersuche ich, wie man eine ListView implementiert, weil meine Buttons programmgesteuert generiert werden. Würden Sie denken, ich könnte ein ListView mit dynamisch generierten Tasten ohne Probleme verwenden? –

+0

Ich mag ListView (Nostalgie? ;-)), aber RecyclerView wurde eingeführt mit einer besseren Performance im Vergleich zu ListView, z. beim Scrollen. – 0X0nosugar

Antwort

0

0X0nosugar ist richtig. A RecycleView wird bessere Leistung bieten, aber viele Anfänger haben mehr Schwierigkeiten bei der Implementierung und mit nur 50 Tasten sollte die Leistung nicht wirklich ein Problem sein. Und obwohl ich mich im Allgemeinen gerne an die Regel "Nutze die beste verfügbare Lösung" halte, denke ich, dass es immer noch angebracht ist zu lernen, wie man die ListView implementiert. So ...

Sie benötigen einen benutzerdefinierten Adapter zu erstellen:

public class MyListDataAdapter extends ArrayAdapter<MyListData> { 

    private static final String TAG = "MyListDataAdapter"; 


    public MyListDataAdapter(Context context, ArrayList<MyListData> data) { 
     super(context, 0, data); 

    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent){ 

     final MyListData data = getItem(position); 

     if(convertView == null){ 
      convertView = LayoutInflater.from(getContext()).inflate(R.layout.edit_list_item, parent, false); 
     } 

     // Add a TextView if you need one 
     final TextView tvName = (TextView) convertView.findViewById(R.id.tvName); 
     Button btnEditTicketHolder = (Button) convertView.findViewById(R.id.btnEdit); 
     btnEditTicketHolder.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View view) { 
       long userId = data.getUserId(); 
       String fName = data.getFirstName(); 

       Intent intent = new Intent(getContext(), EditActivity.class); 
       intent.putExtra("userId", userId); 
       intent.putExtra("fName", fName); 
       getContext().startActivity(intent); 
      } 
     }); 


     String name = data.getFirstName(); 
     tvName.setText(name); 
     return convertView; 
    } 

} 

Jetzt müssen Sie Ihre MyListData Klasse, um die Daten zu halten:

public class MyListData { 

    // Add more as you need 
    private long userId; 
    private String firstName; 

    public MyListData(){ 
    } 


    public void setFirstName(String name){ this.firstName = name; } 
    public void setUserId(long id){ this.userId = id; } 

    public String getFirstName(){ return this.firstName; } 
    public long getUserId(){ return this.userId; } 
} 

Ihr individuelles ListView Layout etwas aussehen könnte :

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
       xmlns:app="http://schemas.android.com/apk/res-auto" 
       android:layout_width="match_parent" 
       android:layout_height="match_parent" 
    > 

    <LinearLayout 
     android:orientation="vertical" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_centerVertical="true" 
     > 

     <TextView 
      android:id="@+id/tvName" 
      android:text="With Whom" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      /> 

    </LinearLayout> 

    <LinearLayout 
     android:orientation="vertical" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentRight="true" 
     android:layout_centerVertical="true" 
     > 

     <Button 
      android:id="@+id/btnEdit" 
      android:layout_width="wrap_content" 
      android:layout_height="40dp" 
      android:paddingRight="10dp" 
      android:paddingLeft="10dp" 
      android:text="Edit" 
      android:backgroundTint="@color/colorAccent" 
      android:focusable="false" 
      /> 

    </LinearLayout> 

</RelativeLayout> 

In Ihrer Aktivität (z. B. in der onCreate() Methode), wo die ListView Sie die Daten für die ListView füllen müssen. Dies sollte nicht auf dem UI-Thread

erfolgen
ArrayList<MyListData> arrayListData = new ArrayList<MyListData>(); 
    MyListDataAdapter adapter = new MyListDataAdapter(this, arrayListData); 

    for (MyListData g : result) { 
     adapter.add(g); 
    } 
    mLstMy.setAdapter(adapter); 

Auch in der Tätigkeit, wo die ListView ist, einige onClick Event-Handler einrichten beibehalten werden, wenn Sie sie benötigen: (Ich finde, dass eine der kleinen Vorteile Umsetzung einfacher als in den RecycleView) die ListView ist, dass die onClick Veranstaltung ist es

mMyLst = (ListView) findViewById(lstMy); 
mMyLst.setOnItemClickListener(new AdapterView.OnItemClickListener() { 
    @Override 
    public void onItemClick(AdapterView<?> parent, View view, int position, long l) { 
     MyListData data = (MyListData) parent.getItemAtPosition(position); 
     selectedName = data.getName(); 

     Intent intent = new Intent(ShowListDataActivity.this, MainActivity.class); 
     startActivity(intent); 
    } 
}); 

mMyLst.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { 
    @Override 
    public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) { 

     MyListData data = (MyistData) adapterView.getItemAtPosition(i); 
     selectedName = data.getFirstName(); 

     selectedTicketPosition = i; 
     // removeValue is my own method for removing an entry from the 
     // list MyListData and then call adapter.notifyDataSetChanged(); 
     removeValue(i); 

     return true; 
    } 
}); 
+0

Vielen Dank @ Barns52 für die tolle Erklärung auf der ListView. Am Ende war ich in der Lage, eine RecyclerView zu implementieren, aber die Ergebnisse waren die gleichen und zu entdecken, dass die Verzögerung in der SQLite-Abfrage war. Ich war in der Lage, diese Abfrage zu optimieren und folglich ist der Bildschirm Render jetzt viel schneller. Ich werde Ihre Antwort aufgrund Ihrer Bemühungen im gesamten ListView-Lernprogramm korrekt einstellen. –

Verwandte Themen