Mejora el adaptador grande ListView deslizamiento suave, a veces espasmódico

Estoy tratando de ver lo que está haciendo mi listview jerk a veces cuando se desplaza, a veces es malo, especialmente cuando la aplicación se lanza por primera vez.

Todas las condiciones que tengo son necesarias, a menos que haya algo que no sé (muy probable). No estoy ejecutando ciertas tareas en un hilo separado porque dependen de los datos que recibo del backend (estoy codificando ambos, así que las sugerencias de backend también son bienvenidas). El producto está en beta, pero realmente necesita hacer esto un poco más suave. Estoy comprimiendo las imágenes, y son un poco largas, pero no es el problema porque cuando subo las imágenes desde el dispositivo, también incluyen el ancho y la altura de la imagen y enviarlo a lo largo del backend. Estas dimensiones vuelven al cargar la lista.

Una cosa que me pregunto es si el cálculo / conversión de las dimensiones de la pantalla del dispositivo específico está causando el ligero retraso. No estoy seguro de cómo es el recurso intensivo que es la tarea, pero sin ella (sin saber las dimensiones, cada fila comenzaría plana y luego ampliar a la imagen real tamaño que haría que la lista de saltar, por lo que no se puede ejecutar ese cálculo en la Fondo o bien.)

Básicamente el desplazamiento no es malo, pero necesito mejorar esto de alguna manera.

Aquí está mi adaptador:

