How can I avoid code duplication when getting data

2020-06-30 03:17发布

I'd imagine this question would apply to any application that uses asynchronous calls.

I'm relatively new to all this, and the problem I'm having is with with fetching data from Firebase to my Android application.

There are several classes throughout the application that need to use data from the "users" table in the database, which I obtain as follows:

DatabaseReference reference = FirebaseDatabase.getInstance().getReference()
.child("users").child("exampleDataFromUsers");
reference.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        // do something with the snapshot
    }

I'd like to create a general purpose class for handling data retrieval from Firebase, something like:

public class FirebaseDataHandler() {

  static String getUserReports() {
    // get Reports
  }

  static int getUserAge() {
    // get age
  }
}

but since it's being retrieved asynchronously, any calls to these methods simply return null. As a result, my code is currently littered with duplicate code.

If anyone has any insight into a better way to achieve this, it would be much appreciated. Thanks.

1条回答
The star\"
2楼-- · 2020-06-30 03:37

I believe this question will generate many good answers primarily based on opinions. But I will still post my opinion anyway:

I personally use Firebase with Android Architecture Components, which (from the documentation) is:

A collection of libraries that help you design robust, testable, and maintainable apps. Start with classes for managing your UI component lifecycle and handling data persistence.

This libraries offers 2 classes to make your data lifecycle aware: Live Data and ViewModel. You can find a guide to integrate these 2 libraries on the Firebase Blog: [Part1, Part2, Part3].

To use the library, you need to add the Google repository to your project's build.gradle file:

allprojects {
    repositories {
        jcenter()
        google()
    }
}

and then add the dependency on your app's build.gradle file:

implementation "android.arch.lifecycle:extensions:1.1.0"

So you create a class that extends from LiveData:

public class FirebaseQueryLiveData extends LiveData<DataSnapshot> {
    private static final String LOG_TAG = "FirebaseQueryLiveData";

    private final Query query;
    private final MyValueEventListener listener = new MyValueEventListener();

    public FirebaseQueryLiveData(Query query) {
        this.query = query;
    }

    public FirebaseQueryLiveData(DatabaseReference ref) {
        this.query = ref;
    }

    @Override
    protected void onActive() {
        Log.d(LOG_TAG, "onActive");
        query.addValueEventListener(listener);
    }

    @Override
    protected void onInactive() {
        Log.d(LOG_TAG, "onInactive");
        query.removeEventListener(listener);
    }

    private class MyValueEventListener implements ValueEventListener {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            setValue(dataSnapshot);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            Log.e(LOG_TAG, "Can't listen to query " + query, databaseError.toException());
        }
    }
}

And create a ViewModel which will load this user's data:

public class UserViewModel extends ViewModel{
  private static final DatabaseReference USERS_REF =
      FirebaseDatabase.getInstance().getReference("users/exampleDataFromUsers");

  private final FirebaseQueryLiveData liveData = new FirebaseQueryLiveData(USERS_REF);

  private final LiveData<String> liveData =
    Transformations.map(liveData, new Function<DataSnapshot, String> {
      @Override
      public String apply(DataSnapshot dataSnapshot) {
          //do something with the snapshot and return a String
      }
    });

  @NonNull
  public LiveData<String> getUserReports() {
      return liveData;
  }
}

Finally, in order to get this data in your activities, you just need to call your ViewModel and observe it's LiveData:

    UserViewModel viewModel = ViewModelProviders.of(this).get(UserViewModel.class);
    viewModel.getUserReports().observe(this, new Observer<String>() {
                @Override
                public void onChanged(@Nullable String reports) {
                    if (reports != null) {
                        // update the UI here with values
                    }
                }
            });
查看更多
登录 后发表回答