1. 程式人生 > >安卓小專案實戰之--定時提醒備忘錄

安卓小專案實戰之--定時提醒備忘錄

寫在前面:

      安卓的學習也有半年多了,期間也曾寫過部落格,但大多都是一些瑣碎的筆記,基本沒用任何參考價值,這幾天閒來無事,便想做個小專案來玩玩,鞏固一下基本知識,並且完整的記錄下來整個開發的過程,以作留念。

/————————我是華麗的分割線—————————-/
      本次專案選擇了可定時提示的備忘錄。原理是利用系統每分鐘傳送一條時間改變的廣播,通過接受這條廣播來判斷是否為使用者設定的時間,如果是則與使用者互動提醒使用者。
首先,在Eclipse中建立一個Android專案,取名為Notification

類:MainActivity.java

MainActivity
此Activity主要用於使用者新增備忘錄頁面的轉跳與已新增備忘錄的展示。
在其佈局檔案activity_main.xml中加入一個Button和一個TextView 。目前還沒有實現多事件的共同設定,所以暫時使用TextView顯示事件。
因為儲存的資料比較少,這裡採用SharedPreferences進行儲存,在Activity的onCreate()方法中進行成員變數的初始化操作:

        protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
        sp = getSharedPreferences("UserNote",MODE_PRIVATE);
    }
public void init() {

        button = (Button) findViewById(R.id
.bt); title = (TextView) findViewById(R.id.main_title); note = (TextView) findViewById(R.id.main_note); time = (TextView)findViewById(R.id.main_time); }

在onStart()中對按鈕bt新增點選事件監聽,並通過startActivity(intent)啟動AddActivity轉跳到新增的Activity:

    protected void onStart() {
        super
.onStart(); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { Intent intent = new Intent(MainActivity.this, AddActivity.class); startActivity(intent); } }); }

在onResume()方法中,獲取SharedPerfences中的資料並更新TextView的內容:

protected void onResume(){
        super.onResume();
        strTime = sp.getString("time","null");
        strTitle = sp.getString("title","null");
        strNote = sp.getString("text","null");
        title.setText(strTitle);
        note.setText(strNote);
        time.setText(strTime);
        System.out.println("onResume");

    }

MainActivity.java整體程式碼如下:

package com.example.notification;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
    private Button button;
    private SharedPreferences sp;
    private TextView title, note,time;
    private String strTitle,strNote,strTime;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
        sp = getSharedPreferences("UserNote",MODE_PRIVATE);
    }

    @Override
    protected void onStart() {
        super.onStart();
        button.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                Intent intent = new Intent(MainActivity.this, AddActivity.class);
                startActivity(intent);
            }
        });

    }
    protected void onResume(){
        super.onResume();
        strTime = sp.getString("time","null");
        strTitle = sp.getString("title","null");
        strNote = sp.getString("text","null");
        title.setText(strTitle);
        note.setText(strNote);
        time.setText(strTime);
        System.out.println("onResume");

    }

    public void init() {

        button = (Button) findViewById(R.id.bt);
        title = (TextView) findViewById(R.id.main_title);
        note = (TextView) findViewById(R.id.main_note);
        time = (TextView)findViewById(R.id.main_time);
    }
}
該Activity佈局檔案activity_main.xml如下
<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.notification.MainActivity"
    android:background="#fcf3ea" >

    <Button
        android:id="@+id/bt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="新增備忘錄"
        android:textSize="20dp" />

    <TextView
        android:id="@+id/setting"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/bt"
        android:textSize="20dp"
        android:text="" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@+id/setting"
        android:layout_toRightOf="@+id/setting"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/main_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20dp"
            android:text="" />
        <TextView
            android:id="@+id/main_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20dp"
            android:text="" />
          <TextView
            android:id="@+id/main_note"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20dp"
            android:text="" />
    </LinearLayout>

</RelativeLayout>

類:AddActivity.java

