更新firebase信息而不重新绘制listview

时间:2017-10-26 01:30:54

标签: java android listview firebase firebase-realtime-database

我在使用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);
                    }
                });
            }
        });
    }
}

1 个答案:

答案 0 :(得分:0)

以下事情可能对您有帮助。

  • android:stackFromBottom="true"
  • 的xml中使用ListView
  • 不要在更新时使用mTriggerList.clear();,请不要清除它,只有在列表中尚不存在该项目时才将项目添加到列表中。

例如

for(Trigger trigger: triggerSnapShot...){
    if (!mTriggerList.contains(trigger)){
        mTriggerList.add(trigger);
    }
}

您可能需要覆盖equals类中的Trigger方法,以使方法contains正常工作。