面向大眾的移動(dòng)技術(shù):簽名,封裝和發(fā)布Android app
面向大從的移動(dòng)打樁其它四篇文章地址(校對(duì)添加):
(一)、android簡(jiǎn)介;
(三)、Android 應(yīng)用程序生命周期中的活動(dòng)與圖標(biāo);
(四)、Overheard Word 的單詞和手勢(shì)。
添加一個(gè)多選擇quiz到你的Android手機(jī)app,然后用一個(gè)安全數(shù)字證書簽名
用網(wǎng)絡(luò)邏輯,內(nèi)容為王。但是對(duì)與手機(jī)用戶來(lái)說(shuō),交互規(guī)則才是王道。對(duì)移動(dòng)app靜態(tài)信息設(shè)計(jì)在減少,并且游戲化正在增多。這個(gè)月 Andrew Glover決定通過將一個(gè)多選擇的quiz特性加入到一個(gè)示例app(Overheard Word,前一篇介紹的。) 中來(lái)介紹 Android移動(dòng)開發(fā)。之后他將展示給你如何生成一個(gè)數(shù)字證書和如何發(fā)布和如何提升你的在Google Play或者Amazon Appstore上 已經(jīng)簽名的app。
目前為止在這個(gè)Mobil for the masses系列中,我們已經(jīng)使用Android作為學(xué)習(xí)怎樣做移動(dòng)開發(fā)的一個(gè)實(shí)例,其中包括 《Android應(yīng)用程序生命周期》教程,在你的Android apps中實(shí)現(xiàn)《手勢(shì)滑動(dòng)功能》。并且《與第三方庫(kù)工作》來(lái)簡(jiǎn)化開發(fā)并且增強(qiáng)app功 能。當(dāng)我不確定做Android時(shí)候,我對(duì)瀏覽其它的手機(jī)環(huán)境和技術(shù)感興趣。所以這個(gè)月我們來(lái) 通過添加一個(gè)quiz特性到Overheard Word 示例app 總結(jié)我們的 Android-intensive(加強(qiáng)安卓)文章 并且準(zhǔn)備部署它到兩個(gè)流行的 Adroid app stores:Google Play和Amazon Appstore。所有的這些將是下一節(jié)的基礎(chǔ):HTML5侵襲移動(dòng)開發(fā)!
游戲化我的app
在我們簽名Overheard Word并且把它推送到Google Play和Amazon Appstore的Android市場(chǎng)同數(shù)百萬(wàn)的其 它apps競(jìng)爭(zhēng)前,我想要確定它是***的Overheard Word app(對(duì)我們的Overheard Word app不熟悉么?回顧下介紹這 個(gè) 示例 的文章)。如你所知,游戲是當(dāng)前推動(dòng)移動(dòng)生態(tài)系統(tǒng)的強(qiáng)勁動(dòng)力,并且一系列的apps都被期望有高效的交互。移動(dòng)apps即使當(dāng)他們的目標(biāo)是提供 信息價(jià)值的時(shí)候,點(diǎn)燃好奇心和獲勝的欲望的移動(dòng)應(yīng)用也做的很好。那也是為什么Overheard Word 不僅僅只是一個(gè)頁(yè)面上的單詞列表;相反,它被 設(shè)計(jì)用來(lái)煽動(dòng)讀者來(lái)挖掘詞匯量,接著獎(jiǎng)勵(lì)他們來(lái)堅(jiān)持學(xué)習(xí)它!(順便說(shuō)下Gamification 游戲化 是一個(gè)正在開始流行的設(shè)計(jì)技術(shù)的術(shù)語(yǔ))
在我們簽名Overheard Word并且把它推送到Google Play和Amazon Appstore的Android市場(chǎng)同數(shù)百萬(wàn)的其它 apps競(jìng)爭(zhēng)前,我想要確定它是***的Overheard Word app(對(duì)我們的Overheard Word app不熟悉么?回顧下介紹這 個(gè) 示例 的文章)。如你所知,游戲是當(dāng)前推動(dòng)移動(dòng)生態(tài)系統(tǒng)的強(qiáng)勁動(dòng)力,并且一系列的apps都被期望有高效的交互。移動(dòng)apps即使當(dāng)他們的目標(biāo)是提供 信息價(jià)值的時(shí)候,點(diǎn)燃好奇心和獲勝的欲望的移動(dòng)應(yīng)用也做的很好。那也是為什么Overheard Word 不僅僅只是一個(gè)頁(yè)面上的單詞列表;相反,它被 設(shè)計(jì)用來(lái)煽動(dòng)讀者來(lái)挖掘詞匯量,接著獎(jiǎng)勵(lì)他們來(lái)堅(jiān)持學(xué)習(xí)它!(順便說(shuō)下Gamification 游戲化 是一個(gè)正在開始流行的設(shè)計(jì)技術(shù)的術(shù)語(yǔ))
在我們簽名Overheard Word并且把它推送到Google Play和Amazon Appstore的Android市場(chǎng)同數(shù)百萬(wàn)的其它 apps競(jìng)爭(zhēng)前,我想要確定它是***的Overheard Word app(對(duì)我們的Overheard Word app不熟悉么?回顧下介紹這 個(gè) 示例 的文章)。如你所知,游戲是當(dāng)前推動(dòng)移動(dòng)生態(tài)系統(tǒng)的強(qiáng)勁動(dòng)力,并且一系列的apps都被期望有高效的交互。移動(dòng)apps即使當(dāng)他們的目標(biāo)是提供 信息價(jià)值的時(shí)候,點(diǎn)燃好奇心和獲勝的欲望的移動(dòng)應(yīng)用也做的很好。那也是為什么Overheard Word 不僅僅只是一個(gè)頁(yè)面上的單詞列表;相反,它被 設(shè)計(jì)用來(lái)煽動(dòng)讀者來(lái)挖掘詞匯量,接著獎(jiǎng)勵(lì)他們來(lái)堅(jiān)持學(xué)習(xí)它!(順便說(shuō)下Gamification 游戲化 是一個(gè)正在開始流行的設(shè)計(jì)技術(shù)的術(shù)語(yǔ))
Overheard Word探詢
我們將啟動(dòng)正定義的一個(gè)新的布局來(lái)使Overheard Word的測(cè)試視圖保持一致,接下來(lái)我們定義一個(gè)來(lái)展示布局的Activity。正如前文所說(shuō),我正使用Eclipse的ADT作為我的開發(fā)環(huán)境,我假設(shè)你也是使用它。
我們將啟動(dòng)正定義的一個(gè)新的布局來(lái)使Overheard Word的測(cè)試視圖保持一致,接下來(lái)我們定義一個(gè)來(lái)展示布局的Activity。正如前文所說(shuō),我正使用Eclipse的ADT作為我的開發(fā)環(huán)境,我假設(shè)你也是使用它。
Figure 1. Creating a new layout in Eclipse
我們將啟動(dòng)正定義的一個(gè)新的布局來(lái)使Overheard Word的測(cè)試視圖保持一致,接下來(lái)我們定義一個(gè)來(lái)展示布局的Activity。正如前文所說(shuō),我正使用Eclipse的ADT作為我的開發(fā)環(huán)境,我假設(shè)你也是使用它。
下一步,拷貝下面的XML到你的新文件。
Listing 1. Quiz layout for Overheard Word
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".OverheardWord" >
- <LinearLayout
- android:id="@+id/widget33"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_marginLeft="20dp"
- android:orientation="vertical" >
- <TextView
- android:id="@+id/quiz_definition"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="20dp"
- android:layout_marginLeft="13dp"
- android:layout_marginRight="10dp"
- android:layout_marginTop="48dp"
- android:text="Definition"
- android:textSize="18sp" />
- <RadioGroup
- android:id="@+id/quiz_answers"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="17dp" >
- <RadioButton
- android:id="@+id/quiz_answer_1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Answer 1" />
- <RadioButton
- android:id="@+id/quiz_answer_2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Answer 2" />
- <RadioButton
- android:id="@+id/quiz_answer_3"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Answer 3" />
- </RadioGroup>
- <TextView
- android:id="@+id/quiz_result"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="10dp"
- android:layout_marginLeft="40dp"
- android:layout_marginTop="20dp"
- android:lines="2"
- android:text="Result"
- android:textSize="18sp" />
- <TextView
- android:id="@+id/quiz_number"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginRight="10dp"
- android:layout_marginTop="30dp"
- android:gravity="right"
- android:text="1/10" />
- </LinearLayout>
- </RelativeLayout>
Overheard Word的存在的布局文件定義了學(xué)習(xí)指南的UI,此布局定義了一系列UI元素樣例文本,目的是你們能夠得到一個(gè)想法 當(dāng)你的 app上線時(shí)東西是怎么樣的。這測(cè)試的布局包括一個(gè)保存詳細(xì)定義的TextView和一個(gè)用來(lái)各種適合那個(gè)定義單詞的RadioGroup。當(dāng)用戶選擇一 個(gè)單詞,提交一個(gè)新問題或再試一次的機(jī)會(huì)時(shí)候,app將立即通知一個(gè)事件并相應(yīng),也有通過這個(gè)小測(cè)試跟蹤用戶進(jìn)程的計(jì)數(shù)器。
我們下一步是創(chuàng)建一個(gè)新的Activity類。這個(gè)類應(yīng)該繼承Activity類且提供一個(gè)onCreate方法,如Listing2所示。(注意, setContentView指定那個(gè)Listing1創(chuàng)建的新布局文件)
Listing 2. New Activity class: OverheardQuiz
- import android.app.Activity;
- import android.os.Bundle;
- public class OverheardQuiz extends Activity {
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_overheard_quiz);
- }
- }
我們下一步是實(shí)例一個(gè)新Activity,這將最終顯示Overheard word的測(cè)試布局。不僅僅創(chuàng)建一個(gè)可選菜單項(xiàng),讓我們嘗試用手勢(shì)滑動(dòng)功能來(lái)啟動(dòng)一個(gè)測(cè)試。稍后我們也會(huì)把a(bǔ)pp菜單加到測(cè)試中。
Intents編程
正如我們之前討論的,一個(gè)Android設(shè)備極其受電池時(shí)間周期、執(zhí)行能力和內(nèi)存的約束,大多數(shù)個(gè)人設(shè)備也有許多像電話和文本特性的apps,所以 同時(shí)他們有多個(gè)激活的程序運(yùn)行。Android平臺(tái)通過給作為開發(fā)者的你在任何時(shí)間使你的app應(yīng)用處于某些約束中來(lái)管理程序。例如,你不能強(qiáng)迫一個(gè) Activity類啟動(dòng)并且顯示它的視圖。而是,你要通過給activity發(fā)送給平臺(tái)一個(gè)intent來(lái)啟動(dòng)。平臺(tái)會(huì)在能啟動(dòng)Activity的時(shí)候啟 動(dòng)它。
想象一個(gè)Intent是一個(gè)異步執(zhí)行任務(wù)的機(jī)制。從用戶角度看,你建議平臺(tái)應(yīng)該做一些事情并且它能做的時(shí)候它立刻做了。
所以不能僅僅啟動(dòng)我們的Activity,我們需要把它包裝在一個(gè)Intent里。之后Android將為我們啟動(dòng)Activity。由于我們正在 用手勢(shì)啟動(dòng)一個(gè)新的測(cè)試Activity,我們將把intent插到一個(gè)GestureDetector實(shí)例。(這系列中更多關(guān)于 GestureDetector看 前兩篇文章)在isUpSwip條件中不是只能返回false,我們會(huì)發(fā)送那樣的一個(gè)新Intent:
Listing 3. Adding the new Activity to GestureDetector
- //.....
- if (detector.isDownSwipe()) {
- return false;
- } elseif (detector.isUpSwipe()) {
- startActivity(new Intent(getApplicationContext(), OverheardQuiz.class));
- } elseif (detector.isLeftSwipe()) {
- //.....
注意 一個(gè)Intent接受一個(gè)上下文和一個(gè)你希望啟動(dòng)的類,startActivity 是Activity實(shí)例的方法。
試一試,啟動(dòng)你的模擬器實(shí)例,當(dāng)顯示一個(gè)單詞時(shí)候向上滑。你應(yīng)該看到一個(gè)新Activity,如Figure2。
Figure 2. A quiz is born!
試一試,啟動(dòng)你的模擬器實(shí)例,當(dāng)顯示一個(gè)單詞時(shí)候向上滑。你應(yīng)該看到一個(gè)新Activity出現(xiàn)在Figure2那樣
上滑,下滑
我們首先要做的就是添加一個(gè)手勢(shì)檢測(cè)以便能夠讓用戶離開這測(cè)試并回到學(xué)習(xí)單詞。由于上滑是讓用戶進(jìn)入到測(cè)驗(yàn),憑直覺下滑是離開測(cè)驗(yàn)比較好。我們調(diào)用finish來(lái)退出測(cè)驗(yàn)Activity回到學(xué)習(xí)模式。
Listing 4. Calling finish inside a swipe gesture
- private GestureDetector initGestureDetector() {
- return new GestureDetector(new SimpleOnGestureListener() {
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- try {
- final SwipeDetector detector = new SwipeDetector(e1, e2, velocityX, velocityY);
- if (detector.isDownSwipe()) {
- finish();
- } else if (detector.isUpSwipe()) {
- return false;
- } else if (detector.isLeftSwipe()) {
- return false;
- } else if (detector.isRightSwipe()) {
- return false;
- }
- } catch (Exception e) {
- // nothing
- }
- return false;
- }
- });
- }
上篇文章說(shuō)過,我們?cè)贠verheard Word里的學(xué)習(xí)Activity中實(shí)現(xiàn)了一個(gè)操作欄,用來(lái)我們退出app。這里我們重用那段代碼來(lái)創(chuàng)建新的測(cè)驗(yàn)退出函數(shù)。
Listing 5. An action bar to quit the quiz
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.overheard_quiz, menu);
- return true;
- }
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.quit_quiz:
- this.finish();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
注意 我們并不想退出我們的app,只是離開測(cè)驗(yàn);所以我們更新了操作欄文本‘退出測(cè)試’而不是‘退出’。
單詞和定義
下一步,我們?cè)O(shè)定一個(gè)有一個(gè)正確答案和兩個(gè)錯(cuò)誤答案的定義。由于我們使用Thingamejig來(lái)處理邏輯,我們唯一需要做的就是輸入相關(guān)字段,如Listing6所示:
Listing 6. Setting up a testable word with definitions
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_overheard_quiz);
- initializeGestures();
- List<Word> words = buildWordList();
- if (engine == null) {
- engine = WordTestEngine.getInstance(words);
- }
- final TestableWord firstWord = engine.getTestableWord();
- final TextView testDefinition = (TextView)findViewById(R.id.quiz_definition);
- testDefinition.setText(formatDefinition(firstWord.getValidDefinition()));
- final List<String> possibleAnswers = possibleAnswersFrom(firstWord);
- final int[] radios = { R.id.quiz_answer_1, R.id.quiz_answer_2, R.id.quiz_answer_3 };
- for (int x = 0; x < radios.length; x++) {
- final RadioButton rButton = (RadioButton)findViewById(radios[x]);
- rButton.setText(possibleAnswers.get(x));
- }
- }
在Listing 5 中,onCreate方法先構(gòu)建我們提供的基礎(chǔ)視圖。下一步,初始化手勢(shì)。就像原來(lái)學(xué)習(xí)Activity那樣工作,一個(gè) WordTestEngine(而不是WordStudyEngine)被實(shí)例化且鏈接到Overheard Word的單詞存儲(chǔ)(這個(gè)例子中是JSON 文件)。possibleAnswersForm方法返回一個(gè)有三個(gè)定義其中一個(gè)正確定義的列表,為了使測(cè)驗(yàn)不是一直顯示相同順序 WordTestEngine實(shí)例會(huì)打亂定義順序。
最終,循環(huán)輸入匹配所給定義的單詞到我們的RadioButtons。如果你啟動(dòng)app實(shí)例,你將會(huì)看到一個(gè)漂亮的 有著一個(gè)單詞定義和三個(gè)單詞選項(xiàng)的表單測(cè)驗(yàn)接口。
Figure 3. The quiz UI with words and a definition
還有注意在屏幕底部有個(gè)靜態(tài)Result按鈕和一個(gè)顯示所有的測(cè)驗(yàn)問題數(shù)量的計(jì)數(shù)器,截圖中10個(gè)問題已經(jīng)使用了1個(gè)。
目前為止,我們使用Thingamejig和一些原來(lái)的Activity邏輯快速創(chuàng)建了測(cè)驗(yàn)的樣本邏輯。接下來(lái)我們將手動(dòng)處理測(cè)驗(yàn)的單選框的按鈕部 分。我們回調(diào)到單選按鈕組的行為并且監(jiān)聽什么時(shí)候選項(xiàng)被選,而不需要用戶額外多點(diǎn)擊按鈕(類似提交)來(lái)表明選中選項(xiàng)。這種方式用戶不需要額外操作就立即得 到反饋。
處理事件調(diào)度
我提到我想要基于他們的單詞選項(xiàng)來(lái)提供立即反饋。還有,我還想程序Overheard Word 對(duì)于反饋可以短暫的暫停。如果用戶給了一個(gè)正確的 回應(yīng),我想他或她在進(jìn)入下一題前有幾秒中來(lái)體會(huì)這種感覺。如果回答錯(cuò)誤,我應(yīng)該讓他們?cè)僭嚮蛘弑3忠粌擅牒笤亠@示正確答案。任何方式,用戶都有機(jī)會(huì)了解他 們?cè)跍y(cè)驗(yàn)中的操作。
但是記住,我們不僅做一些我們喜歡的Android app;沒有強(qiáng)迫app隨時(shí)睡眠或啟動(dòng)線程。(在Android app中啟動(dòng)線程是可能的, 當(dāng)然,但是各種相關(guān)因素是不受控制的。)就像我們使用Intents來(lái)告訴Android app 我們意圖讓它有怎樣的行為,我們用Handlers來(lái) 指示我們渴望推遲或立即執(zhí)行;Android怎樣處理請(qǐng)求是Android的事了。
請(qǐng)暫停
在Android中,你使用Handlers來(lái)處理事件調(diào)度,并且也通過線程間傳遞信息。這種情況,我們將一直用Handlers調(diào)度一個(gè)事件,它將是一個(gè)密封的Runnable實(shí)例。
在響應(yīng)用戶選中一個(gè)單詞的事件中,我們將創(chuàng)建一個(gè)Handler實(shí)例,在Runnable內(nèi)部傳遞某寫邏輯(如展示一個(gè)新的Activity)并且設(shè)置幾秒延遲。
我們實(shí)現(xiàn)onCheckedChangeListener監(jiān)聽附加到RadioGroup上來(lái)回調(diào)敲擊單選按鈕,如下所示:Listing 7
Listing 7. setOnCheckedChangeListener
- final RadioGroup group = (RadioGroup)findViewById(R.id.quiz_answers);
- group.setOnCheckedChangeListener(new OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(final RadioGroup group, final int checkedId) {
- final RadioButton selected = (RadioButton)findViewById(checkedId);
- final String answer = (String) selected.getText();
- if (answer.equals(firstWord.getSpelling())) {
- final TextView result = (TextView)findViewById(R.id.quiz_result);
- result.setTextColor(Color.parseColor("#228b22"));
- result.setText("Correct!");
- final Handler handler = new Handler();
- handler.postDelayed(new Runnable() {
- public void run() {
- final Intent nextQuiz = new Intent(getApplicationContext(), OverheardQuiz.class);
- startActivity(nextQuiz);
- result.setText("");
- finish();
- }
- }, 2500);
- } else {
- final TextView result = (TextView)findViewById(R.id.quiz_result);
- result.setTextColor(Color.parseColor("#ff0000"));
- result.setText("Nope, that's not it! Try again.");
- final Handler handler = new Handler();
- handler.postDelayed(new Runnable() {
- public void run() {
- selected.setChecked(false);
- result.setText("");
- }
- }, 2000);
- }
- }
- });
正如JavaAWT或Swing的傳統(tǒng)GUI編程,你能添加事件監(jiān)聽。例子中,我們就正在添加一 個(gè) OnCheckedChangeListener 到RadioGroup。當(dāng)用戶選擇一個(gè)RadioButton時(shí),監(jiān)聽代碼會(huì)執(zhí)行。如果用戶選擇 正確,新實(shí)例OverheardQuizActivity會(huì)顯示一個(gè)新單詞。用戶也可以在TextView中得到友好的‘正確’的綠色文本信息。
如果用戶選擇錯(cuò)誤,信息文本是紅色的,Activity的UI會(huì)重置讓用戶再次嘗試。
也要注意兩個(gè)Handler實(shí)例延遲啟動(dòng)線程,一個(gè)是因?yàn)橐陆ㄒ粋€(gè)Intent啟動(dòng),另一個(gè)是UI重置。
你也需要?jiǎng)h除在Listing 1 中定義的測(cè)驗(yàn)布局的默認(rèn)的文本。只需回到XML文件并且從ID為quiz_result的TextView中刪除
android:text=”Result”。現(xiàn)在啟動(dòng)你的app并檢測(cè)!
Android中的Bundles
接著我們要做的事情是給測(cè)驗(yàn)視圖右下角的計(jì)數(shù)器添加一些邏輯(看Figure 3)。對(duì)于測(cè)驗(yàn)從用戶的角度觀察,我們想要展示他們的進(jìn)度給他或她, 像還有多少問題。為了我們的計(jì)數(shù)器能工作,我們需要一個(gè)保持計(jì)數(shù)器的狀態(tài)(例如它之前是2,且現(xiàn)在它應(yīng)該是3),這就需要我們能從一個(gè)activity到 另一個(gè)之間傳遞數(shù)據(jù),我們用Bundles來(lái)做這個(gè)任務(wù)。
如果你已經(jīng)讀了一段時(shí)間這個(gè)系列,那么你已經(jīng)接觸過Bundles了,因?yàn)橐粋€(gè)Bundles實(shí)例是每個(gè)Activity的onCreate方法的長(zhǎng)參數(shù)。
Bundles必須是一個(gè)鍵-值對(duì)的Maps。你能通過方法調(diào)用鍵的值檢索一致的值類型。除了Activity實(shí)例外,Bundles也被包括在 Intents中,實(shí)際上,如果你放一個(gè)新Activity鍵-值對(duì)到Intent關(guān)聯(lián)關(guān)系中,你就能通過那個(gè)Intent檢索Bundle得到創(chuàng)建的那 個(gè)Activity。這些聽起來(lái)可能很繞,但親自做一次就理解了。
創(chuàng)建計(jì)數(shù)器
首先,我們更新創(chuàng)建新的OverheardQuizActivity的Handler,添加一個(gè)遞增的計(jì)數(shù)器,如下Listing 8所示:
Listing 8. Adding an incremented counter
- final Handler handler = new Handler();
- handler.postDelayed(new Runnable() {
- public void run() {
- final Intent nextQuiz = new Intent(getApplicationContext(), OverheardQuiz.class);
- nextQuiz.putExtra(QUIZ_NUM, ++quizNumber);
- startActivity(nextQuiz);
- result.setText("");
- finish();
- }
- }, 2500);
putExtra 方法關(guān)聯(lián)著quizNumber增加的鍵值QUIZ_NUM,兩個(gè)都是OverheardQuiz類的成員變量。
下一步,我們更新OverheardQuiz類的onCreate方法從啟動(dòng)的那個(gè)Intent獲取這個(gè)值。(如果onCreate沒找到值,指定 它是1。原因是OverheardWordActivity***次被啟動(dòng)時(shí)候沒有設(shè)置QUIZ_NUM的值。如果這個(gè)值比10大,序列會(huì)重置,并且我們會(huì) 發(fā)送給用戶一個(gè)慶祝的信息(通過Toast)。
最終,我們將更新計(jì)數(shù)器的TextView為新的計(jì)數(shù)。全部代碼如下所示Listing 9.
Listing 9. Updating a TextView with the current count
- final Bundle previous = getIntent().getExtras();
- quizNumber = (previous != null) ? previous.getInt(QUIZ_NUM) : 1;
- if (quizNumber > 10) {
- quizNumber = 1;
- CharSequence text = "Great Job! You made it through 10 questions. Here's another 10!";
- Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG).show();
- }
- final TextView quizCounter = (TextView)findViewById(R.id.quiz_number);
- quizCounter.setText(quizNumber + " of 10");
現(xiàn)在 讓我們啟動(dòng)最終版Overheard Word來(lái)看看它怎么樣。
Figure 4. Overheard Word is munificent!
這樣,我認(rèn)為我們已經(jīng)成功親手做了個(gè)app:它能夠提供有價(jià)值的服務(wù)(快速內(nèi)部詞匯量構(gòu)建),直觀的接口,甚至現(xiàn)在它有個(gè)能反復(fù)拉回用戶的有趣的測(cè)驗(yàn)特性。UI可以更有趣(白底黑字比較討厭),但現(xiàn)在到了我們簽名并把它發(fā)到市場(chǎng)的時(shí)候了。
給你的Android app簽名
如果你想讓你的app能運(yùn)行在所有人的設(shè)備上,你需要把它部署到一個(gè)公共的app 商店。然而有許多可選,其中Android兩個(gè)***的app商店 是Google Play和Amazon Appstore(看 資料)。處于安全原因,兩個(gè)商店規(guī)定它們的apps都必須被作者簽名。
當(dāng)你注冊(cè)一個(gè)app,你創(chuàng)建一個(gè)你私有的證書。然后你用這個(gè)數(shù)字證書給你的代碼簽名。簽名是一種發(fā)布由你簽名而非某未知的、潛在惡意的一方的特別二 進(jìn)制的方法,Android設(shè)備不會(huì)安裝沒有簽名的app應(yīng)用,所以如果你想要成為一個(gè)Android開發(fā)者,你需要知道如何給你app簽名。
我之前展示的幾篇文章在Android設(shè)備上《如何安裝一個(gè)測(cè)試app》,實(shí)際上你用測(cè)試證書簽名。測(cè)試證書對(duì)測(cè)試來(lái)說(shuō)很好用,但公共的app商店不接受這個(gè)。這時(shí)你需要學(xué)習(xí)如何通過Eclipse生產(chǎn)一個(gè)真正的證書。
為了簽名這個(gè)app,去Eclipse ADT的項(xiàng)目菜單中,選擇‘Android Tools’ -> ‘Export Signed Application Package’。會(huì)彈出生成新證書向?qū)А?/p>
Figure 5. The Eclipse ADT certificate wizard
這個(gè)想到會(huì)指導(dǎo)你通過對(duì)話框一步步說(shuō)明你個(gè)人信息。如果你曾買過網(wǎng)站ssl證書,你會(huì)通過相似的過程。還有Android中沒有證書授權(quán)的過程。因此App簽名比SSL證書更容易,但是它欺詐的可能性也高;如,沒人能阻止我說(shuō)我是來(lái)自美國(guó)銀行或可口可樂的人員。
Figure 6. Identifying information for the certificate
在你完成創(chuàng)建證書和私鑰存儲(chǔ)(存儲(chǔ)你的私人密鑰),你就能導(dǎo)出一個(gè).apk擴(kuò)展名的app包,如下所示Figure 7.
Figure 7. OverheardWord.apk
一旦你的app有了數(shù)字簽名,至少?gòu)募夹g(shù)角度你可以自由的分發(fā)它到全世界。然而要發(fā)到公共的app商店只有簽名還不夠。你也需要提升它。
提升你的App
公共app商店只是提供一個(gè)全球市場(chǎng)的平臺(tái),但app市場(chǎng)中聰明的客戶不會(huì)下載舊的東西。就像你需要知道在構(gòu)建apps中包如何提供有價(jià)值的功能和 樂趣,你能誘惑用戶讓他嘗試。當(dāng)你上傳(或發(fā)布)一個(gè)Google Play或Amazon Appstore的Android app時(shí),你可以做一下 這些:
- 定義你的app的主要特性
- 長(zhǎng)短適中且?guī)в袠?biāo)記的描述你app
- 提供關(guān)鍵字來(lái)幫助提升被搜索幾率
- 上傳不同尺寸的你的app截圖
- 提供你的app操作視頻
當(dāng)然,你也需要決定是否你的應(yīng)用要免費(fèi)還是付費(fèi);并且你需要設(shè)置一個(gè)適當(dāng)?shù)膬r(jià)格、市場(chǎng)利率。的確,你可能發(fā)現(xiàn)構(gòu)建和簽名你的應(yīng)用是容易的部分,而在這個(gè)蓬勃發(fā)展、競(jìng)爭(zhēng)激烈的市場(chǎng)中推銷移動(dòng)app是一個(gè)很難的工作。
總結(jié)
正如你所知,本地的Android開發(fā)只是產(chǎn)生移動(dòng)appe的一個(gè)點(diǎn)。這個(gè)系列下一篇首先看看如何用HTML5來(lái)構(gòu)建移動(dòng)網(wǎng)絡(luò)app。以網(wǎng)絡(luò)為基礎(chǔ) 的移動(dòng)app提供一些比本地apps優(yōu)勢(shì)–像實(shí)際上你能發(fā)布它們到任何地方!但是基于網(wǎng)絡(luò)的apps不能像本地app那樣華麗而且未必能達(dá)到本地app相 同的表現(xiàn)。當(dāng)我們深入到HTML5中,我們會(huì)發(fā)現(xiàn)移動(dòng)Web app的樂趣和約束。