0

I want to know that is it possible to assign value to a global variable using FirebaseDatabase methods. I know that the FirebaseDatabase methods are asynchronous and executed in background without blocking the main thread. But I am stuck in a case where the value is needed outside the onDataChange() method. Here is my java class file:

public class DetailActivity extends YouTubeBaseActivity implements YouTubePlayer.OnInitializedListener {

private ProgressBar mProgressBar;
private CoordinatorLayout coordinatorLayout;

private static final int RECOVERY_DIALOG_REQUEST = 1;
YouTubePlayerView youTubePlayerView;

int currentPage = 0;
Timer timer;
final long DELAY_MS = 500;
final long PERIOD_MS = 3000;
CircleIndicator circleIndicator;
private ViewPager viewPager;
private PagerAdapter adapter;

private ArrayList<String> images;
private ArrayList<String> imageDetails;

private DatabaseReference databaseReference;

private TextView capital, area, population,languages,literacyRate;
private ImageView appbarImageView;
private ExpandableTextView historyTextView;

private String youTubeVideoLink;

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_detail);
    CollapsingToolbarLayout collapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);

    viewPager = findViewById(R.id.view_pager);
    circleIndicator = findViewById(R.id.indicator);
    mProgressBar = findViewById(R.id.progress_bar);

    youTubePlayerView =  findViewById(R.id.youtube_player_view);
    youTubePlayerView.initialize(BuildConfig.ApiKey, this);

    population = findViewById(R.id.population);
    capital = findViewById(R.id.capital);
    area = findViewById(R.id.area);

    coordinatorLayout = findViewById(R.id.detail_container);
    appbarImageView = findViewById(R.id.app_bar_image);
    historyTextView = findViewById(R.id.expand_text_view);
    literacyRate = findViewById(R.id.literacy_rate);
    languages = findViewById(R.id.languages);

    Intent intent = getIntent();
    if(intent.hasExtra("State")) {
        collapsingToolbarLayout.setTitle(intent.getStringExtra("State"));
        databaseReference = FirebaseDatabase.getInstance().getReference().child("States").child(intent.getStringExtra("State").trim());
    }



    final Handler handler = new Handler();
    final Runnable update = new Runnable() {
        @Override
        public void run() {
            if(currentPage == 12) {
                currentPage = 0;
            }
            viewPager.setCurrentItem(currentPage++,true);
        }
    };
    timer = new Timer();
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            handler.post(update);
        }
    },DELAY_MS,PERIOD_MS);
}

private void readDataFromDatabase(final StatesCallback statesCallback) {
    databaseReference.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            StateDetails stateDetails = dataSnapshot.getValue(StateDetails.class);
            statesCallback.onCallback(stateDetails);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
}

@Override
protected void onDestroy() {
    super.onDestroy();
    timer.cancel();
}

@Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean b) {

    readDataFromDatabase(new StatesCallback() {
        @Override
        public void onCallback(StateDetails stateDetails) {
            mProgressBar.setVisibility(View.GONE);
            coordinatorLayout.setVisibility(View.VISIBLE);
            capital.setText(stateDetails.getCapital());
            area.setText(stateDetails.getArea());
            population.setText(stateDetails.getPopulation());
            historyTextView.setText(stateDetails.getHistory());
            languages.setText(stateDetails.getLanguages());
            literacyRate.setText(String.valueOf(stateDetails.getLiteracyRate()));
            images = stateDetails.getImages();
            imageDetails = stateDetails.getImageDetails();
            youTubeVideoLink = stateDetails.getYouTubeVideoLink();

            Log.i("youtube video",youTubeVideoLink);
            Picasso.get().load(images.get(0)).into(appbarImageView);
            adapter = new CustomAdapter(DetailActivity.this, images, imageDetails);
            viewPager.setAdapter(adapter);
            circleIndicator.setViewPager(viewPager);
            adapter.registerDataSetObserver(circleIndicator.getDataSetObserver());

        }
    });
    if(!b) {
        Log.i("Checking order","video link: "+youTubeVideoLink);
        youTubePlayer.cueVideo(youTubeVideoLink);
    }
}

@Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
    if(youTubeInitializationResult.isUserRecoverableError()) {
        youTubeInitializationResult.getErrorDialog(DetailActivity.this,RECOVERY_DIALOG_REQUEST);
    } else {
        String errorMessage = getString(R.string.youTubeErrorMessage)+youTubeInitializationResult;
        Toast.makeText(DetailActivity.this,errorMessage,Toast.LENGTH_SHORT).show();
    }

  }
}

Here's the log details:

I/Checking order: video link: null
I/youtube video: QR19-rUVjNQ

I want to assign a dynamic video to the YouTubePlayer who's link is stored in the database through the youTubeVideoLink string. I have tried the method listed here

But that didn't help. So,Is there any way so that the initialized youTubeVideoLink is sent to the onInitializationSuccess() method? Thank You.

1 Answers1

1

You cannot simply create a global variable and use it's value outside the onDataChange() because this methos has an asynchronous behaviour. If you want to use a value that is coming from the database outside the onDataChange() method, you have two choices. The first one would be to pass the desired object as argument to a method that is defined in your class or, if you want it in a more complex way, then dive into the asynchronous world of modern API's and see the last part of my answer in this post, in which I have explained step by step how you can achieve this. For more information, you can take also a look at this video.

Edit:

databaseReference.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        StateDetails stateDetails = dataSnapshot.getValue(StateDetails.class);
        methodThatDoesSomething(stateDetails); //Method call

    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
});

private void methodThatDoesSomething(StateDetails stateDetails) {
    //Do what you need to do with your stateDetails object
}
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • As I have seen in your linked answer that says "Get the data then log it", which means every value so be assigned within onDataChange() and in my case it's not possible, because that data needs to be passed to another method. – Prakash Kumar Jun 15 '18 at 10:39
  • So the first solution, passing the desired object as argument to a method solved your problem? – Alex Mamo Jun 15 '18 at 11:17
  • Can you explain it with an example or sample code, I am not able to get it as I am new to Android. – Prakash Kumar Jun 15 '18 at 11:19
  • I have to pass the youTubeVideoLink variable to the onInitializationSuccess() method, so it will be the same case as earlier – Prakash Kumar Jun 15 '18 at 15:49
  • In this case, you should use only the second solution which will solve your problem. – Alex Mamo Jun 15 '18 at 16:18
  • I tried the 2nd method and placed Log inside both the methods but the onInitializationSuccess() is getting executed before the readData() and hence the required value does not reach there. – Prakash Kumar Jun 15 '18 at 16:51
  • You need to call `readData()` inside the `onInitializationSuccess()` method. When calling in this way, you are waiting for the method to finish getting data from the database . Can you share your changed code? – Alex Mamo Jun 15 '18 at 17:03
  • I have done the same way. I provided the update code together with log details. – Prakash Kumar Jun 15 '18 at 17:25
  • Your code is correct and works as expected and I said that because this statement `youtube video: QR19-rUVjNQ` is printed out because it is placed inside the `onDataChange()` method. If you want to use it outside like in this line of code: `Log.i("Checking order","video link: "+youTubeVideoLink);` the result will always be `null` as in here: `Checking order: video link: null` and this is because the `asynchronous behavior` of this method, as mentioned also in my answer from that post. Move that `if(!b) {}` also inside the method. It does work, right? – Alex Mamo Jun 16 '18 at 09:06
  • Yeah, after placing the `if(! b) {} ` inside the method it did work. Thank you so much, Sir. You have been a great help. – Prakash Kumar Jun 16 '18 at 09:14