Pierre87 Posted August 13, 2010 Share Posted August 13, 2010 Salut ! Dans mon appli, j'utilise de nombreuses ListView avec des vues customs. Je connais déjà le principe du recyclage et des view holders (et je l'applique) Les performances sont bonnes, mais pas exceptionnelles :( J'ai utilisé le "method profiling" et j'ai constaté un petit problème de performance : Lorsque je réutilise une View de ma ListView, je la mets à jour avec mes données. C'est cette fonction qui prend un peu de temps, et fait saccader ma ListView La vue contient entre autre une TextView. Or, grâce au "method profiling", j'ai vu que le setText() prenait énormément de temps par rapport aux autres fonctions! (55% du temps de la mise à jour de ma vue) Ce setText est particulier, puisque je mets dans ma TextView un Spannable. Vous avez des idées? Link to comment Share on other sites More sharing options...
Cyril Mottier Posted August 13, 2010 Share Posted August 13, 2010 Regarde aussi au niveau de l'allocation mémoire ... Sans le code, difficile de te dire ce qu'il est possible de modifier :p Link to comment Share on other sites More sharing options...
Pierre87 Posted August 13, 2010 Author Share Posted August 13, 2010 ouais c'est vrai... Quand je regarde les logs Android, je vois que le GC s'active un peu de temps à autre, mais je "sens" que ce n'est pas ça qui provoque les saccades (pas au mêmes moments) J'ai "plus de saccades que de GC" Comme c'est pour ma boite, le code n'est pas vraiment open source, mais bon... public void update(JSONObject jsonStory) { this.json = jsonStory; this.spannableText.clear(); JSONObject jsonUser = this.json.optJSONObject("user"); if (jsonUser != null) { this.spannableUser.update(jsonUser); this.spannableText.append(this.spannableUser); } JSONObject jsonPlace = this.json.optJSONObject("place"); if (jsonPlace != null) { if (this.spannableText.length() != 0) { this.spannableText.append(" "); } this.spannableText.append(jsonStory.optBoolean("isCheckin", true) ? "@ " : "› "); this.spannablePlace.update(jsonPlace); this.spannableText.append(this.spannablePlace); } String storyContent = this.json.optString("content", null); if (storyContent != null && storyContent.length() > 0) { this.spannableText.append(" : " + storyContent); } Linkify.addLinks(this.spannableText, Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES); this.text.setText(this.spannableText); String textTimeUsers = this.json.optString("parsed_date", ""); int userCount = jsonStory.optInt("userCount", 0); if (userCount > 0) { if (userCount == 1) { textTimeUsers += this.context.getString(R.string.and_one_other); } else { textTimeUsers += this.context.getString(R.string.and_n_others, userCount); } } this.timeUsers.setText(textTimeUsers); int storyCommentCount = this.json.optInt("commentCount", 0); if (storyCommentCount == 0) { this.commentCount.setText(null); this.commentCount.setBackgroundResource(R.drawable.story_comment_count_0); } else { this.commentCount.setText(Integer.toString(storyCommentCount)); this.commentCount.setBackgroundResource(R.drawable.story_comment_count_n); } if (jsonUser != null) { this.icon.setImageResource(R.drawable.user_default_icon); this.icon.setImageUrl(jsonUser.optString("icon", null)); } else if (jsonPlace != null) { this.icon.setImageResource(R.drawable.place_default_icon); JSONObject category = jsonPlace.optJSONObject("category"); if (category != null) { this.icon.setImageUrl(category.optString("icon", null)); } } else { this.icon.setImageBitmap(null); } String pictureUrl = null; int pictureWidth = 0; int pictureHeight = 0; JSONObject jsonPic = this.json.optJSONObject("pic"); if (jsonPic != null) { JSONObject pic150x150 = jsonPic.optJSONObject("150x150"); if (pic150x150 != null) { float density = this.context.getResources().getDisplayMetrics().density; pictureWidth = (int) (pic150x150.optInt("width", 0) * density); pictureHeight = (int) (pic150x150.optInt("height", 0) * density); pictureUrl = pic150x150.optString("url", ""); } } this.picture.setImageBitmap(null); this.picture.setImageUrl(pictureUrl, pictureWidth, pictureHeight); int friendsOnlyVisibility = jsonStory.optBoolean("isFriendsOnly", false) ? View.VISIBLE : View.GONE; this.friendsOnly.setVisibility(friendsOnlyVisibility); } Il s'agit d'une méthode DANS mon view holder Elle est appelée dans le getView de mon Adapter, pour mettre à jour la vue. Les variables de mon view holder sont : private View view; private WebImageView icon; private TextView text; private WebImageView picture; private TextView timeUsers; private ImageView friendsOnly; private TextView commentCount; private JSONObject json; private SpannableStringBuilder spannableText; private User.Spannable spannableUser; private Place.Spannable spannablePlace; Si j'ai bien interprété le "methode tracing", c'est l'appel : this.text.setText(this.spannableText); qui me prend 55% de ma méthode update() J'ai essayé d'instancier le moins possible d'objets dans cette méthode... Mais je suis bloqué par le setText() :( Ce view holder est lié à une View en xml. Celle ci a une complexité de 3 niveaux de profondeur. (en incluant la racine, ce qui est assez peu je pense) Link to comment Share on other sites More sharing options...
Nivek Posted August 13, 2010 Share Posted August 13, 2010 Pour le setText(), j'ai regardé un peu l'implem dans TextView, je ne vois pas trop comment on pourrait gagner dedans (à part en réduisant autant que possible le nombre de spans). Par contre dans ce qu'il y a autour, je suis étonné qu'à chaque getView() tu recrées ton texte à partir du JSON. Il serait intéressant de conserver dans un cache le résultat de ta conversion JSON => Spannable pour éviter d'avoir à le recréer à chaque fois Attention également à l'affectation des images... mais je suppose que la classe WebImageView est sensée optimiser cet aspect. Link to comment Share on other sites More sharing options...
Pierre87 Posted August 13, 2010 Author Share Posted August 13, 2010 L'initialisation du Spannable ne coûte quasiment rien en temps :/ Et ça m'obligerai à les stocker quelque part (donc encore plus de mémoire occupée, GC, etc...) J'ai joint une capture du "method tracing" Je ne sais pas trop comment l'interpréter (surtout le 8,5% en haut) setImageUrl est asynchrone et j'utilise les Bitmap à la taille maximum (pas besoin de redimensionner) Si vous voulez tester, c'est l'application "Plyce" sur le Market Link to comment Share on other sites More sharing options...
FlorentCode Posted August 28, 2010 Share Posted August 28, 2010 J'ai testé PLYCE, c'est pas mal fait du tout. Notamment, tes informations de profil sont bien présentées, je cherche à encadrer ou customiser des editText comme tu as fait mais je vois pas comment. Peux-tu m'expliquer? Merci d'avance Link to comment Share on other sites More sharing options...
Pierre87 Posted August 28, 2010 Author Share Posted August 28, 2010 android:layout_width="0dip" android:layout_height="wrap_content" android:orientation="vertical" android:layout_weight="1" android:background="@drawable/settings_form_background"> android:id="@+id/firstname" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="10dip" android:singleLine="true" android:hint="@string/firstname" android:background="#ffffff" /> android:layout_width="fill_parent" android:layout_height="1dip" android:background="#ffd1af" /> android:id="@+id/lastname" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="10dip" android:singleLine="true" android:background="#ffffff" android:hint="@string/lastname" /> xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> android:color="#ffffff" /> android:radius="10dip" /> android:width="1dip" android:color="#ffd1af" /> Link to comment Share on other sites More sharing options...
FlorentCode Posted August 28, 2010 Share Posted August 28, 2010 Merci :) Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.