android - recyclerview 中的第一项重复
问题描述
在将列表加载到具有自定义布局的警报对话框中的回收器视图中时,我遇到了问题。问题是第一项重复了两次,我不明白为什么。
如果有人可以通过一个很好的解释帮助我和社区理解为什么会发生这种情况?
AccountActivity 女巫调用对话:
public class AccountActivity extends AppCompatActivity {
private Context context;
private Gson gson = new Gson();
private SharedPreferences sharedPreferences;
List<UserAvatar> userAvatarList = new ArrayList<>();
private User user;
private UserAvatar userAvatar;
private TextView textViewAccountUsername;
private TextView textViewAccountFollowersNumber;
private TextView textViewAccountFollowingNumber;
private TextView textViewAccountDescription;
private ImageButton imageButtonAccountBackArrow;
private ImageView imageViewAccountAvatar;
private AlertDialog alertDialogChooseAvatar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_account);
context = getApplicationContext();
sharedPreferences = context.getSharedPreferences(Constants.sharedPreferencesDocName, Context.MODE_PRIVATE);
bindUI();
setListeners();
getLocalData();
getUserAvatar();
}
private void bindUI(){
textViewAccountUsername = findViewById(R.id.textViewAccountUsername);
textViewAccountFollowersNumber = findViewById(R.id.textViewAccountFollowersNumber);
textViewAccountFollowingNumber = findViewById(R.id.textViewAccountFollowingNumber);
textViewAccountDescription = findViewById(R.id.textViewAccountDescription);
imageButtonAccountBackArrow = findViewById(R.id.imageButtonAccountBackArrow);
imageViewAccountAvatar = findViewById(R.id.imageViewAccountAvatar);
}
private void setListeners(){
imageButtonAccountBackArrow.setOnClickListener(v -> onBackPressed());
imageViewAccountAvatar.setOnClickListener(v -> showChooseAvatarDialog());
}
@Override
public void onBackPressed() {
Intent intent = new Intent(AccountActivity.this, MainActivity.class);
startActivity(intent);
finish();
}
private void getLocalData(){
user = gson.fromJson(sharedPreferences.getString("user", ""), User.class);
if(user != null){
setLocalData();
}else{
Toast.makeText(context, getString(R.string.generic_error), Toast.LENGTH_SHORT).show();
}
}
private void getUserAvatar() {
Thread thread = new Thread() {
@Override
public void run() {
Response response;
try {
response = UserAvatarRequests.getAvatar(context, user.getAvatar_id());
String responseBody = Objects.requireNonNull(response.body()).string();
responseBody = responseBody.replace("\r\n", "");
if (response.code() == 200) {
UserAvatar userAvatar = gson.fromJson(responseBody, UserAvatar.class);
sharedPreferences.edit().putString("userAvatar", gson.toJson(userAvatar)).apply();
getAvatars();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
thread.start();
}
private void getAvatars(){
Thread threadGetAvatars = new Thread() {
@Override
public void run() {
Response response;
try {
response = UserAvatarRequests.getAvatars(context);
String responseBody = Objects.requireNonNull(response.body()).string();
if (response.code() == 200) {
userAvatarList.clear();
JSONArray responseArray = new JSONArray(responseBody);
for (int i = 0; i < responseArray.length(); i++) {
String jsonObjectString = responseArray.getJSONObject(i).toString();
userAvatarList.add(gson.fromJson(jsonObjectString, UserAvatar.class));
}
sharedPreferences.edit().putString("userAvatars", gson.toJson(userAvatarList)).apply();
getApiData();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
threadGetAvatars.start();
}
private void getApiData(){
Thread threadGetUserById = new Thread() {
@Override
public void run() {
Response response;
try {
response = UserRequests.getUserById(context, user.getId());
String responseBody = Objects.requireNonNull(response.body()).string();
responseBody = responseBody.replace("\r\n", "");
if (response.code() == 200) {
user = gson.fromJson(responseBody, User.class);
sharedPreferences.edit().putString("user", gson.toJson(user)).apply();
setApiData();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
threadGetUserById.start();
}
private void setLocalData(){
textViewAccountUsername.setText(user.getUsername());
textViewAccountDescription.setText(user.getDescription());
}
private void setApiData(){
Thread thread = new Thread() {
public void run() {
runOnUiThread(() -> {
textViewAccountUsername.setText(user.getUsername());
textViewAccountDescription.setText(user.getDescription());
userAvatar = userAvatarList.get(user.getAvatar_id());
Picasso.get().load(userAvatar.getAvatar_url()).into(imageViewAccountAvatar);
});
}
};
thread.start();
}
private void showChooseAvatarDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(AccountActivity.this);
builder.setTitle(getString(R.string.change_avatar));
final View customLayout = getLayoutInflater().inflate(R.layout.alert_dialog_choose_avatar, null);
builder.setView(customLayout);
alertDialogChooseAvatar = builder.create();
ChooseAvatarAdapter chooseAvatarAdapter = new ChooseAvatarAdapter(AccountActivity.this, userAvatarList, alertDialogChooseAvatar, imageViewAccountAvatar);
RecyclerView recyclerViewChooseAvatar = customLayout.findViewById(R.id.recyclerViewChooseAvatar);
recyclerViewChooseAvatar.setLayoutManager(new GridLayoutManager(context, 3));
recyclerViewChooseAvatar.setAdapter(chooseAvatarAdapter);
alertDialogChooseAvatar.show();
}
}
警报对话框布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:padding="5dp">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerViewChooseAvatar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Recyclerview 项目 XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content"
android:padding="16dp">
<ImageView
android:id="@+id/imageViewChooseAvatar"
android:layout_width="50sp"
android:layout_height="50sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
RecyclerView 适配器:
public class ChooseAvatarAdapter extends RecyclerView.Adapter<ChooseAvatarAdapter.ChooseAvatarAdapterViewHolder> {
private final Context context;
private final List<UserAvatar> userAvatarList;
private final AlertDialog alertDialogAvatar;
private final ImageView imageViewAvatar;
public ChooseAvatarAdapter(Context context, List<UserAvatar> userAvatarList, AlertDialog alertDialogAvatar, ImageView imageViewAvatar) {
this.context = context;
this.userAvatarList = userAvatarList;
this.alertDialogAvatar = alertDialogAvatar;
this.imageViewAvatar = imageViewAvatar;
}
@NonNull
@NotNull
@Override
public ChooseAvatarAdapter.ChooseAvatarAdapterViewHolder onCreateViewHolder(@NonNull @NotNull ViewGroup parent, int viewType) {
return new ChooseAvatarAdapterViewHolder(LayoutInflater.from(context).inflate(R.layout.alert_dialog_choose_avatar_item, parent, false));
}
@Override
public void onBindViewHolder(@NonNull @NotNull ChooseAvatarAdapter.ChooseAvatarAdapterViewHolder holder, int position) {
Picasso.get()
.load(userAvatarList.get(position).getAvatar_url())
.into(holder.imageViewChooseAvatar);
holder.imageViewChooseAvatar.setOnClickListener(v -> {
alertDialogAvatar.dismiss();
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(context.getString(R.string.confirm_avatar_change))
.setPositiveButton(context.getString(R.string.yes), (dialog, which) -> {
Gson gson = new Gson();
SharedPreferences sharedPreferences = context.getSharedPreferences(Constants.sharedPreferencesDocName, Context.MODE_PRIVATE);
User user = gson.fromJson(sharedPreferences.getString("user", ""), User.class);
user.setAvatar_id(position);
sharedPreferences.edit().putString("user", gson.toJson(user)).apply();
Thread thread = new Thread() {
@Override
public void run() {
Response response;
try {
response = UserRequests.editUserAvatar(context, user.getId(), position);
if (response.code() == 200) {
dialog.dismiss();
((AccountActivity) context).runOnUiThread(() -> Picasso.get()
.load(userAvatarList.get(position).getAvatar_url())
.into(imageViewAvatar));
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
thread.start();
})
.setNegativeButton(context.getString(R.string.no), (dialog, which) -> dialog.cancel())
.create()
.show();
});
}
@Override
public int getItemCount() {
return userAvatarList.size();
}
public static class ChooseAvatarAdapterViewHolder extends RecyclerView.ViewHolder {
ImageView imageViewChooseAvatar;
public ChooseAvatarAdapterViewHolder(View itemView) {
super(itemView);
imageViewChooseAvatar = itemView.findViewById(R.id.imageViewChooseAvatar);
}
}
}
解决方案
推荐阅读
- email - GAS 电子邮件表作为 PDF 文件发送损坏的附件
- javascript - 在 vue 中传递信息而不是 props 的正确方法是什么?
- javascript - 如何计算按钮单击中多个坐标之间的距离?
- javascript - JavaScript 对象问题:使用对象名称获取对象的属性值
- python - Keras logits 和标签必须具有相同的第一维,得到 logits 形状 [10240,151] 和标签形状 [1],sparse_categorical_crossentropy
- python - Pocketsphinx new_Decoder 错误,无法在 livepeech 中添加新语言,如何解决?
- apache-kafka - ksqlDB:将流连接到嵌套结构并接收到 postgresql
- windows - git-bash.exe 中的进程无法打开 `CONIN$`
- javascript - 添加 toast 通知时如何解决以下错误?
- javascript - 将第二个参数从视图中的模型传递给 AJAX 函数