Permalink
Browse files

Done S0901- ContentProviderFoundation

  • Loading branch information...
GinaHsu committed Nov 7, 2017
1 parent e137ffc commit c3b4810bd8b78d53780e4e70dfc4cabd38057774
@@ -53,6 +53,9 @@
<activity android:name=".SettingsActivity"/>
<!-- TODO (4) Register WeatherProvider in the manifest with the correct authorities -->
<provider
android:authorities="@string/content_authority"
android:name=".data.WeatherProvider"
android:exported="false"/>
</application>
</manifest>
@@ -18,10 +18,12 @@
import android.annotation.TargetApi;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.NonNull;
/**
* This class serves as the ContentProvider for all of Sunshine's data. This class allows us to
* bulkInsert data, query data, and delete data.
@@ -34,21 +36,100 @@
*/
public class WeatherProvider extends ContentProvider {
// TODO (5) Create static constant integer values named CODE_WEATHER & CODE_WEATHER_WITH_DATE to identify the URIs this ContentProvider can handle
// TODO (5) Create static constant integer values named
// CODE_WEATHER & CODE_WEATHER_WITH_DATE to identify the URIs
// this ContentProvider can handle
/*
* These constant will be used to match URIs with the data they are looking for.
*/
public static final int CODE_WEATHER = 100;
public static final int CODE_WEATHER_WITH_DATE = 101;
// TODO (7) Instantiate a static UriMatcher using the buildUriMatcher method
private WeatherDbHelper mOpenHelper;
WeatherDbHelper mOpenHelper;
// TODO (6) Write a method called buildUriMatcher where you match URI's to their numeric ID /*
/*
* The URI Matcher used by this content provider. The leading "s" in this variable name
* signifies that this UriMatcher is a static member variable of WeatherProvider and is a
* common convention in Android programming.
*/
private static final UriMatcher sUriMatcher = buildUriMatcher();
/**
* Creates the UriMatcher that will match each URI to the CODE_WEATHER and
* CODE_WEATHER_WITH_DATE constants defined above.
* <p>
* It's possible you might be thinking, "Why create a UriMatcher when you can use regular
* expressions instead? After all, we really just need to match some patterns, and we can
* use regular expressions to do that right?" Because you're not crazy, that's why.
* <p>
* UriMatcher does all the hard work for you. You just have to tell it which code to match
* with which URI, and it does the rest automagically. Remember, the best programmers try
* to never reinvent the wheel. If there is a solution for a problem that exists and has
* been tested and proven, you should almost always use it unless there is a compelling
* reason not to.
*
* @return A UriMatcher that correctly matches the constants for CODE_WEATHER and CODE_WEATHER_WITH_DATE
*/
public static UriMatcher buildUriMatcher(){
/*
* All paths added to the UriMatcher have a corresponding code to return when a match is
* found. The code passed into the constructor of UriMatcher here represents the code to
* return for the root URI. It's common to use NO_MATCH as the code for this case.
*/
final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
/*
* For each type of URI you want to add, create a corresponding code. Preferably, these are
* constant fields in your class so that you can use them throughout the class and you no
* they aren't going to change. In Sunshine, we use CODE_WEATHER or CODE_WEATHER_WITH_DATE.
*/
/* This URI is content://com.example.android.sunshine/weather/ */
matcher.addURI(WeatherContract.CONTENT_AUTHORITY,
WeatherContract.PATH_WEATHER, CODE_WEATHER);
/*
* This URI would look something like content://com.example.android.sunshine/weather/1472214172
* The "/#" signifies to the UriMatcher that if PATH_WEATHER is followed by ANY number,
* that it should return the CODE_WEATHER_WITH_DATE code
*/
matcher.addURI(WeatherContract.CONTENT_AUTHORITY,
WeatherContract.PATH_WEATHER+"/#", CODE_WEATHER_WITH_DATE);
return matcher;
}
// TODO (6) Write a method called buildUriMatcher where you match URI's to their numeric ID
// TODO (1) Implement onCreate
/**
* In onCreate, we initialize our content provider on startup. This method is called for all
* registered content providers on the application main thread at application launch time.
* It must not perform lengthy operations, or application startup will be delayed.
*
* Nontrivial initialization (such as opening, upgrading, and scanning
* databases) should be deferred until the content provider is used (via {@link #query},
* {@link #bulkInsert(Uri, ContentValues[])}, etc).
*
* Deferred initialization keeps application startup fast, avoids unnecessary work if the
* provider turns out not to be needed, and stops database errors (such as a full disk) from
* halting application launch.
*
* @return true if the provider was successfully loaded, false otherwise
*/
@Override
public boolean onCreate() {
/*
* As noted in the comment above, onCreate is run on the main thread, so performing any
* lengthy operations will cause lag in your app. Since WeatherDbHelper's constructor is
* very lightweight, we are safe to perform that initialization here.
*/
// TODO (2) Within onCreate, instantiate our mOpenHelper
mOpenHelper = new WeatherDbHelper(getContext());
// TODO (3) Return true from onCreate to signify success performing setup
return false;
return true;
}
/**
@@ -88,11 +169,100 @@ public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) {
@Override
public Cursor query(@NonNull Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
throw new RuntimeException("Student, implement the query method!");
Cursor cursor;
// TODO (9) Handle queries on both the weather and weather with date URI
/*
* Here's the switch statement that, given a URI, will determine what kind of request is
* being made and query the database accordingly.
*/
switch(sUriMatcher.match(uri)){
/*
* When sUriMatcher's match method is called with a URI that looks EXACTLY like this
*
* content://com.example.android.sunshine/weather/
*
* sUriMatcher's match method will return the code that indicates to us that we need
* to return all of the weather in our weather table.
*
* In this case, we want to return a cursor that contains every row of weather data
* in our weather table.
*/
case CODE_WEATHER:{
cursor = mOpenHelper.getReadableDatabase().query(
/* Table we are going to query */
WeatherContract.WeatherEntry.TABLE_NAME,
/*
* A projection designates the columns we want returned in our Cursor.
* Passing null will return all columns of data within the Cursor.
* However, if you don't need all the data from the table, it's best
* practice to limit the columns returned in the Cursor with a projection.
*/
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
break;
}
/*
* When sUriMatcher's match method is called with a URI that looks something like this
*
* content://com.example.android.sunshine/weather/1472214172
*
* sUriMatcher's match method will return the code that indicates to us that we need
* to return the weather for a particular date. The date in this code is encoded in
* milliseconds and is at the very end of the URI (1472214172) and can be accessed
* programmatically using Uri's getLastPathSegment method.
*
* In this case, we want to return a cursor that contains one row of weather data for
* a particular date.
*/
case CODE_WEATHER_WITH_DATE:{
/*
* In order to determine the date associated with this URI, we look at the last
* path segment. In the comment above, the last path segment is 1472214172 and
* represents the number of seconds since the epoch, or UTC time.
*/
String normalizedUtcDateString = uri.getLastPathSegment();
/*
* The query method accepts a string array of arguments, as there may be more
* than one "?" in the selection statement. Even though in our case, we only have
* one "?", we have to create a string array that only contains one element
* because this method signature accepts a string array.
*/
String[] selectionArguments = new String[]{normalizedUtcDateString};
cursor = mOpenHelper.getReadableDatabase().query(
WeatherContract.WeatherEntry.TABLE_NAME,
projection,
/*
* The URI that matches CODE_WEATHER_WITH_DATE contains a date at the end
* of it. We extract that date and use it with these next two lines to
* specify the row of weather we want returned in the cursor. We use a
* question mark here and then designate selectionArguments as the next
* argument for performance reasons. Whatever Strings are contained
* within the selectionArguments array will be inserted into the
* selection statement by SQLite under the hood.
*/
WeatherContract.WeatherEntry.COLUMN_DATE + " = ? ",
selectionArgs,
null,
null,
sortOrder);
break;
}
default:
throw new UnsupportedOperationException("unknown uri: " + uri);
}
// TODO (10) Call setNotificationUri on the cursor and then return the cursor
cursor.setNotificationUri(getContext().getContentResolver(),uri);
return cursor;
}
/**

0 comments on commit c3b4810

Please sign in to comment.