udacity android 實踐筆記: lesson 4 part b
udacity android 實踐筆記: lesson 4 part b
作者:幹貨店打雜的 /titer1 /Archimedes
出處:https://code.csdn.net/titer1
聯系:1307316一九六八(短信最佳)
聲明:本文採用以下協議進行授權: 自由轉載-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0 。轉載請註明作者及出處。
tips:https://code.csdn.net/titer1/pat_aha/blob/master/Markdown/android/
摘要
- 全然展示content provider加入的過程
- 動態展示android單元測試的過程
動圖出沒喔!o(^▽^)o。動圖在最後
overviw 圖
還是老圖,(create / insert /query)
以下 我們開始 content provider的學習
復習四大 組件
content provider
service
broadcast provider
actvity
本章 overview
4.07 init code for content provider
- 測試打樁函數就占了大半
- 然後傳統的函數裏面改動了 weatherContrace
- 添加了 weatherProvider
- 改動了 fetchweatherTask函數。代碼的來源是
從 forececastFragment代碼拆解出來的。
- 除了改動weatherContrace,其它文件都是 新添加的
關鍵詞 uri
weatherContract裏面添加的最多就是生成uri的函數
/* Inner class that defines the table contents of the location table */
public static final class LocationEntry implements BaseColumns {
...
public static Uri buildLocationUri(long id) {
return ContentUris.withAppendedId(CONTENT_URI, id);
}
}
===
/* Inner class that defines the table contents of the weather table */
public static final class WeatherEntry implements BaseColumns {
...
public static Uri buildWeatherLocation(String locationSetting) {
return null;
}
public static Uri buildWeatherLocationWithStartDate(
String locationSetting, long startDate) {
long normalizedDate = normalizeDate(startDate);
return CONTENT_URI.buildUpon().appendPath(locationSetting)
.appendQueryParameter(COLUMN_DATE, Long.toString(normalizedDate)).build();
}
public static Uri buildWeatherLocationWithDate(String locationSetting, long date) {
return CONTENT_URI.buildUpon().appendPath(locationSetting)
.appendPath(Long.toString(normalizeDate(date))).build();
}
public static String getLocationSettingFromUri(Uri uri) {
return uri.getPathSegments().get(1);
}
public static long getDateFromUri(Uri uri) {
return Long.parseLong(uri.getPathSegments().get(2));
}
public static long getStartDateFromUri(Uri uri) {
String dateString = uri.getQueryParameter(COLUMN_DATE);
if (null != dateString && dateString.length() > 0)
return Long.parseLong(dateString);
else
return 0;
}
}
}
4.08 uri location with weather
僅2處更新
1/2 weatherContract
/*
Student: This is the buildWeatherLocation function you filled in.
*/
public static Uri buildWeatherLocation(String locationSetting) {
return CONTENT_URI.buildUpon().appendPath(locationSetting).build();//上一版本號這裏返回空值
}
##2/2 test
只打開 這裏的凝視
“` java
/*
Students: This is NOT a complete test for the WeatherContract — just for the functions
that we expect you to write.
*/
public class TestWeatherContract extends AndroidTestCase {
// intentionally includes a slash to make sure Uri is getting quoted correctly
private static final String TEST_WEATHER_LOCATION = "/North Pole";
private static final long TEST_WEATHER_DATE = 1419033600L; // December 20th, 2014
/*
Students: Uncomment this out to test your weather location function.
*/
public void testBuildWeatherLocation() {
Uri locationUri = WeatherContract.WeatherEntry.buildWeatherLocation(TEST_WEATHER_LOCATION);
assertNotNull("Error: Null Uri returned. You must fill-in buildWeatherLocation in " +
"WeatherContract.",
locationUri);
assertEquals("Error: Weather location not properly appended to the end of the Uri",
TEST_WEATHER_LOCATION, locationUri.getLastPathSegment());
assertEquals("Error: Weather location Uri doesn‘t match our expected result",
locationUri.toString(),
"content://com.example.android.sunshine.app/weather/%2FNorth%20Pole");
}
}
“`
4.09 write uri matcher
1/2 weatherProvider
這是框架裏面的代碼,更新一處
/*
Students: Here is where you need to create the UriMatcher. This UriMatcher will
match each URI to the WEATHER, WEATHER_WITH_LOCATION, WEATHER_WITH_LOCATION_AND_DATE,
and LOCATION integer constants defined above. You can test this by uncommenting the
testUriMatcher test within TestUriMatcher.
*/
static UriMatcher buildUriMatcher() {
// I know what you‘re thinking. Why create a UriMatcher when you can use regular
// expressions instead? Because you‘re not crazy, that‘s why.
// All paths added to the UriMatcher have a corresponding code to return when a match is
// found. The code passed into the constructor 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);
final String authority = WeatherContract.CONTENT_AUTHORITY;
// For each type of URI you want to add, create a corresponding code.
matcher.addURI(authority, WeatherContract.PATH_WEATHER, WEATHER);
matcher.addURI(authority, WeatherContract.PATH_WEATHER + "/*", WEATHER_WITH_LOCATION);
matcher.addURI(authority, WeatherContract.PATH_WEATHER + "/*/#", WEATHER_WITH_LOCATION_AND_DATE);
matcher.addURI(authority, WeatherContract.PATH_LOCATION, LOCATION);
return matcher;
}
2/2 test
依舊是已經寫好的測試代碼框架,這裏只打開凝視
public class TestUriMatcher extends AndroidTestCase {
...
/*
Students: This function tests that your UriMatcher returns the correct integer value
for each of the Uri types that our ContentProvider can handle. Uncomment this when you are
ready to test your UriMatcher.
*/
public void testUriMatcher() {
UriMatcher testMatcher = WeatherProvider.buildUriMatcher();
assertEquals("Error: The WEATHER URI was matched incorrectly.",
testMatcher.match(TEST_WEATHER_DIR), WeatherProvider.WEATHER);
assertEquals("Error: The WEATHER WITH LOCATION URI was matched incorrectly.",
testMatcher.match(TEST_WEATHER_WITH_LOCATION_DIR), WeatherProvider.WEATHER_WITH_LOCATION);
assertEquals("Error: The WEATHER WITH LOCATION AND DATE URI was matched incorrectly.",
testMatcher.match(TEST_WEATHER_WITH_LOCATION_AND_DATE_DIR), WeatherProvider.WEATHER_WITH_LOCATION_AND_DATE);
assertEquals("Error: The LOCATION URI was matched incorrectly.",
testMatcher.match(TEST_LOCATION_DIR), WeatherProvider.LOCATION);
}
···
4.10 register content provider
1/2
這裏只使能(打開凝視) testProviderRegistry
public class TestProvider extends AndroidTestCase {
...
/*
This test checks to make sure that the content provider is registered correctly.
Students: Uncomment this test to make sure you‘ve correctly registered the WeatherProvider.
*/
public void testProviderRegistry() {
PackageManager pm = mContext.getPackageManager();
// We define the component name based on the package name from the context and the
// WeatherProvider class.
ComponentName componentName = new ComponentName(mContext.getPackageName(),
WeatherProvider.class.getName());
try {
// Fetch the provider info using the component name from the PackageManager
// This throws an exception if the provider isn‘t registered.
ProviderInfo providerInfo = pm.getProviderInfo(componentName, 0);
// Make sure that the registered authority matches the authority from the Contract.
assertEquals("Error: WeatherProvider registered with authority: " + providerInfo.authority +
" instead of authority: " + WeatherContract.CONTENT_AUTHORITY,
providerInfo.authority, WeatherContract.CONTENT_AUTHORITY);
} catch (PackageManager.NameNotFoundException e) {
// I guess the provider isn‘t registered correctly.
assertTrue("Error: WeatherProvider not registered at " + mContext.getPackageName(),
false);
}
}
}
androidManifest update
<provider
android:authorities="com.example.android.sunshine.app"
android:name=".data.WeatherProvider" />
小憩
添加provider布湊
- 預計要從 1代版本號代碼 和 2代代碼 進行比較
聰明的編譯器
智能提示
android 在debug模式下,有非常有趣的話題在裏面,比方變量值的提示
還有搜索字符時,主動過濾凝視裏面字符
test ok 單元測試的方法 && testPractise
而且 我沒有選右鍵觸發,而是直接 run ( shift f10)
(4a-28 )裏面單元測試的方法。全然能夠復現
- 展現執行的配置
- 展示出錯情形怎樣定位錯誤
- 展示正常情況
使用的是 sunshine version2 的4.02的代碼。code: testPractise
todo 實踐後思考
空白的android testproject是怎樣的?
4.02章節裏面。命名唯獨有效的3個testcase,怎麽顯示有6個testcase ?
testDb之testCreateDb
4.04 (git version) delete the testPractise,
實際執行記錄:
我在全部的 assertTrue,assertFalse,assertEqual
位置都下了斷點,可是唯獨testDb中的testCreateDb 被觸發。
數字上。run窗體顯示的“6 of 6”ok,
但6個中的4個被觸發,
我懷疑這個6是不是顯示過時
testdb之testLocationTable
測試全然通過.
- 該函數完整的調用了db的操作函數
- insert
- query
而且有趣的是調用了TestUtilities.validateCurrentRecord。
(這裏面還有2個assert,這裏面的斷言最終被觸發了)
這是我觀察中
testUtilities類中函數的第一次調用。
上一輪。我在這個類的static函數裏面設置斷點。
都沒有被調用。
還有這個類testUtilities提供了數據庫插入的樣本數據
todo
實踐後思考:
既然單元測試都是利用AndroidTestCase
那麽為什麽每次都是testDb被調用,
而其它AndroidTestCase的繼承類testUtilities 沒有被直接調用.
testWeatherTable 和重構 testLocationTable
4.06 lesson,
而且有趣的是前者內部調用調用了
locationTable的內容
居然全部的測試通過了
todo 內容深入分析
// Fifth Step: Validate the location Query
TestUtilities.validateCurrentRecord("testInsertReadDb weatherEntry failed to validate",
weatherCursor, weatherValues);
小憩
github 前6個小節,就是認識單元測試
單元測試的魔力非常大啊。這裏
興許
from 4.06 -4.10 (github)
測試函數有:
- test weatherContract
- test uri matcher
- test Provider
- test providerRegistery
構造一個content provider,每個模塊都不能馬虎
晚安 小憩
至少方向是光明的
下一天 復習
解釋 前面 為什麽 不是 全部的uri都被命中
再看 weather provider 和 testProvider的演示
作者是逐一功能的enable,逐一測試。逐漸深入
差點兒每種testProvider的函數(query/getType/insert/updat)
都含有uri matcher的篩選
新近發現 能夠 查看 每個測試的內容:
video 4b-24 是個階段總結
bulkinsert 事實上利用了事務,唯獨endtrancsation 才執行操作
小節
小節:整章節 就是 uri 使用
- define uri
- update uri(feflect to number)
- uri matcher (I think ,here addmatch)
- implement (I think, sUriMatcher.match(uri);)
說到。開源非常多 封裝了 content provider ?
toco
怎樣理解 notification oserver ..here
整合
至此。我們的content provider 還沒有和 database 聯合起來。
操作不是 test*.java,也不主要是 weatherprovider裏面
我們將精力集中到 FetchweatherTask
- addlocation
- getWeatherDataFromJson insert + query part
(網絡收報後的處理例程)
看到凡是使用了getContentResolver的地方,都是利用了contentprovider的地方,
最後
為了ui theread 更加流暢,引出Loader
至此,我們的video 來到4b的借書,代碼
代碼範圍是:
todo 附code
小節
android 你好
android 再見
呵呵。本博客android暫停更新。假設有興趣能夠短信聯系
udacity android 實踐筆記: lesson 4 part b