Android用のシンプルタイムマネージャー。 パート2

このパートでは、 最初のパートからTime Managerアプリケーションを完成させます。



ベルキンと、最初の部分に加えて、あなたが私を招待してくれたすべての人に感謝します)



当初意図したとおり、サービスの使用を拒否したという事実に注意を喚起したいと思います。 自分で判断して、タイマーを1秒ごとに増やすためだけにプロセスを開始するのは愚かです。 解決策は簡単です。各プログラムが停止する前に時間を節約し、開始後に現在の時間から減算して秒数を取得します。



アクションプラン:





すぐに謝罪して自慢したい)長い間待たせてしまったことを謝罪し、先日Androidが私に最初の井戸をもたらしたのを自慢し、すっごく良いお金で、私は喜んでxboxを買って週末中に失ったので、私は遅らせた)



さあ、行こう!





まず、 最初の部分を読むか、

私たち自身がすべてを理解するために、ナレーションの下でそれを書くか、

すべてが明確な場合は、最初の部分のソースをダウンロードしてください。

働く。

ソース(134 Kb)



開かれ、発射され、すべての消防士が収集して発射しました。



 [2010-03-12 09:12:15-TimeManager] Android Launch!
 [2010-03-12 09:12:15-TimeManager] adbは正常に実行されています。
 [2010-03-12 09:12:15-TimeManager]実行
 com.nixan.timemanager.Mainアクティビティの起動
 [2010-03-12 09:12:15-TimeManager]自動ターゲットモード:デバイスを使用
 「HT91MKV01100」
 [2010-03-12 09:12:15-TimeManager] TimeManager.apkのアップロード
デバイス「HT91MKV01100」
 [2010-03-12 09:12:15-TimeManager] TimeManager.apkのインストール...
 [2010-03-12 09:12:19-TimeManager]が原因で再インストールに失敗しました
異なるアプリケーション署名。
 [2010-03-12 09:12:19-TimeManager]完全なアンインストールを実行する必要があります
アプリケーションの。 警告:これにより、アプリケーションデータが削除されます!
 [2010-03-12 09:12:19-TimeManager] 'adb uninstallを実行してください
 com.nixan.timemanager 'シェルで。
 [2010-03-12 09:12:19-TimeManager]打ち上げがキャンセルされました!


私の場合、Eclipseはアプレットをインストールできないと誓いましたが、

既にインストールされているという事実のため。

簡単な説明:Eclipseでアプレットを収集し、その後に

インストールでは、アプリケーションはデバッグキーで署名され、インストール時に

市場-通常。 したがって、日食には削除する機能がありません

市場を通じてインストールされたアプリケーションなので、アンインストールする必要があります

手で。 ここではすべてが非常に簡単です-市場に行って削除します)、または

Eclipseが私たちに言ったことを行う-ターミナルでadbをする

<パッケージ名>をアンインストールします。

別の余談:adbは一般的に非常に便利なものです。

たとえば、データベースを操作することもできます。

スクリーンショットが撮られ、スクリーンキャストも撮られます。

youtubeが投稿されました。



したがって、アンインストールしてから、再度組み立ててインストールしてください。 すべてが機能するはずです

いいえ、エラーを探すか、ソースをダウンロードしてください。



バグ修正と改善



ツールを使用する日、私はそうではないが、画面の回転を実現しました

カウンターをオフにしますが、開始する直前にリセットします

プログラムにはリセットカウンターがなく、 Riotは同じバグを報告しました。 さあ、行きましょう。



バグ修正

参考のために、アクティビティのライフサイクルを開きます。 画面を回転させると、アプレットは

アクティビティを強制終了してから再起動します。 前回onCreate()に来たとき

タイマーが実行されているかどうか、およびそれらに何秒あるかの値のロードを追加しました

降りてきた。 ポイントは小さい-殺すときにアクティビティを保存するだけです

タイマー値。

 @Override
    public void onStop()
    {
   	 super.onStop();
		 stats_editor.putInt( "key_rest_time"、rest_time);
		 stats_editor.putInt( "key_work_time"、work_time);
		 stats_editor.commit();
   	
    }


super.onStop(); -行は親のonStop()メソッドを呼び出します。 もし

それはあなたに何も言わない、それについて何かを読むのはいいだろう

JavaのOOP。

stats_editor.putInt(); -前回話したとき、

しかし、再び、これらのメソッドはアプリケーション設定ファイルに入れられます。

キーを使用して変数、データを保存するために使用します。

stats_editor.commit(); -メソッドは変数を保存します

以前にputInt、putBoolean、putString ...などで記述された

良い方法で両方に開かれていることを覚えおくことが重要です

セットアップファイルの記録は1回のみ可能です。

設定付きの変数、コミット後()後になるリスクを負う

出力は最後の変数です。

commit()メソッドが呼び出されました。



私は少し噛んでいます:

設定には、2つの整数integer_oneと

integer_two、両方とも1に等しい。

 SharedPreferences.Editor stats_editor1 =
 PreferenceManager.getDefaultSharedPreferences(this).edit();
 SharedPreferences.Editor stats_editor2 =
 PreferenceManager.getDefaultSharedPreferences(this).edit();
 stats_editor1.putInt( "integer_one"、2);
 stats_editor2.putInt( "integer_two"、2);
 stats_editor1.commit();
 stats_editor2.commit();


出力でinteger_one == 1およびinteger_two == 2を取得するリスクがあります。



収集、立ち上げ、すべてが私のために働いた。



タイマーをリセットする機能を追加します。

デバイスの<>ボタンを押して呼び出されるメニューを作成する必要があります。

タイマーをリセットするボタンがあるはずです。

開始するには、ボタンを呼び出す必要があります。 前回の様子を覚えている

ファイルres / values / strings.xmlを編集し、そこに追加して

ローカライズされたファイルにローカライズしました。

 <string name = "button_reset">タイマーをリセット</ string>


私の文字列はbutton_resetと呼ばれます。

余談:今、あなたはの証拠を目撃しました

ローカライズは、行末で最も便利に行われます。 ただ

5行ではなく200行の奇数行があると推定します。



次に、メインで、これまで唯一のクラスで、2つのメソッドを追加する必要があります。

 public boolean onCreateOptionsMenu(メニューメニュー)


そして

 public boolean onOptionsItemSelected(MenuItemアイテム)


1つ目-メニューを生成し、2つ目はその要素をクリックします。



次に、メニューを生成するコードを記述します。

 MenuItem menuItem;
 menuItem = menu.add(Menu.NONE、Menu.NONE、Menu.NONE、R.string.button_reset);
 menuItem.setIcon(android.R.drawable.ic_menu_delete);
 return super.onCreateOptionsMenu(メニュー);


menuItem-変数にはメニュー内のボタン自体が含まれます。 最初に

線で示すだけです。

menu.add-まず、メソッド呼び出しから取得されます-見て、

そこに入力パラメーターとして示されています。次に、このメソッド

変数MenuItemに押し込んだMenuItem型を返します。

次の値がパラメーターに渡されます。

1.ボタンのグループ。 Menu.NONEがありますが、使用しません。

2.アイテムの識別子。 一般に、良い方法でどこにでも置く必要があります

異なる、コードのこの部分をループに入れて渡す最も簡単な方法

ループカウンターがあります。 クリックハンドラで理解するために必要な、

どのボタンをクリックしたか。

3.シーケンス。

4.ボタンの名前。 res / values / strings.xmlのbutton_resetを参照します。

setIcon-メニュー項目のアイコンを設定します。

ic_menu_delete.pngをフォルダーにアップロードしなかったことに注意してください

ドロアブル、および私たちがいつものように対処していないという事実-R.drawable、しかし

android.R.drawable。 これは、システムがこの画像を検索することを意味します。

システム自体の写真であり、特にアプリケーションの写真ではありません。

いつものように隠れ家。 ほとんどの写真を使用する理由

システム? 第一に、既にあるものを描画したり引き出したりする必要はありません。

長く描かれた。 第二に、これは最も理想的なオプションです

ガイドラインシステム。 第三に、例えば、私を見てみましょう

RoboJournal-LiveJournalのクライアント(市場で入手可能、再度検索

フレーズpub: "Nixan")。 1.5および1.6では、ポップアップのアニメーションは1つでしたが、

2.0で更新されました。 その結果、異なるシステムでは異なる

写真。



このケースをまとめて、何が起こったのか見てみましょう。



これが私のオプションです。



メニューをクリックするためのハンドラを書くことだけが完全な喜びです。



 if(休息)
 {
	 rest_timer.startAnimation(shrink_rest);
	 resting = false;
 }
 if(作業中)
 {
	 work_timer.startAnimation(shrink_work);
	 working = false;
 }
 rest_timer.setText( "0:00:00");
 work_timer.setText( "0:00:00");
 rest_time = 0;
 work_time = 0;
 stats_editor.putInt( "key_rest_time"、rest_time);
 stats_editor.putInt( "key_work_time"、work_time);
 stats_editor.commit();
 return super.onOptionsItemSelected(item);


1.カウンターを停止します。

2.タイマーのテキストをゼロにします。

3.カウンター自体をゼロにします。

4.含まれている設定をゼロにします。



わずかな最適化

私は告白しますが、カウンターのある行をString.format();で設定できることは頭から直接飛び出しました。

これを行うには、TimerTaskに進み、変数のリストからすべての文字列を削除し、秒と分の前にゼロが追加されているコードのセクションを削除します。

 rest_timer.setText(hours_ind_r + ":" + minutes_ind_r + ":" + seconds_ind_r);


に変更

 rest_timer.setText(String.format( "%d:%02d:%02d"、hours_r、minutes_r、seconds_r));




集めてみてください。 すべてが機能します!



アプリケーションを実行し続ける必要がなくなりました。



前述したように、この場合、サービスをブロックすることはお勧めできません。 私は議論しません、私は本当にこれについて何かを書きたかったのですが、私もある程度ハウツーをしなかったという事実)。 さらに 3fonovによるHabr 「おやすみ」に関するすばらしい記事があります。これは、サービスについて完全に説明しています。つまり、次の2つのタイプがあります。

1.作成、動作、停止。

2.接続し、接続アクティビティのコマンドでコードを実行し、停止しました。

3fonovは2番目の部分を詳細に説明しましたが、インターフェースとaidlファイルには非常に微妙な点があります。 最初のタイプでは、すべてが非常に簡単です。 たとえば、クラス、つまりそのonCreate()およびonDestroyメソッドを取り上げます。 そのようなサービスのすべての作業は、それらで行われます。

小さなギャグ。 どのタイプのサービスをどこで使用しますか?

2番目のタイプのサービスは、同じGoogleトークのように、サーバーとの非常にアクティブなユーザー通信を暗示するアプリケーションに非常に便利です。サービスは常にメモリにハングしています。 onBindコマンドを呼び出すことにより、Activityはこのサービスに接続し、たとえば誰がオンラインであるかを尋ねます。最後に更新したときにダウンロードしたデータでサービスが応答します。 同じチームには、おそらくメッセージを送信してステータスを設定できるメソッドがあります。 これの利点は、バックグラウンド作業とユーザーのために、このサービスで実装された1つのソケットと1つの接続を持っていることです。

私の意見では、最初のタイプは、ユーザーがサーバーに与える影響がはるかに少ないアプリケーション、つまりコンテンツ検索機能にとって非常に便利です。 現時点では、サービスがコンテンツを更新するためのTimerTaskのみを含むアプリケーションを作成しています。更新時には、すべての情報がローカルデータベースに保存され、インターフェイスの更新に関するブロードキャストメッセージ(Broadcastという名前で)が送信されます。 同時に、アクティビティが実行されている場合、このメッセージを取得してデータベースを再度読み取り、すべての新しい要素を表示します。そうでない場合、Broadcastは何もしません。 このタイプのサービスの利点は、私の観察によると、その開発と実装の時間です...アクティビティをそれらに接続する機能を備えたサービスよりも3倍少ないと思います。



したがって、撤退後も、リアルコーディングを続けます)

アプリケーションが時間をカウントし続けるために、それがアクティブでなくても、私はそのようなアルゴリズムを思いつきました。

アプリケーションを閉じると、設定の現在の時刻、2つの作業タイマーと休憩タイマー、およびこれらのタイマーが実行されているかどうかの2つのブール値が保存されます。 次に、起動時にこれらのパラメーターを読み取り、実際の現在の時刻から設定から現在の時刻の値を減算します(このパラメーターを最後の起動の日付などと呼ぶ方が正しいでしょう)。



これらはすべて数行のコードで実行されます。

設定を保存するメソッドの前に、この行をonStop()メソッド(アクティビティが強制終了されたときに呼び出され、再びアクティビティライフサイクルを参照するメソッド)に追加します。

 stats_editor.putLong( "key_last_used_date"、System.currentTimeMillis());


私の記憶でそれをリフレッシュします。 stats_editorは、アプリケーション設定を保存するSharedPreferences.Editorクラスの変数ですが、データストレージとして使用します。 SharedPreferencesクラスもありますが、これらの設定の読み取り専用です。 2つの変数StringがputLongメソッドに報告されます-設定キーと値-値。 putStringメソッド、putIntメソッドなどもあり、それぞれ、2番目のパラメーターString、int ...があります。これらは、getString、getIntメソッドなどによって読み取られ、2つのパラメーターもあります。たとえば、設定がシステムが見つからない場合、デフォルト値を返します。

System.currentTimeMillis()-現在の時刻の長い値をミリ秒で返します。



最初の部分で作成したすべての変数に、変数int last_timeを追加します。 現在の時刻とアプリケーションの最後の起動(またはむしろ停止)の時刻の差を取得します。



次に、onCreate()メソッドに移動して追加します。

 last_time =(int)((System.currentTimeMillis()-saved_stats.getLong( "key_last_used_date"、System.currentTimeMillis()))/ 1000);


注意! 私が言及する価値はありますが、saved_stats変数を初期化した後にこの行を追加する必要があることを誰もが理解してくれることを望みます。そうしないと、NullPointerExceptionをキャッチします。

私は噛む:現在の時刻は最後の開始(より正確には、停止)の時刻であり、これをすべて1000で除算して1ミリ秒から取得し、int構造全体が返されます。

分割? これは整数変数です! -Javaでは、整数を整数で除算すると、除算の整数部分が返されます。



これらの秒をアクティブカウンターに追加することは残ります。 同じonCreate()コンストラクトを探しています。このコンストラクトは、ブール変数の休止と動作に応じて、カウンターのテキストサイズを増やし、そこにこの増加を追加します。

 if(休息)
 {
       	 rest_timer.startAnimation(magnify_rest);
       	 rest_time + = last_time;
 }
 if(作業中)
 {
       	 work_timer.startAnimation(magnify_work);
       	 work_time + = last_time;
 }




始めて、試して、すべてが私のために働くので、それはあなたと共にあるべきです。



通知



アルゴリズムは次のとおりです。カウンターがオンになっている場合、アプレットの停止時に通知を表示し、プログラムの起動時に通知を非表示にするコマンドを送信します。



通知を制御するだけのNotificationManagerクラスの変数を宣言して初期化します。

 notificationManager =(NotificationManager)getSystemService(NOTIFICATION_SERVICE);




この変数には、cancel()とnotify()の2つのメソッドが必要です。 おそらく既に推測したように、最初のものは通知を削除します。 1つのパラメーターが渡されます-id、アプリケーションに複数の通知がある場合、何らかの通知を削除するために、この識別子を使用します。 Notify()には、idとNotificationクラスの変数の2つのパラメーターがあります。

私のアプリケーションには通知が1つしかないため、idの代わりに太字で0またはその他の番号を入力します。 作成されたものとキャンセルされたものが同じであることが重要です。



notificationManager変数が初期化された後、すぐにcancel()メソッドを使用して、アプリケーションの起動時に通知が強制終了されるようにすることができます。

 notificationManager.cancel(0);




次に、onStop()に移動して追加します。

通知通知= null;
 PendingIntent intent = PendingIntent.getActivity(this、0、new Intent(this、Main.class)、PendingIntent.FLAG_UPDATE_CURRENT);
 if(作業中)
 {
	 notification =新しい通知(R.drawable.notification、getResources()。getString(R.string.notification_work)、System.currentTimeMillis());
	 notification.setLatestEventInfo(this、getResources()。getString(R.string.notification_work)、getResources()。getString(R.string.show_app)、intent);
 }
 if(休息)
 {
	 notification =新しい通知(R.drawable.notification、getResources()。getString(R.string.notification_rest)、System.currentTimeMillis());
	 notification.setLatestEventInfo(this、getResources()。getString(R.string.notification_rest)、getResources()。getString(R.string.show_app)、intent);
 }
 if(通知!= null)
 {
	 notification.flags = Notification.FLAG_ONGOING_EVENT |  Notification.FLAG_AUTO_CANCEL;
	 notificationManager.notify(0、通知);
 }


1. Notificationクラスの変数を作成します。

2.使用する線と画像、およびこの通知をクリックしたときに実行する必要があるものについて説明します。

3.通知します();