public class VListAdapter extends BaseAdapter { ViewHolder viewHolder; private boolean isItFromProfile; /** * fields For number formating, ex. 1000 * would return 1k in the format method */ private static final NavigableMap<Long, String> suffixes = new TreeMap<>(); static { suffixes.put(1_000L, "k"); suffixes.put(1_000_000L, "M"); suffixes.put(1_000_000_000L, "G"); suffixes.put(1_000_000_000_000L, "T"); suffixes.put(1_000_000_000_000_000L, "P"); suffixes.put(1_000_000_000_000_000_000L, "E"); } private Context mContext; private LayoutInflater mInflater; private ArrayList<Post> mDataSource; private static double lat; private static double lon; public VListAdapter(Context context, ArrayList<Post> items) { mContext = context; mDataSource = items; //mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); isItFromProfile = false; mInflater = LayoutInflater.from(context); } public VListAdapter() { } public VListAdapter(Context baseContext, ArrayList<Post> posts, boolean b) { mContext = baseContext; mDataSource = posts; //mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); isItFromProfile = b; mInflater = LayoutInflater.from(baseContext); } public void addElement(Post post) { mDataSource.add(0, post); this.notifyDataSetChanged(); } @Override public int getCount() { return mDataSource.size(); } @Override public Object getItem(int position) { return mDataSource.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { int limit = Math.min(position + 4, getCount()); for (int i = position; i < limit; i++) { Glide.with(mContext).load(((Post) getItem(i)).getFilename().toString()).preload(); } // StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads() // .detectDiskWrites().detectNetwork() // .penaltyLog().build()); View rowView = convertView; if (rowView == null) { viewHolder = new ViewHolder(); rowView = mInflater.inflate(R.layout.mylist, parent, false); viewHolder.titleTextView = (TextView) rowView.findViewById(R.id.usernameinlist); viewHolder.timeago = (TextView) rowView.findViewById(R.id.timeago); //viewHolder.sharebutton = (ImageView) rowView.findViewById(R.id.sharebutton); viewHolder.likesTextView = (TextView) rowView.findViewById(R.id.likestext); viewHolder.viewcount = (TextView) rowView.findViewById(R.id.viewcount); viewHolder.distance = (TextView) rowView.findViewById(R.id.distance); viewHolder.footprints = (TextView) rowView.findViewById(R.id.footprintcount); viewHolder.postText = (TextView) rowView.findViewById(R.id.posttext); viewHolder.profilePic = (ImageView) rowView.findViewById(R.id.profilethumb); viewHolder.caption = (TextView) rowView.findViewById(R.id.captiontext); viewHolder.moremenu = (ImageView) rowView.findViewById(R.id.dots); viewHolder.likesPic = (ImageView) rowView.findViewById(R.id.likeimage); viewHolder.mapitPic = (ImageView) rowView.findViewById(R.id.mapimage); viewHolder.playbutton = (ImageView) rowView.findViewById(R.id.playbutton); viewHolder.videoThumb = (ImageView) rowView.findViewById(R.id.videothumb); viewHolder.listphoto = (ImageView) rowView.findViewById(R.id.listphoto); viewHolder.rainbow = (ImageView) rowView.findViewById(R.id.rainbow); rowView.setTag(viewHolder); } else { viewHolder = (ViewHolder) rowView.getTag(); } final Post post = (Post) getItem(position); int color = Color.parseColor("#dddddd"); viewHolder.likesPic.setColorFilter(color); viewHolder.mapitPic.setColorFilter(color); viewHolder.moremenu.setColorFilter(color); if (Hawk.count() == 0) initHawkWithDataFromServer(); if (isItFromProfile) { viewHolder.profilePic.setVisibility(View.GONE); viewHolder.titleTextView.setVisibility(View.GONE); viewHolder.distance.setVisibility(View.GONE); } viewHolder.titleTextView.setText(post.getUsername()); PrettyTime prettyTime = new PrettyTime(); DateTime dateTime = new DateTime(post.getUploadDate().get$date()); viewHolder.timeago.setText(prettyTime.format(dateTime.toDate())); viewHolder.likesTextView.setText(String.valueOf(format(post.getLikes()))); viewHolder.footprints.setText(String.valueOf(format(post.getLocation().size() - 1))); //don't display 0 if there are no likes, just show heart icon if (viewHolder.likesTextView.getText().equals("0")) viewHolder.likesTextView.setVisibility(View.GONE); else viewHolder.likesTextView.setVisibility(View.VISIBLE); //don't display 0 if there are no footprints if (viewHolder.footprints.getText().equals("0")) viewHolder.footprints.setVisibility(View.GONE); else viewHolder.footprints.setVisibility(View.VISIBLE); double[] loc = post.getLocation().get(0); viewHolder.distance.setText("~" + PostListFragment.distance(loc[0], loc[1], 'M') + " Miles"); if (post.getViews() != null) viewHolder.viewcount.setText(format(post.getViews()) + (post.getViews() == 1 ? " View" : " Views")); String profilePictureS3Url = "https://s3-us-west-2.amazonaws.com/moleheadphotos/" + post.getUsername() + ".jpg"; String filename = post.getS3link(); final String videoThumbURL = "https://s3-us-west-2.amazonaws.com/moleheadphotos/" + filename; Glide.with(mContext).load(profilePictureS3Url).asBitmap().centerCrop().into(new BitmapImageViewTarget(viewHolder.profilePic) { @Override protected void setResource(Bitmap resource) { RoundedBitmapDrawable circularBitmapDrawable = RoundedBitmapDrawableFactory.create(mContext.getResources(), resource); circularBitmapDrawable.setCircular(true); viewHolder.profilePic.setImageDrawable(circularBitmapDrawable); } }); int height = ((Post) getItem(position)).getHeight(); int width = ((Post) getItem(position)).getWidth(); if (height != 0 && width != 0) { ViewGroup.LayoutParams params = viewHolder.listphoto.getLayoutParams(); Resources r = mContext.getResources(); height = (int) getHeight(height, width); params.height = height; params.width = ViewGroup.LayoutParams.MATCH_PARENT; viewHolder.listphoto.setLayoutParams(params); } else { ViewGroup.LayoutParams params = viewHolder.listphoto.getLayoutParams(); params.height = ViewGroup.LayoutParams.WRAP_CONTENT; params.width = ViewGroup.LayoutParams.MATCH_PARENT; viewHolder.listphoto.setLayoutParams(params); } if (post.getType() == null) { Glide.clear(viewHolder.listphoto); viewHolder.listphoto.setVisibility(View.GONE); //Glide.clear(viewHolder.listphoto); viewHolder.videoThumb.setVisibility(View.VISIBLE); viewHolder.rainbow.setVisibility(View.VISIBLE); Glide.with(mContext).load(videoThumbURL).fitCenter() .diskCacheStrategy(DiskCacheStrategy.ALL).dontAnimate().into(viewHolder.videoThumb); viewHolder.playbutton.setVisibility(View.VISIBLE); } if (post.getType() != null) { if (post.getType().equals("video")) { viewHolder.playbutton.setVisibility(View.VISIBLE); Glide.clear(viewHolder.listphoto); viewHolder.listphoto.setVisibility(View.GONE); Glide.clear(viewHolder.postText); viewHolder.postText.setVisibility(View.GONE); viewHolder.videoThumb.setVisibility(View.VISIBLE); viewHolder.rainbow.setVisibility(View.VISIBLE); Glide.with(mContext).load(videoThumbURL).fitCenter() .diskCacheStrategy(DiskCacheStrategy.ALL).dontAnimate().into(viewHolder.videoThumb); } if (post.getType().equals("image")) { Glide.clear(viewHolder.videoThumb); viewHolder.videoThumb.setVisibility(View.GONE); viewHolder.rainbow.setVisibility(View.GONE); Glide.clear(viewHolder.playbutton); viewHolder.playbutton.setVisibility(View.GONE); Glide.clear(viewHolder.postText); viewHolder.postText.setVisibility(View.GONE); viewHolder.listphoto.setVisibility(View.VISIBLE); viewHolder.listphoto.setBottom(0); Glide.with(mContext).load(post.getFilename().toString()) .diskCacheStrategy(DiskCacheStrategy.ALL).dontAnimate() .into(viewHolder.listphoto); } if (post.getType().equals("text")) { Glide.clear(viewHolder.videoThumb); viewHolder.videoThumb.setVisibility(View.GONE); viewHolder.rainbow.setVisibility(View.GONE); Glide.clear(viewHolder.playbutton); viewHolder.playbutton.setVisibility(View.GONE); Glide.clear(viewHolder.listphoto); viewHolder.listphoto.setVisibility(View.GONE); viewHolder.postText.setVisibility(View.VISIBLE); viewHolder.postText.setText(post.getText()); } } if (Hawk.contains("liked" + post.getId().get$oid())) { viewHolder.likesPic.clearColorFilter(); Glide.with(mContext).load(R.drawable.heartroundorange).into(viewHolder.likesPic); ((ImageView) viewHolder.likesPic).setColorFilter(Color.parseColor("#ff3a6f")); } else { Glide.with(mContext).load(R.drawable.heartroundgray).diskCacheStrategy(DiskCacheStrategy.ALL) .into(viewHolder.likesPic); } if (Hawk.contains("mapped" + post.getId().get$oid())) { viewHolder.mapitPic.clearColorFilter(); ((ImageView) viewHolder.mapitPic).setImageResource(R.drawable.dropmaincolororange); ((ImageView) viewHolder.mapitPic).setColorFilter(Color.parseColor("#444444")); } else { Glide.with(mContext).load(R.drawable.dropdarkgray).diskCacheStrategy(DiskCacheStrategy.ALL) .into(viewHolder.mapitPic); } if (!Hawk.contains("mapped" + post.getId().get$oid())) { viewHolder.mapitPic.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Hawk.put("mapped" + post.getId().get$oid(), 1); ((ImageView) viewHolder.mapitPic).setImageResource(R.drawable.dropmaincolororange); viewHolder.footprints.setText(String.valueOf(post.getLocation().size() + 1)); post.getLocation().add(new double[]{PostListFragment.lon, PostListFragment.lat}); notifyDataSetChanged(); Thread t = new Thread(new Runnable() { @Override public void run() { postMappedToServer(post.getId().get$oid()); } }); t.start(); TastyToast.makeText(mContext, "Post dropped off here.", TastyToast.LENGTH_SHORT, TastyToast.CONFUSING); } }); } else { viewHolder.mapitPic.setClickable(false); } if (!Hawk.contains("liked" + post.getId().get$oid())) { viewHolder.likesPic.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Hawk.put("liked" + post.getId().get$oid(), 1); viewHolder.likesPic.setClickable(false); ((ImageView) viewHolder.likesPic).setImageResource(R.drawable.heartroundorange); viewHolder.likesTextView.setText(String.valueOf(post.getLikes() + 1)); post.setLikes(post.getLikes() + 1); notifyDataSetChanged(); Thread t = new Thread(new Runnable() { @Override public void run() { postLikeToServer(post); } }); t.start(); } }); } else { viewHolder.likesPic.setClickable(false); } if (post.getType() == null || post.getType().equals("video")) viewHolder.videoThumb.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (VListAdapter.this.mContext instanceof ProfileFeed) { ((ProfileFeed) VListAdapter.this.mContext).closeActivity(); } Intent broadcast = new Intent(); broadcast.setAction("com.molehead.openout.POST"); broadcast.putExtra("postId", post.getFilename().toString()); broadcast.putExtra("hawkId", post.getId().get$oid()); broadcast.putExtra("s3link", post.getS3link()); broadcast.putExtra("username", post.getUsername()); if (Hawk.contains("liked" + post.getId().get$oid())) broadcast.putExtra("liked", "yes"); else broadcast.putExtra("liked", "no"); broadcast.putExtra("likecount", post.getLikes().toString()); App.post = post; LocalBroadcastManager.getInstance(mContext.getApplicationContext()).sendBroadcast(broadcast); } }); viewHolder.moremenu.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { PopupMenu popup = new PopupMenu(mContext.getApplicationContext(), viewHolder.moremenu, Gravity.CENTER); //Inflating the Popup using xml file popup.getMenuInflater().inflate(R.menu.menu_main, popup.getMenu()); //registering popup with OnMenuItemClickListener popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.action_share: String postId = post.getId().get$oid(); Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND); sharingIntent.setType("text/plain"); String shareBody = postId + ".jpg"; //https://openout.herokuapp.com/posts/" + postId; String shareSub = "Shared via Molehead"; sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, shareSub); sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, shareBody); sharingIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Intent new_intent = Intent.createChooser(sharingIntent, "Share"); new_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.getApplicationContext().startActivity(new_intent); break; } return true; } }); popup.show(); } }); return rowView; } private void initHawkWithDataFromServer() { SharedPreferences settings = mContext.getApplicationContext().getSharedPreferences("userinfo", 0); String username = settings.getString("username", "ok"); String password = settings.getString("password", "ok"); LoginService loginService = ServiceGenerator.createService(LoginService.class, username, password); final Call<List<Post>> call = loginService.getLikes(username); Log.i("lonlat", String.valueOf(lon) + " and " + String.valueOf(lat)); call.enqueue(new Callback<List<Post>>() { @Override public void onResponse(Call<List<Post>> call, Response<List<Post>> response) { ArrayList<Post> posts = new ArrayList<>(); posts = (ArrayList<Post>) response.body(); if (!posts.isEmpty()) for (Post p : posts) { Hawk.put("liked" + p.getId().get$oid(), 1); } } @Override public void onFailure(Call<List<Post>> call, Throwable t) { } }); } private void postMappedToServer(String oid) { SharedPreferences settings = mContext.getSharedPreferences("userinfo", 0); String username = settings.getString("username", "ok"); String password = settings.getString("password", "ok"); LoginService loginService = ServiceGenerator.createService(LoginService.class, username, password); Log.i("postlistfraglat", String.valueOf(PostListFragment.lat)); Call<ResponseBody> call = loginService.addLocation(oid, PostListFragment.lon, PostListFragment.lat); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if (response.isSuccessful()) Log.i("mapped", "success"); } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { } }); } public void postLikeToServer(Post post) { SharedPreferences settings = mContext.getSharedPreferences("userinfo", 0); String username = settings.getString("username", "ok"); String password = settings.getString("password", "ok"); LoginService loginService = ServiceGenerator.createService(LoginService.class, username, password); Call<ResponseBody> call = loginService.like(post, 1, username); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if (response.isSuccessful()) { try { Log.i("call", response.body().string()); } catch (IOException e) { e.printStackTrace(); } } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Log.i("MFEED", "like request failed"); } }); } public static String format(long value) { //Long.MIN_VALUE == -Long.MIN_VALUE so we need an adjustment here if (value == Long.MIN_VALUE) return format(Long.MIN_VALUE + 1); if (value < 0) return "-" + format(-value); if (value < 1000) return Long.toString(value); //deal with easy case Map.Entry<Long, String> e = suffixes.floorEntry(value); Long divideBy = e.getKey(); String suffix = e.getValue(); long truncated = value / (divideBy / 10); //the number part of the output times 10 boolean hasDecimal = truncated < 100 && (truncated / 10d) != (truncated / 10); return hasDecimal ? (truncated / 10d) + suffix : (truncated / 10) + suffix; } static class ViewHolder { private TextView titleTextView; private TextView timeago; private TextView likesTextView; private TextView viewcount; private TextView distance; private TextView footprints; private ImageView profilePic; private ImageView moremenu; private ImageView likesPic; private ImageView mapitPic; private ImageView rainbow; //private ImageView sharebutton; private TextView caption; private ImageView listphoto; private ImageView videoThumb; private ImageView playbutton; private TextView postText; private Post post; } private float getHeight(float height, float width) { WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); Point size = new Point(); display.getSize(size); return (height * size.x / width); } } 

