gpt4 book ai didi

java - 改进 Large ListView Adapter 的平滑滚动,有时会出现抖动

转载 作者:搜寻专家 更新时间:2023-10-30 20:00:34 24 4
gpt4 key购买 nike

我想看看是什么让我的 ListView 有时在滚动时出现问题,有时情况很糟糕,尤其是在应用程序首次启动时。

我具备的所有条件都是必要的,除非有我不知道的(极有可能)。我没有在单独的线程上运行某些任务,因为它们依赖于我从后端接收的数据(我正在对两者进行编码,因此也欢迎后端建议)。产品处于测试阶段,但确实需要让它稍微平滑一些。我正在压缩图像,它们有点长,但这不是问题,因为当我从设备上传图像时,我还包括图像的宽度和高度并将其发送到后端。加载列表时,这些尺寸会返回。

我想知道的一件事是计算/转换特定设备屏幕的尺寸是否会导致轻微的延迟。不确定该任务的资源密集程度如何,但如果没有它(不知道尺寸,每一行开始时都是平的,然后扩展到实际图片大小,这会导致列表跳转,所以我无法在背景。)

基本上滚动还不错,但我需要以某种方式改进它。

这是我的适配器:

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);

}
}

最佳答案

无法指出具体问题,因为您的 Adapter 中有太多代码。不过有一件事是肯定的——在这种情况下切换到 RecyclerView 对您没有帮助。

适配器不应该包含业务逻辑——它们应该只将输入对象“适配”到底层 View 。在您的情况下,适配器似乎执行计算、生成新线程、执行网络请求等。

您需要重构您的代码,使适配器类似于:

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;
}

}

您的代码需要以这样的方式构建,即涉及在将新数据绑定(bind)到 ListViewPost 之前执行的数据计算和转换的业务逻辑您传递给 bindPosts() 方法的对象已经包含上述计算和转换的结果。

适配器只是将最终数据从 Posts“适配”到 Views - 仅此而已。

如果您现在时间紧迫,并且只需要“让它工作”,那么我将从删除生成新线程和发出网络请求的逻辑开始。看看这是否会提高性能。

关于java - 改进 Large ListView Adapter 的平滑滚动,有时会出现抖动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41632233/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com