intent-クラス変数PendingIntent-クリックしたときに実行するクラスを示すのはここです。 また、最後のパラメーターに注意してください。起動されたインテントに対してフラグが送信されます。新しいインテントが古いインテントを更新するようにフラグが設定されています。

通知コンストラクターは、図、通知の作成時に表示されるテキスト、通知バーの幅全体、通知時間です。

setLatestEventInfo -2行:1行目は大きな活字で表示されるもの、2行目は小さな活字で実行される署名です。

notification.flags-ご存知のように、Androidには2種類の通知があります。 この顕著な例は、カレンダーとフラッシュドライブのマウントです。 1つは間もなく、もう1つは最新です。 Notification.FLAG_ONGOING_EVENT-現在の通知のステータスを設定します。

ところで、別のフラグ-Notification.FLAG_AUTO_CANCELを使用して、onCreate()メソッドから通知を削除する行を削除できます。 一般的に、説明を読んでください、面白いことがたくさんあります)

notify-この通知を実際に適用します。



これがすべての外観です。





アプレットを収集し、実行してみます。 すべてが正常に機能するはずですが、すべての消防士について、ソースを共有しています。

Zipアーカイブ(158 Kb)



通知で使用した画像は、すべての写真とともに更新されたアーカイブにあります。

Zipアーカイブ(295 Kb)



市場に注ぐ



開発者の登録手順を経て、25ドルの料金を支払ったとします。今度はプロジェクトをレイアウトするときです。 さあ、行こう!



アプリケーションが正しいバージョンを設定するために最初に必要なこと。

AndroidManifest.xmlを開き、検索します

 android:versionCode = "1"
 android:versionName = "1.0"


versionCode-市場に必要です。 現在インストールされているコードと市場のコードを比較し、更新が少ない場合。

versionNameは「読み取り可能な」バージョン番号です。



最初の部分を書いた後、アプリケーションは市場で利用可能になったので、それを更新する時が来ました。 versionCodeを1増やし、versionNameに1.1を設定しますが、これはすべてあなたの裁量に任されていますが、少なくともライフ0を収集します。



プロジェクトを保存して右クリックし、Android tools-Export Signed Application Packageを選択します。 エクスポートするプロジェクトの名前を入力します。通常、すべてが既に設定されているので、次へをクリックします。 次に、既存のキーを選択するか、新しいキーを作成する必要があります。

キーへのパスとパスワードの2倍を入力します。



このようなものを記入してください。 有効期間については、Googleは2030年まで公開することを推奨しているため、最大限にひねります)



次にクリックして署名し、アプリケーションでapkファイルを取得します。

アプリケーションapk(46 Kb)



念のため、adb install TimeManager_2.apkコマンドを実行することをお勧めします。このコマンドは、既に署名されたバージョンを電話にインストールし、もう一度動作を確認します。



マーケットの管理パネルに行き、アプリケーションに入力します。 原則として、そこもすべて明確です。スクリーンショットの撮り方を説明するだけです。



インストール済みのSDKが必要です。

ターミナルで、ddmsを実行し、左側でデバイスまたはスクリーンキャプチャのハンドセットまたはエミュレータを選択します。



そして、プログラムの説明とその名前をロシア語で書くことを忘れないでください)



特に折りたたみなどについてのMiXeRについては、おそらくandroid.com、つまり開発チームのブログからの記事に再度お送りします。興味深いことがたくさんあります。



runOnUiThread()について。

スレッドなしでアクティビティを作成するということは、すべてのコードがいわゆる1つのスレッドで実行されることを意味します。インターフェイス全体を描画するため、UIスレッド。長い計算を行うときにインターフェイスが遅くなるのはなぜですか?すべてが1つのスレッドで機能し、計算が終了するまで、インターフェイスはそれ以上レンダリングされないため、そうです。これにはストリームが使用されますが、これは主な目的からはほど遠いものです。ただし、UIスレッドでインターフェイスを描画することはできません。これらのタスクには、スレッドから呼び出されるハンドラーがあります。それらでは、描画が行われます。一般に、これらは多くの有用性を提供します。たとえば、最後に1つのスレッドを作成して別のスレッドを作成することができます。これは例です。しかし、それらは非常に大きく、パラメーターにRunnableクラスを指定してrunOnUiThread()メソッドを作成する方がはるかに簡単です。ここで、run()メソッドは、インターフェイススレッドで行う必要があるすべてのことを記述します。事前に謝罪しますが、私はくだらない話者ですが、一般的にはそのようなものです)



All Articles