  • Cambie su implementación a RecyclerView que es más eficiente en términos de eliminación de vistas o reciclaje.
  • También podemos habilitar las optimizaciones si los elementos son estáticos y no cambiará para un desplazamiento significativamente más suave:

     recyclerView.setHasFixedSize(true); 
  • Cree un servicio de intenciones y registre BroadcastReceiver como retorno de devolución de datos o devolución de llamada de error cuando se complete la solicitud de api, la regla de negocios y la modificación de datos. Utilice la llamada sincrónica para ejecutar initHawkWithDataFromServer() de antemano y después de obtener el resultado de api continuar modificando o aplicando la lógica de negocio. Después de crear un nuevo adaptador o actualizar el conjunto de datos del adaptador existente.

  • Mueva todo el cálculo de datos o la lógica de formateo de valores de datos que se getView() el getView() del adaptador al servicio de intención superior.

    Usted puede agregar más getter y setter al pojo existente del poste.

     DateTime dateTime = new DateTime(post.getUploadDate().get$date()); viewHolder.timeago.setText(prettyTime.format(dateTime.toDate())); viewHolder.likesTextView.setText(String.valueOf(format(post.getLikes()))); viewHolder.footprints.setText(String.valueOf(format(post.getLocation().size)) - 1))); Post{ //Your existing property @Expose(serialize = false, deserialize = false) //equals neither serialize nor deserialize or private DateTime uploadedDateTime; //etc. prettyTime.format, String.valueOf } 
  • Elimina la reflexión innecesaria:

     GsonBuilder builder = new GsonBuilder(); builder.excludeFieldsWithoutExposeAnnotation(); Gson gson = builder.create(); new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(gson)).build(); 

    Y ello a su clase de creación de servicios de retrofit. También puede utilizar transitorio ( private transient DateTime uploadedDateTime; )

  • Eliminar public void addElement(Post post) { mDataSource.add(0, post); this.notifyDataSetChanged();} public void addElement(Post post) { mDataSource.add(0, post); this.notifyDataSetChanged();} y siempre que necesite notificar si un solo o más elementos insertados, eliminados, etc. Utilice lo siguiente:

     notifyItemChanged(int) notifyItemInserted(int) notifyItemRemoved(int) notifyItemRangeChanged(int, int) notifyItemRangeInserted(int, int) notifyItemRangeRemoved(int, int) 

Podemos usarlas de la actividad o fragmento:

 //Add a new contact items.add(0, new Post("Barney")); //Notify the adapter that an item was inserted at position 0 adapter.notifyItemInserted(0); 

Los métodos anteriores son más eficientes. Cada vez que deseemos agregar o quitar elementos de RecyclerView , tendremos que informar explícitamente al adaptador del evento. A diferencia del adaptador ListView , un adaptador RecyclerView no debe confiar en notifyDataSetChanged() ya que las acciones más granulares deben ser utilizadas. Consulte la documentación de la API para obtener más detalles

Además, si tiene la intención de actualizar una lista existente, asegúrese de obtener la cuenta actual de elementos antes de realizar cualquier cambio. Por ejemplo, se debe llamar a un getItemCount() en el adaptador para registrar el primer índice que se va a cambiar.

 // record this value before making any changes to the existing list int curSize = adapter.getItemCount(); // replace this line with wherever you get new records ArrayList<Post> newItems = Post.createPostsList(20); // update the existing list items.addAll(newItems); // curSize should represent the first element that got added // newItems.size() represents the itemCount adapter.notifyItemRangeInserted(curSize, newItems.size()); 

Difusión de cambios mayores

Se ha agregado una nueva clase DiffUtil en la v24.2.0 de la biblioteca de soporte para calcular la diferencia entre la lista antigua y la nueva. Detalles

  • No precargue imágenes a través de deslizamiento si los tamaños de imagen son diferentes. Trate de crear su propia . También intente mirar .
  • Crear color como miembro de la clase

     int color = Color.parseColor("#dddddd"); 
  • Escribe View.GONE o View.VISIBLE en Post pojo, que se ejecutará en el hilo de fondo de Retrofit if IntentService. Intente api devolver boolean en json en lugar de "0" como String.

  • Mover todo a continuación a IntentService // no mostrar 0 si no hay gustos, sólo mostrar el icono del corazón si (viewHolder.likesTextView.getText (). Es igual ("0")) viewHolder.likesTextView.setVisibility (View.GONE); Else viewHolder.likesTextView.setVisibility (View.VISIBLE);

     //don't display 0 if there are no footprints if (viewHolder.footprints.getText().equals("0")) viewHolder.footprints.setVisibility(View.GONE); else viewHolder.footprints.setVisibility(View.VISIBLE); double[] loc = post.getLocation().get(0); viewHolder.distance.setText("~" + PostListFragment.distance(loc[0], loc[1], 'M') + " Miles"); 
  • Todas las concatenaciones String también en Post o IntnetService como:

     String profilePictureS3Url = "https://s3-us-west-2.amazonaws.com/moleheadphotos/" + post.getUsername() + ".jpg"; 

También puede crear filtro de color por adelantado y una sola vez. Quita la barra de desplazamiento de listview mientras calcula la altura para mostrar la barra de desplazamiento.

Es imposible señalar un problema específico porque hay tanto código en tu adaptador. Una cosa es segura, sin embargo – cambiar a RecyclerView no le ayudará en este caso.

Los adaptadores no deben contener lógica de negocios; sólo deben "adaptar" los objetos de entrada a las Vistas subyacentes. En su caso, parece que el adaptador realiza cálculos, genera nuevos subprocesos, realiza solicitudes de red, etc.

Debe refactorizar su código de forma que el adaptador sea similar a esto:

 public class PostsListAdapter extends ArrayAdapter<Post> { private Context mContext; public PostsListAdapter(Context context, int resource) { super(context, resource); mContext = context; } public void bindPosts(List<Post> posts) { clear(); addAll(posts); notifyDataSetChanged(); } @NonNull @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { // assign new View to convertView // create new ViewHolder // set ViewHolder as tag of convertView // set listeners } else { // get a reference to existing ViewHolder } // populate ViewHolder's elements with data from getItem(position) // kick off asynchronous loading of images // NOTE: no calculations allowed here - just simple bidding of data to Views return convertView; } } 

Su código debe estructurarse de tal manera que la lógica de negocio que implica cálculos y transformación de datos ejecutados antes de enlazar un nuevo dato a ListView , y los objetos Post que pasa al método bindPosts() ya contengan los resultados de los cálculos mencionados Y transformaciones.

Adaptador "adapta" los datos finales de los Posts a las Views – nada más.

Si ahora tienes poco tiempo y sólo necesitas "hacer que funcione", empezaría por eliminar la lógica que genera nuevos subprocesos y hace peticiones de red. Ver si esto mejora el rendimiento.

Hay demasiadas cosas que mejorar aquí. He aquí algunos ejemplos.

veo esto

 if (Hawk.count() == 0) initHawkWithDataFromServer(); 

Creo que el método initHawkWithDataFromServer se llamará muchas veces durante el tiempo que aparece la lista.

Esta llamada se puede hacer sólo una vez cuando se creó la actividad.

 Glide.with(mContext).load(videoThumbURL).fitCenter() 

Pero debes refactorizar tu código primero, moviendo la lógica a otra clase. Trate de eliminar algún código como este (debe hacerse utilizando algunos atributos de diseño)

 ViewGroup.LayoutParams params = viewHolder.listphoto.getLayoutParams(); Resources r = mContext.getResources(); height = (int) getHeight(height, width); params.height = height; params.width = ViewGroup.LayoutParams.MATCH_PARENT; viewHolder.listphoto.setLayoutParams(params); 
  • Cómo comprobar si existe una clave en Json Object y obtener su valor
  • Float o doble?
  • En Android; ¿Es mejor aplicar un OnClickListener o usar android: onClick?
  • Java Android leer el archivo completo rápidamente
  • La respuesta de Json es un android muy lento
  • Android: dibujar fondo sin GPU OverDraw como WhatsApp
  • Rendimiento ORM: ¿es greenDAO más rápido que ORMLite?
  • Acceder directamente a los campos estáticos en lugar de llamar a un método getter estático, ¿es más rápido?
  • Para la eficiencia de bucle
  • Android sólo descarga imágenes que son visibles en horizontalScrollView
  • ¿Qué podría hacer que una aplicación de Android se ejecute lentamente en un dispositivo idéntico a uno en el que corre rápido?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.