小米開源便籤Notes-原始碼研究(2)-定時提醒的便籤
本篇講述小米便籤中的定時提醒功能。
便籤,可以理解為一件事情,一項任務,有個定時提醒的功能,還是蠻不錯的~
小米便籤定時功能,是當編輯便籤的時候,有個選單項,選了之後,就彈出一個“日期對話方塊”,
選擇了日期,就設定了定時功能。
下面講解技術實現的整體思路(很多地方我也不懂,不懂的就搜尋):
AndroidManifest.xml配置
<receiver android:name=".ui.AlarmInitReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver
android:name="net.micode.notes.ui.AlarmReceiver"
android:process=":remote" >
</receiver>
<activity
android:name=".ui.AlarmAlertActivity"
android:label="@string/app_name"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar" >
</activity>
定義了2個receiver和1個activity。
Broadcast Receiver(廣播接收器)是Android中的四大元件之一。
AlarmInitReceiver的配置“android.intent.action.BOOT_COMPLETED”,表明
Android手機開機後,會傳送android.intent.action.BOOT_COMPLETED廣播,監聽這個廣播就能監聽開機。
開機之後,就處理已有的便籤,逐條比較日期,如果有到期的,就用AlarmManager提醒使用者。
場景1.剛剛提到的,開機的時候,需要處理已有的便籤。
public class AlarmInitReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
long currentDate = System.currentTimeMillis();
Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
PROJECTION,
NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE,
new String[] { String.valueOf(currentDate) },
null);
if (c != null) {
if (c.moveToFirst()) {
do {
long alertDate = c.getLong(COLUMN_ALERTED_DATE);
Intent sender = new Intent(context, AlarmReceiver.class);
sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID)));
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0);
AlarmManager alermManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent);
} while (c.moveToNext());
}
c.close();
}
}
}
場景2:編輯便籤的時候,需要設定日期。
NodeEditActivity的選單事件
case R.id.menu_delete_remind:
mWorkingNote.setAlertDate(0, false);
break;
WorkingNote
public void setAlertDate(long date, boolean set) {
if (date != mAlertDate) {
mAlertDate = date;
mNote.setNoteValue(NoteColumns.ALERTED_DATE,
String.valueOf(mAlertDate));
}
if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onClockAlertChanged(date, set);
}
}
事件監聽器,最終還是NodeEditActivity
public void onClockAlertChanged(long date, boolean set) {
/**
* User could set clock to an unsaved note, so before setting the alert
* clock, we should save the note first
*/
if (!mWorkingNote.existInDatabase()) {
saveNote();
}
if (mWorkingNote.getNoteId() > 0) {
Intent intent = new Intent(this, AlarmReceiver.class);
intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI,
mWorkingNote.getNoteId()));
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
intent, 0);
AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE));
showAlertHeader();
if (!set) {
alarmManager.cancel(pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, date, pendingIntent);
}
} else {
/**
* There is the condition that user has input nothing (the note is
* not worthy saving), we have no note id, remind the user that he
* should input something
*/
Log.e(TAG, "Clock alert setting error");
showToast(R.string.error_note_empty_for_clock);
}
}
如果使用者設定了時間,就通過AlarmManager放一個監聽事項。
場景3:提醒廣播的最終執行者
AlarmInitReceiver是負責,系統啟動的時候,處理notes。
AlarmReceiver一直在等待“有note需要提醒使用者”的廣播。
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
intent.setClass(context, AlarmAlertActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
時間到期,提醒的活動是AlarmAlertActivity。
public class AlarmAlertActivity extends Activity implements OnClickListener,
OnDismissListener {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
final Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
if (!isScreenOn()) {
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
}
Intent intent = getIntent();
try {
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1));
mSnippet = DataUtils.getSnippetById(this.getContentResolver(),
mNoteId);
mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet
.substring(0, SNIPPET_PREW_MAX_LEN)
+ getResources().getString(R.string.notelist_string_info)
: mSnippet;
} catch (IllegalArgumentException e) {
e.printStackTrace();
return;
}
mPlayer = new MediaPlayer();
if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId,
Notes.TYPE_NOTE)) {
showActionDialog();
playAlarmSound();
} else {
finish();
}
}
}
需要特別學習的Android機制和類庫。
a.AlarmManager
AlarmManager,顧名思義,就是“提醒”,是Android中常用的一種系統級別的提示服務,在特定的時刻為我們廣播一個指定的Intent。
簡單的說就是我們設定一個時間,然後在該時間到來時,AlarmManager為我們廣播一個我們設定的Intent。
通常我們使用PendingIntent,PendingIntent可以理解為Intent的封裝包,簡單的說就是在Intent上在加個指定的動作。
在使用Intent的時候,我們還需要在執行startActivity、startService或sendBroadcast才能使Intent有用。
而PendingIntent的話就是將這個動作包含在內了。
b.MediaPlayer播放聲音。
c.RingtoneManager鈴聲。
d.PowerManager和WindowManager。
播放鈴聲的時候,首先判斷PowerManager.isScreenOn判斷螢幕是否"亮",如果沒亮需要做一些處理。
WindowManager允許app和視窗互動(The interface that apps use to talk to the window manager. )。
應該就是在鎖屏等情況,做一點特殊處理,還沒有具體去細看。
PowerManager,電源管理~
寫在最後:
研究過程中,遇到很多不很懂的程式碼,網上搜尋學習下,基本就知道怎麼回事了。
2011年,4年前就有過2個月時間的學習。
現在工作好幾年了,各種技術都研究或者瞭解過。
現在,重新看Android應用開發,難度不是很大。
對Android有了整體的瞭解,看了幾本書,就可以自己研究寫程式碼了。
不懂的,網上找找資料,然後自己總結,時間長了,估計1~2年,就算是了熟練工了。
預計,到2016年下半年,我的Android水平就很不錯了。
在武漢這種二線城市,如果讓我搞Android開發,薪資在8k~15k左右吧~
也許~
參考資料:
Android開機廣播android.intent.action.BOOT_COMPLETED
http://my.oschina.net/onlytwo/blog/281892
AndroidManifest.xml檔案詳解(receiver)
http://blog.csdn.net/think_soft/article/details/7583047
Android中Broadcast Receiver元件詳解
http://blog.csdn.net/zuolongsnail/article/details/6450156
Android中的AlarmManager的使用
http://blog.csdn.net/wangxingwu_314/article/details/8060312
【Android筆記】MediaPlayer基本使用方式
http://blog.csdn.net/ddna/article/details/5176233#reply
Media開發之鈴聲設定(RingtoneManager)
http://rocking-kaan-126-com.iteye.com/blog/1228215
Android判斷螢幕鎖屏的方法總結
http://www.2cto.com/kf/201404/296615.html
android 之 PowerManager 與電源管理
http://blog.csdn.net/xieqibao/article/details/6562256
相關文章
- 小米開源便籤Notes-原始碼研究(1)-匯出功能整體思路原始碼
- 小米便籤AS部署之Git的基本使用Git
- windows10便籤怎麼開啟啊_windows10便籤在哪裡Windows
- Android開發資料便籤Android
- win10便籤如何加粗字型_win10便籤加粗字型的步驟Win10
- win10便籤在哪裡查詢 win10系統便籤功能怎麼開啟Win10
- win10桌面便籤怎麼新增_win10便籤如何固定在桌面Win10
- Win10便箋如何同步 Win10便籤同步的設定步驟Win10
- Win10如何修改便籤字型和顏色 win10系統便籤字型和顏色的設定方法Win10
- win+w打不開win10便籤怎麼辦_win10便籤打不開如何進入Win10
- js便籤筆記(10) - 分享:json2.js原始碼解讀筆記筆記JSON原始碼
- 有可以間隔兩個月提醒的電腦桌面便籤軟體嗎?
- win10便籤常駐桌面的設定方法Win10
- Android專案自動生成uml圖(以小米便籤為例)Android
- win10 ghost沒有便籤怎麼辦_win10 ghost找不到便籤解決方法Win10
- Mac桌面便籤工具——Handy Note for MacMac
- js便籤筆記(9)——解讀jquery原始碼時記錄的一些知識點JS筆記jQuery原始碼
- win10如何讓便籤顯示在桌面上 win10便籤固定在桌面置頂Win10
- js便籤筆記(10) - 分享:json.js原始碼解讀筆記筆記JSON原始碼
- android widget 開發例項 : 桌面便籤程式的實現詳解和源Android
- js便籤筆記(2)——DOM元素的特性(Attribute)和屬性(Property)JS筆記
- win10中使用便籤功能的方法_win10怎麼使用OneNote便箋功能Win10
- js便籤筆記(1)——說說HTMLCollection、NodeList以及NamedNodeMapJS筆記HTML
- Win10系統下無法正常開啟便籤功能的解決方法Win10
- android記帳本、塗鴉、仿騰訊新聞、仿bilibili、Markdwon便籤、資訊APP等原始碼AndroidAPP原始碼
- 使用electron+vue開發一個跨平臺todolist(便籤)桌面應用Vue
- js便籤筆記(8)——js載入XML字串或檔案JS筆記XML字串
- js便籤筆記(12)——瀏覽TOM大叔部落格的學習筆記 part2JS筆記
- 好用的win10電腦桌面便利貼,桌面便籤小工具Win10
- js便籤筆記(6)——jQuery中的ready()事件為何需要那麼多程式碼?JS筆記jQuery事件
- js便籤筆記(4)——簡單說說getAttributeNode()和setAttributeNode()JS筆記
- js便籤筆記(14)——用nodejs搭建最簡單、輕量化的http server筆記NodeJSHTTPServer
- js便籤筆記(7)——style、currentStyle、getComputedStyle區別介紹【轉載】JS筆記
- 個人免籤支付原始碼原始碼
- js便籤筆記(13)——jsonp其實很簡單【ajax跨域請求】筆記JSON跨域
- js便籤筆記(11)——瀏覽TOM大叔部落格的學習筆記 part1JS筆記
- win10 windows ink工作區找不到便籤 消失不見了該怎麼辦Win10Windows
- Java Web應用下實現定時任務的簡便方法JavaWeb