1. 程式人生 > >udacity android 實踐筆記: lesson 4 part b

udacity android 實踐筆記: lesson 4 part b

tag hid cor use shift complete loader line 樣本

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