我在使用firebase作为后端的Android应用中制作投票系统。我正在从他们的历史记录中获取用户的投票状态,相应地更新视图,并响应按钮上的投票触摸。我遇到的问题是,当用户点击向上或向下投票按钮时,它会重新绘制列表视图,有时会省略其中两个选项,并始终将视图的滚动向上移动到顶部。我可以在不完全重绘列表视图的情况下更新列表视图中的数据吗?如果是这样,怎么样?
MovieActivity.java
public class MovieActivity extends AppCompatActivity {
private static final String KEY_IMDB = "KEY_IMDB";
private ImageView mPosterImageView;
private TextView mTitleTextView;
private TextView mYearTextView;
private TextView mSummaryTextView;
private ListView triggerListView;
private ArrayList<Trigger> mTriggerPrefList;
private Movie mMovie;
private LinkedList<Trigger> resultList;
DatabaseReference movieDB;
DatabaseReference userDB;
DatabaseReference thisMovieDB;
DatabaseReference triggerDB;
DatabaseReference adminDB;
FirebaseAuth mFirebaseAuth;
FirebaseUser mUser;
ArrayList<Trigger> mTriggerList;
String imdbID;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_movie);
mPosterImageView = (ImageView) findViewById(R.id.posterImageView);
mTitleTextView = (TextView) findViewById(R.id.titleTextView);
mYearTextView = (TextView) findViewById(R.id.yearTextView);
mSummaryTextView = (TextView) findViewById(R.id.summaryTextView);
triggerListView = (ListView) findViewById(R.id.triggerListView);
mFirebaseAuth = FirebaseAuth.getInstance();
mUser = mFirebaseAuth.getCurrentUser();
movieDB = FirebaseDatabase.getInstance().getReference("movies");
userDB = FirebaseDatabase.getInstance().getReference("users");
adminDB = FirebaseDatabase.getInstance().getReference("admin");
Intent intent = getIntent();
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
imdbID = intent.getStringExtra("ID_KEY");
final String keyTitle = intent.getStringExtra("TITLE_KEY");
final String keyYear = intent.getStringExtra("YEAR_KEY");
final String keyPoster = intent.getStringExtra("POSTER_KEY");
try {
getMovieDetails(imdbID, new Runnable() {
@Override
public void run() {
CheckForTriggerValues(new Runnable() {
@Override
public void run() {
populateTriggers(new Runnable() {
@Override
public void run() {
populatePrefs(new Runnable() {
@Override
public void run() {
reOrderList(new Runnable() {
@Override
public void run() {
Movie passMovie = new Movie();
passMovie.setImdbID(imdbID);
passMovie.setPosterURL(keyPoster);
passMovie.setYear(keyYear);
passMovie.setTitle(keyTitle);
TriggerAdapter adapter = new TriggerAdapter(MovieActivity.this, resultList, passMovie, imdbID );
triggerListView.setAdapter(adapter);
}
});
}
});
}
});
}
});
}
});
} catch (JSONException e) {
e.printStackTrace();
}
thisMovieDB = movieDB.child(imdbID);
triggerDB = thisMovieDB.child("Triggers");
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(KEY_IMDB, imdbID);
}
@Override
protected void onStart() {
super.onStart();
Intent intent = getIntent();
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
imdbID = intent.getStringExtra("ID_KEY");
}
private void getMovieDetails(String imdbID, Runnable runnable) throws JSONException {
String apiKey = OMITTED;
String theURL = "http://www.omdbapi.com/?i=" + imdbID + "&apikey=" + apiKey;
final OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(theURL).build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String jsonData = response.body().string();
if (response.isSuccessful()) {
runOnUiThread(new Runnable() {
@Override
public void run() {
try {
Movie movie = parseMovieDetails(jsonData);
updateMovieUI(movie);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
}
});
runnable.run();
}
private Movie parseMovieDetails(String jsonData) throws JSONException {
JSONObject jsonObject = new JSONObject(jsonData);
Movie movie = new Movie();
movie.setPosterURL(jsonObject.getString("Poster"));
movie.setTitle(jsonObject.getString("Title"));
movie.setYear(jsonObject.getString("Year"));
movie.setSummary(jsonObject.getString("Plot"));
mMovie = movie;
return movie;
}
private void updateMovieUI(Movie movie){
Context mContext = getApplicationContext();
mSummaryTextView.setText(movie.getSummary());
mYearTextView.setText(movie.getYear());
mTitleTextView.setText(movie.getTitle());
Picasso.with(mContext).load(movie.getPosterURL()).into(mPosterImageView);
}
private void populatePrefs(final Runnable runnable) {
mTriggerPrefList = new ArrayList<>();
mFirebaseAuth = FirebaseAuth.getInstance();
mUser = mFirebaseAuth.getCurrentUser();
movieDB = FirebaseDatabase.getInstance().getReference("movies");
userDB = FirebaseDatabase.getInstance().getReference("users");
adminDB = FirebaseDatabase.getInstance().getReference("admin");
thisMovieDB = movieDB.child(imdbID);
thisMovieDB.child("Details").setValue(mMovie);
triggerDB = thisMovieDB.child("Triggers");
userDB.child(mUser.getUid()).child("preferences").child("trigger").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot triggerSnapshot : dataSnapshot.getChildren()) {
String name = String.valueOf(triggerSnapshot.child("triggerName").getValue());
Trigger trigger = new Trigger();
trigger.setTriggerName(name);
trigger.setTriggerVotesTotal(0);
trigger.setTriggerVotesYes(0);
mTriggerPrefList.add(trigger);
}
Intent intent = getIntent();
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
imdbID = intent.getStringExtra("ID_KEY");
runnable.run();
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void populateTriggers(final Runnable runnable) {
mTriggerList = new ArrayList<>();
mFirebaseAuth = FirebaseAuth.getInstance();
mUser = mFirebaseAuth.getCurrentUser();
movieDB = FirebaseDatabase.getInstance().getReference("movies");
userDB = FirebaseDatabase.getInstance().getReference("users");
adminDB = FirebaseDatabase.getInstance().getReference("admin");
thisMovieDB = movieDB.child(imdbID);
thisMovieDB.child("Details").setValue(mMovie);
triggerDB = thisMovieDB.child("Triggers");
triggerDB.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
mTriggerList.clear();
for (DataSnapshot triggerSnapshot : dataSnapshot.getChildren()) {
Trigger trigger = triggerSnapshot.getValue(Trigger.class);
mTriggerList.add(trigger);
}
runnable.run();
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void reOrderList(Runnable runnable) {
resultList = new LinkedList<>();
for (Trigger triggerA : mTriggerList) {
boolean found = false;
for (Trigger triggerB : mTriggerPrefList) {
if (triggerB.getTriggerName().equals(triggerA.getTriggerName())) {
found = true;
}
}
if (found) {
resultList.add(triggerA);
}
}
mTriggerList.removeAll(resultList);
resultList.addAll(mTriggerList);
runnable.run();
}
private void CheckForTriggerValues(final Runnable runnable) {
adminDB.child("triggerList").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
GenericTypeIndicator<Map<String, Object>> genericTypeIndicator = new GenericTypeIndicator<Map<String, Object>>() {};
final Map<String, Object> triggerList = dataSnapshot.getValue(genericTypeIndicator);
triggerDB.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (Map.Entry<String, Object> entry : triggerList.entrySet())
{
if (dataSnapshot.hasChild(entry.getKey())){
}
else {
Trigger trigger1 = new Trigger(entry.getKey(), 0, 0);
triggerDB.child(trigger1.getTriggerName()).setValue(trigger1);
}
}
runnable.run();
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
int isTrue(Boolean boolDown, Boolean boolUp) {
int x = 0;
if (boolUp) {
x = 1;
}
if (boolDown) {
x = -1;
}
return x;
}
}
TriggerAdapter.java
package me.paxana.cwnet.Adapters;
import android.app.Activity;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Typeface;
import android.os.Build;
import android.provider.ContactsContract;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.TextView;
import com.andremion.counterfab.CounterFab;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.MutableData;
import com.google.firebase.database.Transaction;
import com.google.firebase.database.ValueEventListener;
import java.util.List;
import me.paxana.cwnet.Model.Movie;
import me.paxana.cwnet.Model.Trigger;
import me.paxana.cwnet.R;
import me.paxana.cwnet.ui.AdminPanelActivity;
import me.paxana.cwnet.ui.MovieActivity;
/**
* Created by paxie on 10/11/17.
*/
public class TriggerAdapter extends BaseAdapter {
private Context mContext;
private List<Trigger> mTriggers;
private Movie mMovie;
private String mImdbID;
private String mTitle;
private String mYear;
private String mPosterURL;
private DatabaseReference movieDB;
private DatabaseReference userDB;
private DatabaseReference triggerDB;
private DatabaseReference adminDB;
public TriggerAdapter(Context context, List<Trigger> triggerList, Movie movie, String imdbID){
mContext = context;
this.mTriggers = triggerList;
mMovie = movie;
mImdbID = imdbID;
mTitle = movie.getTitle();
mYear = movie.getYear();
mPosterURL = movie.getPosterURL();
};
public TriggerAdapter(Context context, List<Trigger> triggerList) {
mContext = context;
this.mTriggers = triggerList;
}
@Override
public int getCount() {
return this.mTriggers.size();
}
@Override
public Object getItem(int i) {
return mTriggers.get(i);
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(int i, View view, final ViewGroup viewGroup) {
final ViewHolder holder;
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
FirebaseUser user = firebaseAuth.getCurrentUser();
movieDB = FirebaseDatabase.getInstance().getReference("movies");
userDB = FirebaseDatabase.getInstance().getReference("users");
adminDB = FirebaseDatabase.getInstance().getReference("admin");
final String mUserId = user.getUid();
final Trigger trigger = mTriggers.get(i);
if (view == null) {
view = LayoutInflater.from(mContext).inflate(R.layout.trigger_list_item, null);
holder = new ViewHolder();
holder.triggerName = view.findViewById(R.id.triggerName);
holder.upButton = view.findViewById(R.id.mTriggerButtonUp);
holder.downButton = view.findViewById(R.id.mTriggerButtonDown);
holder.total = view.findViewById(R.id.triggerCounter);
view.setTag(holder);
}
else {
holder = (ViewHolder) view.getTag();
}
holder.triggerName.setText(trigger.getTriggerName());
if (mContext instanceof AdminPanelActivity) {
holder.upButton.setVisibility(View.INVISIBLE);
holder.downButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
adminDB.child("triggerList").child(trigger.getTriggerName()).removeValue();
int i = mTriggers.indexOf(trigger);
mTriggers.remove(i);
TriggerAdapter.this.notifyDataSetChanged();
}
});
}
if (mContext instanceof MovieActivity) {
userDB.child(mUserId).child("changes").child(mImdbID).child("triggers").child(trigger.getTriggerName()).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() != null) {
int userVote = dataSnapshot.getValue(Integer.class);
if (userVote == 0) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
holder.upButton.setBackgroundTintList(mContext.getResources().getColorStateList(R.color.colorAccent, null));
holder.downButton.setBackgroundTintList(mContext.getResources().getColorStateList(R.color.colorAccent, null));
}
else {
holder.upButton.setBackgroundTintList(mContext.getResources().getColorStateList(R.color.colorAccent));
holder.downButton.setBackgroundTintList(mContext.getResources().getColorStateList(R.color.colorAccent));
}
neitherButtonIsSelected(holder, trigger, mUserId);
}
if (userVote == 1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
holder.upButton.setBackgroundTintList(mContext.getResources().getColorStateList(R.color.votebuttons, null));
holder.downButton.setBackgroundTintList(mContext.getResources().getColorStateList(R.color.colorAccent, null));
}
else {
holder.upButton.setBackgroundTintList(mContext.getResources().getColorStateList(R.color.votebuttons));
holder.downButton.setBackgroundTintList(mContext.getResources().getColorStateList(R.color.colorAccent));
}
upButtonIsSelected(holder, trigger, mUserId);
}
if (userVote == -1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
holder.upButton.setBackgroundTintList(mContext.getResources().getColorStateList(R.color.colorAccent, null));
holder.downButton.setBackgroundTintList(mContext.getResources().getColorStateList(R.color.votebuttons, null));
}
else {
holder.upButton.setBackgroundTintList(mContext.getResources().getColorStateList(R.color.colorAccent));
holder.downButton.setBackgroundTintList(mContext.getResources().getColorStateList(R.color.votebuttons));
}
downButtonIsSelected(holder, trigger, mUserId);
}
}
else {
userDB.child(mUserId).child("changes").child(mImdbID).child("triggers").child(trigger.getTriggerName()).setValue(0);
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
holder.total.setText(String.valueOf(trigger.getTriggerVotesYes()));
holder.upButton.setCount(trigger.getTriggerVotesYes());
if (trigger.getTriggerVotesTotal() != 0){
holder.total.setText(String.valueOf(trigger.getTriggerVotesTotal()));
int downButtonCount = (trigger.getTriggerVotesTotal() - trigger.getTriggerVotesYes());
holder.downButton.setCount(downButtonCount);
}
return view;
}
private static class ViewHolder {
TextView triggerName;
CounterFab upButton;
CounterFab downButton;
TextView total;
}
private void neitherButtonIsSelected(final ViewHolder holder, final Trigger trigger, final String mUserId) {
holder.upButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
triggerDB = movieDB.child(mImdbID).child("Triggers").child(trigger.getTriggerName());
triggerDB.child("triggerVotesYes").runTransaction(new Transaction.Handler() {
@Override
public Transaction.Result doTransaction(MutableData mutableData) {
int count = mutableData.getValue(Integer.class);
mutableData.setValue(count + 1);
return Transaction.success(mutableData);
}
@Override
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
}
});
triggerDB.child("triggerVotesTotal").runTransaction(new Transaction.Handler() {
@Override
public Transaction.Result doTransaction(MutableData mutableData) {
int count = mutableData.getValue(Integer.class);
mutableData.setValue(count + 1);
userDB.child(mUserId).child("changes").child(mImdbID).child("triggers").child(trigger.getTriggerName()).setValue(1);
return Transaction.success(mutableData);
}
@Override
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
}
});
userDB.child(mUserId).child("changes").child(mImdbID).child("triggers").child(trigger.getTriggerName()).setValue(1);
}
});
holder.downButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
triggerDB.child("triggerVotesTotal").runTransaction(new Transaction.Handler() {
@Override
public Transaction.Result doTransaction(MutableData mutableData) {
int count = mutableData.getValue(Integer.class);
mutableData.setValue(count + 1);
userDB.child(mUserId).child("changes").child(mImdbID).child("triggers").child(trigger.getTriggerName()).setValue(1);
return Transaction.success(mutableData);
}
@Override
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
}
});
userDB.child(mUserId).child("changes").child(mImdbID).child("triggers").child(trigger.getTriggerName()).setValue(1);
}
});
}
private void upButtonIsSelected(final ViewHolder holder, final Trigger trigger, final String mUserId) {
holder.upButton.setOnClickListener(null);
holder.downButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
triggerDB = movieDB.child(mImdbID).child("Triggers").child(trigger.getTriggerName());
triggerDB.child("triggerVotesYes").runTransaction(new Transaction.Handler() {
@Override
public Transaction.Result doTransaction(MutableData mutableData) {
int count = mutableData.getValue(Integer.class);
mutableData.setValue(count - 1);
userDB.child(mUserId).child("changes").child(mImdbID).child("triggers").child(trigger.getTriggerName()).setValue(-1);
return Transaction.success(mutableData);
}
@Override
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
holder.downButton.getBackground().setAlpha(127);
}
});
}
});
}
private void downButtonIsSelected(final ViewHolder holder, final Trigger trigger, final String mUserId) {
holder.downButton.setOnClickListener(null);
holder.upButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
triggerDB = movieDB.child(mImdbID).child("Triggers").child(trigger.getTriggerName());
triggerDB.child("triggerVotesYes").runTransaction(new Transaction.Handler() {
@Override
public Transaction.Result doTransaction(MutableData mutableData) {
int count = mutableData.getValue(Integer.class);
mutableData.setValue(count + 1);
userDB.child(mUserId).child("changes").child(mImdbID).child("triggers").child(trigger.getTriggerName()).setValue(1);
return Transaction.success(mutableData);
}
@Override
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
holder.downButton.getBackground().setAlpha(127);
}
});
}
});
}
}
答案 0 :(得分:0)
以下事情可能对您有帮助。
android:stackFromBottom="true"
ListView
mTriggerList.clear();
,请不要清除它,只有在列表中尚不存在该项目时才将项目添加到列表中。例如
for(Trigger trigger: triggerSnapShot...){
if (!mTriggerList.contains(trigger)){
mTriggerList.add(trigger);
}
}
您可能需要覆盖equals
类中的Trigger
方法,以使方法contains
正常工作。