Permalink
Browse files

Step: Create the Repository to Fetch and Save Data

Change-Id: Id50ac3448519c884bef46e14afe919664ddb72f9
  • Loading branch information...
ceruleanotter committed Aug 24, 2017
1 parent 1d6ff9d commit c78292d187a33efe3509438663e7614f18ae9d2f
@@ -1,106 +1,118 @@
///*
// * Copyright (C) 2017 The Android Open Source Project
// *
// * Licensed under the Apache License, Version 2.0 (the "License");
// * you may not use this file except in compliance with the License.
// * You may obtain a copy of the License at
// *
// * http://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// */
//
//package com.example.android.sunshine.data;
//
//import android.util.Log;
//
//import com.example.android.sunshine.AppExecutors;
//import com.example.android.sunshine.data.database.WeatherDao;
//import com.example.android.sunshine.data.network.WeatherNetworkDataSource;
//
///**
// * Handles data operations in Sunshine. Acts as a mediator between {@link WeatherNetworkDataSource}
// * and {@link WeatherDao}
// */
//public class SunshineRepository {
// private static final String LOG_TAG = SunshineRepository.class.getSimpleName();
//
// // For Singleton instantiation
// private static final Object LOCK = new Object();
// private static SunshineRepository sInstance;
// private final WeatherDao mWeatherDao;
// private final WeatherNetworkDataSource mWeatherNetworkDataSource;
// private final AppExecutors mExecutors;
// private boolean mInitialized = false;
//
// private SunshineRepository(WeatherDao weatherDao,
// WeatherNetworkDataSource weatherNetworkDataSource,
// AppExecutors executors) {
// mWeatherDao = weatherDao;
// mWeatherNetworkDataSource = weatherNetworkDataSource;
// mExecutors = executors;
//
// }
//
// public synchronized static SunshineRepository getInstance(
// WeatherDao weatherDao, WeatherNetworkDataSource weatherNetworkDataSource,
// AppExecutors executors) {
// Log.d(LOG_TAG, "Getting the repository");
// if (sInstance == null) {
// synchronized (LOCK) {
// sInstance = new SunshineRepository(weatherDao, weatherNetworkDataSource,
// executors);
// Log.d(LOG_TAG, "Made new repository");
// }
// }
// return sInstance;
// }
//
// /**
// * Creates periodic sync tasks and checks to see if an immediate sync is required. If an
// * immediate sync is required, this method will take care of making sure that sync occurs.
// */
// public synchronized void initializeData() {
//
// // Only perform initialization once per app lifetime. If initialization has already been
// // performed, we have nothing to do in this method.
// if (mInitialized) return;
// mInitialized = true;
//
// // TODO Finish this method when instructed
// }
//
// /**
// * Database related operations
// **/
//
// /**
// * Deletes old weather data because we don't need to keep multiple days' data
// */
// private void deleteOldData() {
// // TODO Finish this method when instructed
// }
//
// /**
// * Checks if there are enough days of future weather for the app to display all the needed data.
// *
// * @return Whether a fetch is needed
// */
// private boolean isFetchNeeded() {
// // TODO Finish this method when instructed
// return true;
// }
//
// /**
// * Network related operation
// */
//
// private void startFetchWeatherService() {
// // TODO Finish this method when instructed
// }
//
//}
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.sunshine.data;
import android.arch.lifecycle.LiveData;
import android.util.Log;
import com.example.android.sunshine.AppExecutors;
import com.example.android.sunshine.data.database.WeatherDao;
import com.example.android.sunshine.data.database.WeatherEntry;
import com.example.android.sunshine.data.network.WeatherNetworkDataSource;
/**
* Handles data operations in Sunshine. Acts as a mediator between {@link WeatherNetworkDataSource}
* and {@link WeatherDao}
*/
public class SunshineRepository {
private static final String LOG_TAG = SunshineRepository.class.getSimpleName();
// For Singleton instantiation
private static final Object LOCK = new Object();
private static SunshineRepository sInstance;
private final WeatherDao mWeatherDao;
private final WeatherNetworkDataSource mWeatherNetworkDataSource;
private final AppExecutors mExecutors;
private boolean mInitialized = false;
private SunshineRepository(WeatherDao weatherDao,
WeatherNetworkDataSource weatherNetworkDataSource,
AppExecutors executors) {
mWeatherDao = weatherDao;
mWeatherNetworkDataSource = weatherNetworkDataSource;
mExecutors = executors;
// As long as the repository exists, observe the network LiveData.
// If that LiveData changes, update the database.
LiveData<WeatherEntry[]> networkData = mWeatherNetworkDataSource.getCurrentWeatherForecasts();
networkData.observeForever(newForecastsFromNetwork -> {
mExecutors.diskIO().execute(() -> {
// Insert our new weather data into Sunshine's database
mWeatherDao.bulkInsert(newForecastsFromNetwork);
Log.d(LOG_TAG, "New values inserted");
});
});
}
public synchronized static SunshineRepository getInstance(
WeatherDao weatherDao, WeatherNetworkDataSource weatherNetworkDataSource,
AppExecutors executors) {
Log.d(LOG_TAG, "Getting the repository");
if (sInstance == null) {
synchronized (LOCK) {
sInstance = new SunshineRepository(weatherDao, weatherNetworkDataSource,
executors);
Log.d(LOG_TAG, "Made new repository");
}
}
return sInstance;
}
/**
* Creates periodic sync tasks and checks to see if an immediate sync is required. If an
* immediate sync is required, this method will take care of making sure that sync occurs.
*/
public synchronized void initializeData() {
// Only perform initialization once per app lifetime. If initialization has already been
// performed, we have nothing to do in this method.
if (mInitialized) return;
mInitialized = true;
startFetchWeatherService();
}
/**
* Database related operations
**/
/**
* Deletes old weather data because we don't need to keep multiple days' data
*/
private void deleteOldData() {
// TODO Finish this method when instructed
}
/**
* Checks if there are enough days of future weather for the app to display all the needed data.
*
* @return Whether a fetch is needed
*/
private boolean isFetchNeeded() {
// TODO Finish this method when instructed
return true;
}
/**
* Network related operation
*/
private void startFetchWeatherService() {
mWeatherNetworkDataSource.startFetchWeatherService();
}
}
@@ -19,6 +19,8 @@
import android.content.Intent;
import android.util.Log;
import com.example.android.sunshine.utilities.InjectorUtils;
/**
* An {@link IntentService} subclass for immediately scheduling a sync with the server off of the
* main thread. This is necessary because {@link com.firebase.jobdispatcher.FirebaseJobDispatcher}
@@ -35,6 +37,8 @@ public SunshineSyncIntentService() {
@Override
protected void onHandleIntent(Intent intent) {
Log.d(LOG_TAG, "Intent service started");
// TODO Finish this method when instructed. Will eventually call the fetch weather code
WeatherNetworkDataSource networkDataSource =

This comment has been minimized.

Show comment
Hide comment
@davinctor

davinctor Apr 26, 2018

IntentService#onHandleIntent(Intent) runs on background thread. Also, one remark is that SunshineSyncIntentService references to WeatherNetworkDataSource and conversely. Why do not just run WeatherNetworkDataSource #fetchWeather() instead of starting service which is a resource-intensive operation? It'll not break the SunshineFirebaseJobService because it also calls the WeatherNetworkDataSource #fetchWeather() which runs on a background thread.

By the way, many thanks for this tutorial, really cool codelab.

@davinctor

davinctor Apr 26, 2018

IntentService#onHandleIntent(Intent) runs on background thread. Also, one remark is that SunshineSyncIntentService references to WeatherNetworkDataSource and conversely. Why do not just run WeatherNetworkDataSource #fetchWeather() instead of starting service which is a resource-intensive operation? It'll not break the SunshineFirebaseJobService because it also calls the WeatherNetworkDataSource #fetchWeather() which runs on a background thread.

By the way, many thanks for this tutorial, really cool codelab.

InjectorUtils.provideNetworkDataSource(this.getApplicationContext());
networkDataSource.fetchWeather();
}
}
@@ -15,11 +15,14 @@
*/
package com.example.android.sunshine.data.network;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.example.android.sunshine.AppExecutors;
import com.example.android.sunshine.data.database.WeatherEntry;
import com.firebase.jobdispatcher.Constraint;
import com.firebase.jobdispatcher.Driver;
import com.firebase.jobdispatcher.FirebaseJobDispatcher;
@@ -51,11 +54,14 @@
private static WeatherNetworkDataSource sInstance;
private final Context mContext;
// LiveData storing the latest downloaded weather forecasts
private final MutableLiveData<WeatherEntry[]> mDownloadedWeatherForecasts;
private final AppExecutors mExecutors;
private WeatherNetworkDataSource(Context context, AppExecutors executors) {
mContext = context;
mExecutors = executors;
mDownloadedWeatherForecasts = new MutableLiveData<WeatherEntry[]>();
}
/**
@@ -72,6 +78,10 @@ public static WeatherNetworkDataSource getInstance(Context context, AppExecutors
return sInstance;
}
public LiveData<WeatherEntry[]> getCurrentWeatherForecasts() {
return mDownloadedWeatherForecasts;
}
/**
* Starts an intent service to fetch the weather.
*/
@@ -165,8 +175,11 @@ void fetchWeather() {
response.getWeatherForecast()[0].getMin(),
response.getWeatherForecast()[0].getMax()));
// TODO Finish this method when instructed.
// Will eventually do something with the downloaded data
// When you are off of the main thread and want to update LiveData, use postValue.
// It posts the update to the main thread.
mDownloadedWeatherForecasts.postValue(response.getWeatherForecast());
// If the code reaches this point, we have successfully performed our sync
}
} catch (Exception e) {
// Server probably invalid
@@ -24,6 +24,7 @@
import com.example.android.sunshine.R;
import com.example.android.sunshine.data.database.WeatherEntry;
import com.example.android.sunshine.databinding.ActivityDetailBinding;
import com.example.android.sunshine.utilities.InjectorUtils;
import com.example.android.sunshine.utilities.SunshineDateUtils;
import com.example.android.sunshine.utilities.SunshineWeatherUtils;
@@ -78,6 +79,9 @@ protected void onCreate(Bundle savedInstanceState) {
e.printStackTrace();
}
});
// THIS IS JUST TO RUN THE CODE; REPOSITORY SHOULD NEVER BE CREATED IN DETAILACTIVITY
InjectorUtils.provideRepository(this).initializeData();
}
private void bindWeatherToUI(WeatherEntry weatherEntry) {
@@ -16,24 +16,31 @@
package com.example.android.sunshine.utilities;
import android.content.Context;
import com.example.android.sunshine.AppExecutors;
import com.example.android.sunshine.data.SunshineRepository;
import com.example.android.sunshine.data.database.SunshineDatabase;
import com.example.android.sunshine.data.network.WeatherNetworkDataSource;
/**
* Provides static methods to inject the various classes needed for Sunshine
*/
public class InjectorUtils {
// public static SunshineRepository provideRepository(Context context) {
// SunshineDatabase database = SunshineDatabase.getInstance(context.getApplicationContext());
// AppExecutors executors = AppExecutors.getInstance();
// WeatherNetworkDataSource networkDataSource =
// WeatherNetworkDataSource.getInstance(context.getApplicationContext(), executors);
// return SunshineRepository.getInstance(database.weatherDao(), networkDataSource, executors);
// }
//
// public static WeatherNetworkDataSource provideNetworkDataSource(Context context) {
// AppExecutors executors = AppExecutors.getInstance();
// return WeatherNetworkDataSource.getInstance(context.getApplicationContext(), executors);
// }
//
public static SunshineRepository provideRepository(Context context) {
SunshineDatabase database = SunshineDatabase.getInstance(context.getApplicationContext());
AppExecutors executors = AppExecutors.getInstance();
WeatherNetworkDataSource networkDataSource =
WeatherNetworkDataSource.getInstance(context.getApplicationContext(), executors);
return SunshineRepository.getInstance(database.weatherDao(), networkDataSource, executors);
}
public static WeatherNetworkDataSource provideNetworkDataSource(Context context) {
AppExecutors executors = AppExecutors.getInstance();
return WeatherNetworkDataSource.getInstance(context.getApplicationContext(), executors);
}
// public static DetailViewModelFactory provideDetailViewModelFactory(Context context, Date date) {
// SunshineRepository repository = provideRepository(context.getApplicationContext());
// return new DetailViewModelFactory(repository, date);

1 comment on commit c78292d

@LifetimeCode

This comment has been minimized.

Show comment
Hide comment
@LifetimeCode

LifetimeCode Apr 10, 2018

Please Make sure that SunshineDatabase class is public so that it can be imported in other classes.

LifetimeCode commented on c78292d Apr 10, 2018

Please Make sure that SunshineDatabase class is public so that it can be imported in other classes.

Please sign in to comment.