AddActivity
該Activity為使用者新增備忘錄事件的Activity,使用者通過EditText和DatePicker和TimePicker進行資料的輸入,單擊按鈕由SharedPerfences記錄使用者輸入的資料.在onCreate()中進行初始化,在onStart()中對按鈕新增監聽,並且將時間選擇器和使用者輸入的內容存入SharedPerfences,這裡應當注意的是,時間選擇器選擇的資料如果為一位數如1月 則記錄的日期為1 並非01,這點與SimpleDateFormat生成的不一致,所以我們需要自己建立一個類來規範我們的時間,這個類取名為MyTime,在儲存完畢使用者鍵入的資料以後,Activity會啟動一個服務NotifyService,並且呼叫finish()關閉自身。

AddActivity程式碼如下:
package com.example.notification;

import java.text.SimpleDateFormat;
import java.util.Date;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.TimePicker;
import android.widget.Toast;

public class AddActivity extends Activity {
    private Button conButton;
    private TimePicker tp;
    private DatePicker dp;
    private EditText etTitle, etNote;
    private String title, text;
    private SharedPreferences sp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add);
        init();
    }

    protected void onStart() {
        super.onStart();
        conButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                saveTime();

            }
        });
    }

    @SuppressLint("NewApi")
    public void init() {
        conButton = (Button) findViewById(R.id.add_bt_confirm);
        tp = (TimePicker) findViewById(R.id.timePicker1);
        dp = (DatePicker) findViewById(R.id.datePicker1);
        etTitle = (EditText) findViewById(R.id.add_et_title);
        etNote = (EditText) findViewById(R.id.add_et_note);
        tp.setIs24HourView(true);
        dp.setCalendarViewShown(false);
        sp = getSharedPreferences("UserNote", MODE_PRIVATE);
    }

    public void saveTime() {
        text = etNote.getText().toString();
        title = etTitle.getText().toString();
        int day = dp.getDayOfMonth();
        int mon = dp.getMonth()+1;//getMonth 返回從0開始
        System.out.println("setMon is"+mon);
        int year = dp.getYear();
        int hour = tp.getCurrentHour();
        int min = tp.getCurrentMinute();

        SimpleDateFormat sdf = new SimpleDateFormat("HHmm");

        String time = MyTime.getTime(year,mon,day,hour, min);
        System.out.println(time);
        SharedPreferences.Editor editor = sp.edit();
        editor.putString("text", text);
        editor.putString("time", time);
        editor.putString("title",title);
        editor.commit();
        System.out.println(time);
        Intent intent = new Intent(AddActivity.this, NotifyService.class);
        startService(intent);
        Log.i("ADD","intent完畢");
        finish();
    }

}
MyTime.java如下
package com.example.notification;

public class MyTime {

    public MyTime() {
        // TODO 自動生成的建構函式存根
    }

    public static String getTime(int year,int mon,int day,int hour, int min) {

        String mins,mons,days,hours;
        if(hour<10)
            hours = 0+String.valueOf(hour);
        else
            hours = String.valueOf(hour);
        if(min<10)
            mins =0+ String.valueOf(min);
        else
            mins = String.valueOf(min);
        if(mon<10)
            mons =0+ String.valueOf(mon);
        else
            mons = String.valueOf(mon);
        if(day<10)
            days = 0+String.valueOf(mon);
        else
            days = String.valueOf(day);
        return year+":"+mons+":"+days+":"+hours+":"+mins;

    }
}

服務NotifyService.java

新建服務需要在AndroidManifest.xml進行註冊,在節點下加入以下程式碼進行註冊

  <service android:name=".NotifyService" ></service>

該服務主要功能為判斷當前時間與使用者儲存時間是否一致,並進行相應動作,在onCreate()方法動態註冊一個廣播接收器TimeRecevier,該廣播接收器接收系統時間變化的廣播,該廣播每分鐘由系統發出一次,並在OnDestroy()方法中登出該廣播接收器。具體ACTION如下(要接收該廣播,必須進行動態註冊):

private String ACTION = Intent.ACTION_TIME_TICK;

在onStartCommand()方法中,利用SimpleDateFormat將當前系統時間格式化與本地儲存一致的格式,當前時間可以通過new Date()獲取(new Date()實質上就是System.currentTimeMillis());然後進行時間的比對,如果一致,則通知欄通知使用者,並且啟動一個可以在鎖屏狀態下喚醒螢幕的Activity。這裡值得注意的是,在服務中啟動一個Activity必須為呼叫的intent新增一個Flag如下:

ActIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  

最後呼叫stopSelf()方法,關閉自身.

NotifyService.java程式碼如下:
package com.example.notification;

import java.text.SimpleDateFormat;
import java.util.Date;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.util.Log;

public class NotifyService extends Service {
    private NotificationManager nm;
    private boolean isRec = false;
    private boolean isFirst = true;
    private String ACTION = Intent.ACTION_TIME_TICK;
    private SharedPreferences sp;
    private IntentFilter ifter;
    private TimeReceiver receiver;

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO 自動生成的方法存根
        return null;
    }

    @Override
    public void onCreate() {
        // TODO 自動生成的方法存根
        super.onCreate();
        sp = getSharedPreferences("UserNote", MODE_PRIVATE);
        nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        ifter = new IntentFilter();
        ifter.addAction(ACTION);
        receiver = new TimeReceiver();
        if (isRec == false) {
            registerReceiver(receiver, ifter);
            isRec = true;
        }
        Log.i("Service","onCreate");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        System.out.println("服務拜拜");
        unregisterReceiver(receiver);
    }

    @SuppressWarnings("deprecation")
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // TODO 自動生成的方法存根
        Log.i("Service","onStart");
        if (isFirst) {
            isFirst = false;
        } else {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd:HH:mm");
            String curTime = sdf.format(new Date());
            System.out.println(curTime);

            String time =sp.getString("time", "0000");
            System.out.println("curTime"+curTime+" setTime"+time);
            if (curTime.equals(time)) {
                String text = sp.getString("text", "預設事件");
                System.out.println("onStart");
                Notification notify = new Notification(R.drawable.ic_launcher,
                        "小貼士", System.currentTimeMillis());
                PendingIntent pi = PendingIntent.getActivity(this,0, 
                        new Intent(this,MainActivity.class),0);
                notify.setLatestEventInfo(this, "小貼士提醒您", time+"  "+text, pi);
                notify.defaults = Notification.DEFAULT_ALL;
                nm.notify(1044, notify);
                Intent ActIntent = new Intent(this,DialogActivity.class);
                ActIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
                startActivity(ActIntent);

                stopSelf();
            }
        }
        return super.onStartCommand(intent, flags, startId);

    }

}

類,廣播接收器:TimeReceiver.java

整個接收器的作用只有一個,就是每次接收到廣播,便啟動服務NotifyService。

TimeReceiver.java如下
package com.example.notification;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class TimeReceiver extends BroadcastReceiver{



    @Override
    public void onReceive(Context context, Intent intent) {
        System.out.println("recevice");
        context.startService(new Intent(context,NotifyService.class));

    }

}

類DialogActivity.java

DialogActivity
該Activity為使用者預設的時間到了通知使用者的Activity,該Activity有如下特性:
      1.可以點亮螢幕。
      2.可以在鎖屏狀態下啟動。
實現這兩個特點並不困難,只需要加入這兩句話:

 getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                    | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);

另外,值得一提的是,QQ客戶端的鎖屏聊天視窗就是這樣實現的(如圖):
QQ對話方塊
這個視窗看似是在彈窗之上。其實本身只是一個Activity,玄機就在他的背景圖片,他是一個以系統桌布為背景的沒有標題欄的Activity。因此為了不讓Activity突然彈出看起來那麼突兀,我們要自定義一個Theme。在AndroidManifest.xml的節點下加入以下程式碼

<activity
            android:name=".DialogActivity"
            android:label="提醒您" 
            android:theme="@android:style/Theme.Wallpaper.NoTitleBar"
            >

在res/values/styles.xml加入自定義的Style

  <style name="FullScreenTheme" parent="@android:style/Theme.Light.NoTitleBar">
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:colorBackgroundCacheHint">@null</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowIsTranslucent">true</item>
    </style>

完成

感謝你的閱讀,在此我們就完成了定時提醒備忘錄這個小專案,當然這個專案還有很多不足,只是一個功能的實現,如果有興趣你可以根據原始碼新增想要的功能例如多條事件的新增,還可以加上桌面元件.

原始碼下載地址: