转载请注明出处:http://blog.csdn.net/ns_code/article/details/11269957      


     鉴于很多网友发私信或者留言想我所要课程表项目源码,我这里将其开源到我的Github上:

https://github.com/mmc-maodun/Multi-function-curriculum-Based-on-Android

     工欲善其事,必先利其器,刚接触Android一个月的时候,便准备做一款Android平台下的多功能课程表,做了一周多,便出去实习了,近几个月一直在忙公司(实习)的事情,利用断断续续的闲暇时间,将该APP做出来了,虽说这东东不算难做,但真要做起来,遇到的问题还是蛮多的,在不断的发现问题与解决问题中成长,也是对自己的一种锻炼。

该APP已经上传到小米应用商店,欢迎下载:http://app.xiaomi.com/detail/42115

【基本功能】 
编辑、添加、删除和查看课程表; 
【核心功能】 
1、打开课表时来,默认显示当天的课程信息; 
2、根据用户的设置,在上课前通知提醒; 
3、根据用户的设置,上课时自动将手机调节振动,下课后将手机恢复正常铃声; 

先附上几张在模拟器上截取的效果图片:




 


完成这个APP之后,大致总结了几点局部功能的实现方法(不是很全),如下:
1、上课自动静音功能的实现:
通过开关控制是否启动后台的SetQuierService,从而在程序退出后一直在后台运行,
在SetQuierService中,用TimeTask,每隔一分钟从数据库中取出一次数据,
并从系统取得一次当天是星期几,以及当前的时间,
通过二者对比较,确定是否开启振动模式以及恢复原始铃声模式设置。
另外:这里写了一个LauncherReceiver用来监听系统开机事件,当用户开启了SetQuierService,但是因为某种原因关机了,
再次开机后,它会在这种情况下开机自启动SetQuierService。

2、课前提醒功能的实现:
通过开关控制是否每隔一分钟发送一次广播,而该广播会被RemindReceiver接收到,从而每隔一分钟从数据库中取得一次数据,
并从系统中取得一次当天是星期几,以及当前的时间,
通过对二者的比较,确定是否启动提醒用户的RemindActivity
另外,该广播的发送通过AlarmManager来实现,参数里设置的休眠不发送广播,但开机后会继续发送,因此不受关机影响。

3、完全退出应用程序采用的方法:
建立一个继承自Application的类MyApplication,在其中定义一个放置Activity的容器,用单例设计模式取得唯一的MyApplication实例,每建立一个Activity,就将其添加到该MyApplication实例的容器中。

4、第一次打开APP时直接创建数据库表,之后直接调用数据库:
采用单例设计模式创建数据库表,通过SharedPreferences保存一标志位,判断是否是第一次创建数据库表。


详细的工程文件截图如下:

各文件的源代码如下,详细的注释代码里面都有,这里不再详细说明:
文件

<?xml version="1.0" encoding="utf-8"?>                                                                                                                                                                                                                                                                                                                                                                                     


文件,用来设置启动画面
package zyb.org.load;import zyb.org.androidschedule.MainActivity;import zyb.org.androidschedule.R;import android.app.Activity;import android.content.Intent;import android.graphics.PixelFormat;import android.os.Bundle;import android.os.Handler;import android.view.WindowManager;public class LoadActivity extends Activity {    //time for picture display    private static final int LOAD_DISPLAY_TIME = 3000;        /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);                getWindow().setFormat(PixelFormat.RGBA_8888);        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DITHER);        setContentView(R.layout.activity_load);                new Handler().postDelayed(new Runnable() {            public void run() {                //Go to main activity, and finish load activity                Intent mainIntent = new Intent(LoadActivity.this, MainActivity.class);                LoadActivity.this.startActivity(mainIntent);                LoadActivity.this.finish();            }        }, LOAD_DISPLAY_TIME);     }}


布局文件,与文件相对应
<?xml version="1.0" encoding="utf-8"?>  

文件,设置主界面上的相关操作
package zyb.org.androidschedule;import temp.DataBase;import temp.MyApplication;import temp.MyDialog;import temp.ShareMethod;import zyb.org.editschedule.SetActivity;import android.media.AudioManager;import android.os.Bundle;import android.app.Activity;import android.app.AlertDialog;import android.app.Service;import android.content.Context;import android.content.DialogInterface;import android.content.Intent;import android.content.SharedPreferences;import android.database.Cursor;import android.support.v4.widget.SimpleCursorAdapter;import android.util.Log;import android.view.GestureDetector;import android.view.Menu;import android.view.MenuItem;import android.view.MotionEvent;import android.view.View;import android.view.View.OnClickListener;import android.view.View.OnTouchListener;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.ListView;import android.widget.TabHost;import android.widget.TabWidget;import android.widget.TextView;public class MainActivity extends Activity { public ListView list[] = new ListView[7];private TabHost tabs   = null;private TextView exitButton = null; private TextView setButton = null;public static DataBase db;public Cursor[] cursor=new Cursor[7];public SimpleCursorAdapter adapter;private SharedPreferences pre;    //定义手势检测器实例private GestureDetector detector = null;    //定义手势动作两点之间的最小距离private final int FLIP_DISTANCE = 200;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//将该activity加入到MyApplication对象实例容器中MyApplication.getInstance().addActivity(this);db=new DataBase(MainActivity.this);pre=getSharedPreferences("firstStart",Context.MODE_PRIVATE);/* * 判断程序是否第一次运行,如果是创建数据库表 */if(pre.getBoolean("firstStart", true)){SingleInstance.createTable();(pre.edit()).putBoolean("firstStart",false).commit();//finish();}exitButton = (TextView)findViewById(R.id.exitButton);setButton = (TextView)findViewById(R.id.setButton);list[0] = (ListView)findViewById(R.id.list0);list[1] = (ListView)findViewById(R.id.list1);list[2] = (ListView)findViewById(R.id.list2);list[3] = (ListView)findViewById(R.id.list3);list[4] = (ListView)findViewById(R.id.list4);list[5] = (ListView)findViewById(R.id.list5);list[6] = (ListView)findViewById(R.id.list6);tabs  = (TabHost)findViewById(R.id.tabhost);    //创建手势检测器    detector = new GestureDetector(this, new DetectorGestureListener());   //在配置任何的TabSpec之前,必须在TabHost上调用该方法tabs.setup();//为主界面注册七个选项卡TabHost.TabSpec  spec = null;addCard(spec,"tag1",R.id.list0,"日");addCard(spec,"tag2",R.id.list1,"一");addCard(spec,"tag3",R.id.list2,"二");addCard(spec,"tag4",R.id.list3,"三");addCard(spec,"tag5",R.id.list4,"四");addCard(spec,"tag6",R.id.list5,"五");addCard(spec,"tag7",R.id.list6,"六");//修改tabHost选项卡中的字体的颜色TabWidget tabWidget = tabs.getTabWidget();for(int i=0;i arg0, View arg1,final int id, long arg3) {final int currentDay=tabs.getCurrentTab();final int n=id;    final AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);    builder.setIcon(R.drawable.ic_launcher);builder.setTitle("选择");TextView tv=(TextView)arg1.findViewById(R.id.ltext0);Log.i("Test",(tv.getText().toString().equals(""))+"");//如果课程栏目为空就启动添加对话框if((tv.getText()).toString().equals("")){//通过数组资源为对话框中的列表添加选项内容,这里只有一个选项builder.setItems(R.array.edit_options1, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {//如果单击了该列表项,则跳转到编辑课程信息的界面if(which == 0){new MyDialog(MainActivity.this).add(currentDay,n);}}});builder.create().show();  }//否则启动修改对话框,或直接删除数据else{builder.setItems(R.array.edit_options2, new DialogInterface.OnClickListener() {@SuppressWarnings("deprecation")@Overridepublic void onClick(DialogInterface dialog, int which) {//如果单击了该列表项,则跳转到编辑课程信息的界面if(which == 0){new MyDialog(MainActivity.this).modify(currentDay,n);}if(which == 1){cursor[currentDay].moveToPosition(n);int n1=Integer.parseInt(cursor[currentDay].getString(7));//课程的总节数int n2=Integer.parseInt(cursor[currentDay].getString(8));//选中的为该课程的第几节switch(n2){case 0:for(int m=0;m=0;m--){MainActivity.db.deleteData(currentDay,n-m+1);}break;default:break;}cursor[currentDay].requery();list[currentDay].invalidate();}}});builder.create().show();}}});}}//内部类,实现GestureDetector.OnGestureListener接口class DetectorGestureListener implements GestureDetector.OnGestureListener{@Overridepublic boolean onDown(MotionEvent e) {return false;}//当用户在触屏上“滑过”时触发此方法@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {int i = tabs.getCurrentTab();//第一个触点事件的X坐标值减去第二个触点事件的X坐标值超过FLIP_DISTANCE,也就是手势从右向左滑动if(e1.getX() - e2.getX() > FLIP_DISTANCE){if(i<6)tabs.setCurrentTab(i+1);//float currentX = e2.getX();//list[i].setRight((int) (inialX - currentX));return true;}//第二个触点事件的X坐标值减去第一个触点事件的X坐标值超过FLIP_DISTANCE,也就是手势从左向右滑动else if(e2.getX() - e1.getX() > FLIP_DISTANCE){if(i>0)tabs.setCurrentTab(i-1);return true;}return false;}@Overridepublic void onLongPress(MotionEvent e) {}@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) {return false;}@Overridepublic void onShowPress(MotionEvent e) {}@Overridepublic boolean onSingleTapUp(MotionEvent e) {return false;}}//覆写Activity中的onTouchEvent方法,将该Activity上的触碰事件交给GestureDetector处理@Overridepublic boolean onTouchEvent(MotionEvent event) {return detector.onTouchEvent(event);}//设置菜单按钮@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.activity_main, menu);return true;}//当点击菜单中的“退出”键时,弹出提示是否退出的对话框@Overridepublic boolean onOptionsItemSelected(MenuItem item) {//创建AlertDialog.Builder对象,该对象是AlterDialog的创建器,AlterDialog用来创建弹出对话框    final AlertDialog.Builder builder = new AlertDialog.Builder(this);if(item.getItemId() == R.id.menu_exit){exit(builder);return true;}if(item.getItemId() == R.id.menu_settings){Intent intent = new Intent(MainActivity.this, SetActivity.class);startActivity(intent);return true;}return super.onOptionsItemSelected(item);} //子 方法:为主界面添加选项卡public void addCard(TabHost.TabSpec spec,String tag,int id,String name){spec = tabs.newTabSpec(tag);spec.setContent(id);spec.setIndicator(name);tabs.addTab(spec);}//子方法:用来弹出是否退出程序的对话框,并执行执行是否退出操作public void exit(AlertDialog.Builder builder){//为弹出的对话框设置标题和内容builder.setIcon(R.drawable.ic_launcher);builder.setTitle("退出程序");builder.setMessage("确定要退出随身课程表吗?");//设置左边的按钮为“确定”键,并且其绑定监听器,点击后退出builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {//退出应用程序,即销毁地所有的activityMyApplication.getInstance().exitApp();}});//设置右边的按钮为“取消”键,并且其绑定监听器,点击后仍然停留在当前界面builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {}});//创建并显示弹出的对话框builder.create().show();}/* * 为每一个list提供数据适配器 */@SuppressWarnings("deprecation")public SimpleCursorAdapter adapter(int i){return new SimpleCursorAdapter(this, R.layout.list_v2,cursor[i],new String[]{"_id","classes","location","teacher","zhoushu"},new int[]{R.id.number,R.id.ltext0,R.id.ltext1,R.id.ltext6,R.id.ltext7} );}/* * 第一次运行时创建数据库表 */static class SingleInstance{static SingleInstance si;private SingleInstance(){for(int i=0;i<7;i++){db.createTable(i);}}static SingleInstance createTable(){if(si==null)return si=new SingleInstance();return null;}}}


布局文件,与文件相对应
                                                                                                                        

文件,该类中定义了对sqlite数据库的相关操作
package temp;import android.content.ContentValues;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;public class DataBase extends SQLiteOpenHelper{private final static String DB_NAME="myBase";private final static String[] TB_NAME={"Mon","Tue","Wed","Thur","Fri","Sat","Sun"};public  final static String ID="_id";public final static String CLASS="classes";public final static String LOCA="location";public final static String TEACHER="teacher";public final static String ZHOUSHU="zhoushu";public final static String JIESHU="jieshu";public final static String TIME1="time1";public final static String TIME2="time2";public final static String WHICH="which";public DataBase(Context context){super(context,DB_NAME,null,1);}@Overridepublic void onCreate(SQLiteDatabase db) {for(int i=0;i<7;i++){String sql="CREATE TABLE "+TB_NAME[i]+" (_id INTEGER primary key autoincrement,classes varchar(70),location varchar(70)," +"teacher varchar(70),zhoushu varchar(70),time1 varchar(70),time2 varchar(70),jieshu varchar(70),which varchar(70))";db.execSQL(sql);}}@Overridepublic void onUpgrade(SQLiteDatabase db, int oleVersion, int newVersion) {for(int i=0;i<7;i++){String sql="DROP TABLE IF EXISTS "+TB_NAME[i];db.execSQL(sql);}onCreate(db);}public Cursor select(int i){SQLiteDatabase db=DataBase.this.getReadableDatabase();Cursor cursor=db.query(TB_NAME[i],null,null,null,null,null,null);return cursor;}public  long insert(int i,String cla,String loca,String tea,String zhou,String jie,String time1,String time2,String which){SQLiteDatabase db=DataBase.this.getWritableDatabase();ContentValues cv=new ContentValues();cv.put(CLASS,cla);cv.put(LOCA, loca);cv.put(TEACHER,tea);cv.put(ZHOUSHU,zhou);cv.put(JIESHU,jie);cv.put(TIME1,time1);cv.put(TIME2,time2);cv.put(WHICH,which);long row=db.insert(TB_NAME[i],null,cv);return row;}public void update(int i,int _id,String cla,String loca,String tea,String zhou,String jie,String time1,String time2,String which){SQLiteDatabase db=DataBase.this.getWritableDatabase();String where="_id = ?";String[] whereValues={Integer.toString(_id)};ContentValues cv=new ContentValues();if(!cla.equals("")) cv.put(CLASS,cla);if(!loca.equals("")) cv.put(LOCA, loca);if(!tea.equals("")) cv.put(TEACHER,tea);if(!zhou.equals("")) cv.put(ZHOUSHU,zhou);if(!jie.equals("")) cv.put(JIESHU,jie);if(!time1.equals("")) cv.put(TIME1,time1);if(!time2.equals("")) cv.put(TIME2,time2);if(!which.equals("")) cv.put(WHICH,which);db.update(TB_NAME[i], cv, where, whereValues);}public void deleteData(int i,int _id){SQLiteDatabase db=DataBase.this.getWritableDatabase();String where="_id = ?";String[] whereValues={Integer.toString(_id)};ContentValues cv=new ContentValues();cv.put("classes","");cv.put("location","");cv.put("teacher","");cv.put("zhoushu","");cv.put("jieshu","");cv.put("time1","");cv.put("time2","");cv.put("which","");db.update(TB_NAME[i], cv, where, whereValues);}public void delete(int i,int _id){SQLiteDatabase db=this.getWritableDatabase();String where="_id = ?";String[] whereValues={Integer.toString(_id)};db.delete(TB_NAME[i], where, whereValues);}public  void createTable(int j){for(int i=1;i<=12;i++)insert(j,"", "", "","","","","","");}}


文件
package temp;import zyb.org.androidschedule.MainActivity;import android.content.Context;public class MyAdapter {private Context context;private MainActivity main;public MyAdapter(Context context){this.context=context;main=(MainActivity) context;}}

文件,定义编辑课表信息时显示的对话框
package temp;import java.util.Calendar;import zyb.org.androidschedule.MainActivity;import zyb.org.androidschedule.R;import android.app.AlertDialog;import android.app.AlertDialog.Builder;import android.app.TimePickerDialog;import android.content.Context;import android.content.DialogInterface;import android.content.DialogInterface.OnClickListener;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.TimePicker;import android.widget.Toast;public class MyDialog {private EditText course_name;private EditText course_address;private EditText course_teacher;private EditText course_week;//private EditText course_time1,course_time2;private EditText course_count;private View view;private Context context;private LayoutInflater inflater;private Builder builder;MyAdapter adapter;MainActivity main;String s1="",s2="",s3="",s4="",s5="",s6="",s7="";public MyDialog(Context context){this.context=context;main=(MainActivity) context;adapter=new MyAdapter(context);} /* * 点击未编辑的课程列表跳出”添加课程“对话框 */public void add(final int day,final int n){//填装对话框的viewinflater=LayoutInflater.from(context);view=inflater.inflate(R.layout.edit_shedule,null);findWidgetes();//取部件final Button course_time1=(Button)view.findViewById(R.id.time1);final Button course_time2=(Button)view.findViewById(R.id.time2);//为两个输入时间的按钮绑定监听器course_time1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {TimeSet_Dialog(course_time1);}});course_time2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {TimeSet_Dialog(course_time2);}});builder=new AlertDialog.Builder(context).setIcon(R.drawable.ic_launcher).setTitle("编辑课程信息").setView(view).setPositiveButton("确认",new OnClickListener(){@SuppressWarnings("deprecation")@Overridepublic void onClick(DialogInterface arg0, int arg1) {if(!(s1=course_name.getText().toString()).equals("")) s1="课程: "+s1;if(!(s2=course_address.getText().toString()).equals("")) s2="地点: "+s2;if(!(s3=course_teacher.getText().toString()).equals("")) s3="老师: "+s3;if(!(s4=course_week.getText().toString()).equals("")) s4="周数: "+s4;if(!(s6=course_time1.getText().toString()).equals("")) s6="时间: "+s6;if(!(s7=course_time2.getText().toString()).equals("")) ;if((s5=course_count.getText().toString()).equals("")||s1.equals("")) {Toast.makeText(context, "请正确输入课程及节数!", 3000).show();return;}else {int i=Integer.parseInt(s5.trim());//i为节数for(int m=0;m=0;m--){MainActivity.db.update(day,n-m+1,s1,s2,s3,s4,s5,s6,s7,Integer.toString(n2-m));}break;}}//若节数有变化,先确定新节数并赋予旧的数据再更新数据else{int n3=Integer.parseInt(s5.trim());//扩充节数if(n3>n1){switch(n2){//更新数据case 0:for(int m=0;m=0;m--){MainActivity.db.update(day,n-m+1,s1,s2,s3,s4,s5,s6,s7,Integer.toString(n2-m));}break;}}//缩减节数:删除旧数据再根据新的节数赋予旧数据最后更新新数据if(n3=0;m--){MainActivity.db.deleteData(day,n-m+1);}break;default:Toast.makeText(context, "error", 3000).show();break;}switch(n2){//更新数据case 0:for(int m=0;m

文件,主要在其中定义一个放置Activity的容器,没建立一个Activity,便将其放入其中,在退出应用程序时候,遍历销毁所有的Activity
package temp;import java.util.LinkedList;import java.util.List;import android.app.Activity;import android.app.Application;//MyApplication类用来存储每一个activity,并实现关闭所有activity的操作public class MyApplication extends Application {//定义容activity容器private List activityList = new LinkedList();private static MyApplication instance;private MyApplication(){}//单例设计模式中取得唯一的MyApplication实例public static MyApplication getInstance(){if(instance == null)instance = new MyApplication();return instance;}//添加activity到容器中public void addActivity(Activity activity){activityList.add(activity);}//遍历所有的activity并finishpublic void exitApp(){for(Activity activity : activityList){if(activity != null)activity.finish();}System.exit(0);}//清空缓存@Override    public void onLowMemory() {         super.onLowMemory();             System.gc();     }  }

文件,定义一些公用的方法,这些方法主要在后面的Service及BroadcastReceiver相关类中用到
package temp;import java.util.Calendar;import java.util.Date;public class ShareMethod {//获取当天是星期几,这里星期七、一......分别为数字0、1......public static int getWeekDay(){Calendar calendar=Calendar.getInstance();Date date=new Date(System.currentTimeMillis());calendar.setTime(date);int weekDay=calendar.get(Calendar.DAY_OF_WEEK)-1;return weekDay;}//获取当前的时间,并以字符串"xx:xx"的形式返回public static String getTime(){Calendar c=Calendar.getInstance();int hourOfDay = c.get(Calendar.HOUR_OF_DAY);int minute = c.get(Calendar.MINUTE);//获取完整的时间,在只有一位的数字前面加0StringBuffer s_hour = new StringBuffer();StringBuffer s_minute = new StringBuffer();s_hour.append(hourOfDay);s_minute.append(minute);if(hourOfDay<10){s_hour.insert(0,"0");}if(minute<10){s_minute.insert(0,"0");}return s_hour.toString() + ":" + s_minute.toString();}}

文件,设置类,点击“设置”按钮,便跳转到该Activity
package zyb.org.editschedule;import temp.MyApplication;import zyb.org.about.AboutUsActivity;import zyb.org.androidschedule.R;import zyb.org.service.RemindReceiver;import zyb.org.version.VersionActivity;import android.app.Activity;import android.app.AlarmManager;import android.app.AlertDialog;import android.app.Dialog;import android.app.PendingIntent;import android.app.Service;import android.app.AlertDialog.Builder;import android.content.Context;import android.content.DialogInterface;import android.content.Intent;import android.content.SharedPreferences;import android.media.AudioManager;import android.os.Bundle;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.CompoundButton;import android.widget.CompoundButton.OnCheckedChangeListener;import android.widget.Switch;import android.widget.TextView;import android.widget.Toast;public class SetActivity extends Activity {//声明一个SharedPreferences对象,用来保存switch组件的开关信息private SharedPreferences preferences = null;//editor对象用来向preferences中写入数据private SharedPreferences.Editor editor = null;//声明一个SharedPreferences对象,用来保存time_choice的值private SharedPreferences pre = null;//pre_editor对象用来向pre中写入数据private SharedPreferences.Editor pre_editor = null;//声明一个AlarmManager对象,用来开启课前提醒服务private AlarmManager alarmManager = null;//声明一个PendingIntent对象,用来指定alarmManager要启动的组件private PendingIntent pi = null;private Intent alarm_receiver = null; //定义单选列表对话狂的id,该对话框用于显示课前提醒时间的可选项final int SINGLE_DIALOG = 0x113;//定义选中的时间private int time_choice = 0;private Switch switch_quietButton;private Switch switch_remindButton;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_set);//将该activity加入到MyApplication对象实例容器中MyApplication.getInstance().addActivity(this);//声明一个获取系统音频服务的类的对象final AudioManager audioManager = (AudioManager)getSystemService(Service.AUDIO_SERVICE);//从MainAcivity中获取原始设置的铃声模式Intent intent = getIntent();final int orgRingerMode = intent.getIntExtra("mode_ringer", AudioManager.RINGER_MODE_NORMAL);//获取系统的闹钟定时服务alarmManager = (AlarmManager)getSystemService(Service.ALARM_SERVICE);//指定alarmManager要启动的组件alarm_receiver = new Intent(SetActivity.this,RemindReceiver.class);//alarm_receiver.putExtra("anvance_remindtime", time_choice);pi = PendingIntent.getBroadcast(SetActivity.this, 0, alarm_receiver, 0);//取出各组件TextView backButton = (TextView)findViewById(R.id.backtoMainButton);switch_quietButton = (Switch)findViewById(R.id.switch_quiet);switch_remindButton = (Switch)findViewById(R.id.switch_remind);//这里模式一定要设置为MODE_MULTI_PROCESS,否则即使相应的xml文件中数据有更新,RemindReceiver中也不能获取更新后的数据,而是一直获取上次的数据, 除非清空缓存this.pre = SetActivity.this.getSharedPreferences("time", Context.MODE_MULTI_PROCESS);this.pre_editor = pre.edit();//指定该SharedPreferences数据可以跨进称调用this.preferences = SetActivity.this.getSharedPreferences("switch", Context.MODE_MULTI_PROCESS);this.editor = preferences.edit();//每次创建该activity时,从preferences中读取switch_quietButton和switch_remindButton的开关信息的数据Boolean quiet_status = preferences.getBoolean("switch_quiet", false);Boolean remind_status = preferences.getBoolean("switch_remind", false);switch_quietButton.setChecked(quiet_status);switch_remindButton.setChecked(remind_status);//为返回按钮绑定监听器backButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {finish();//Intent intent = new Intent(Set.this,MainActivity.class);//intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);//刷新//startActivity(intent);}});//为自动静音开关按钮绑定监听器switch_quietButton.setOnCheckedChangeListener(new OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {//启动自动静音的serviceIntent intent = new Intent();intent.setAction("zyb.org.service.QUIET_SERVICE");if(isChecked){if(startService(intent) != null)Toast.makeText(SetActivity.this, "成功开启,上课期间的来电将自动转为振动模式", 3000).show();else{Toast.makeText(SetActivity.this, "未能成功开启,请重新尝试", 3000).show();switch_quietButton.setChecked(false);}}else{if(stopService(intent))Toast.makeText(SetActivity.this, "成功关闭,恢复到原来的响铃模式", 3000).show();else{Toast.makeText(SetActivity.this, "未能成功关闭,请重新尝试", 3000).show();switch_quietButton.setChecked(true);}audioManager.setRingerMode(orgRingerMode);}//将开关信息数据保存进preferences中SetActivity.this.editor.putBoolean("switch_quiet", isChecked);editor.commit();}});//为课前提醒开关按钮绑定监听器switch_remindButton.setOnCheckedChangeListener(new OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {if(isChecked){showDialog(SINGLE_DIALOG);}else{alarmManager.cancel(pi);}//将开关信息数据保存进preferences中SetActivity.this.editor.putBoolean("switch_remind", isChecked);editor.commit();}});}@Override//该方法返回的Dialog将被showDialog()方法回调protected Dialog onCreateDialog(int id, Bundle args) {//判断生成何种类型的对话框if(id == SINGLE_DIALOG){Builder b = new AlertDialog.Builder(this);// 设置对话框的标题b.setTitle("选择课前提醒时间");// 为对话框设置多个列表,参数-1表示默认不选中任何选项b.setSingleChoiceItems(R.array.set_remind, -1, new DialogInterface.OnClickListener(){@Overridepublic void onClick(DialogInterface dialog,int which){switch (which){case 0:time_choice = 5;break;case 1:time_choice = 10;break;case 2:time_choice = 20;break;case 3:time_choice = 30;break;case 4:time_choice = 40;break;case 5:time_choice = 50;break;case 6:time_choice = 60;break;}}});// 添加一个“确定”按钮,用于关闭该对话框b.setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {//System.out.println("SetActivity:" + time_choice);if(time_choice == 0){Toast.makeText(SetActivity.this, "请选择课前提醒的时间", 3000).show();switch_remindButton.setChecked(false);}else{SetActivity.this.pre_editor.putInt("time_choice", time_choice);pre_editor.commit();//从当前时间开始,每隔一分钟启动一次pi指定的组件,即发送一次广播alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 60000, pi);Toast.makeText(SetActivity.this, "设置成功,系统将在课前" + time_choice + "分钟提醒您", Toast.LENGTH_LONG).show();}}});//添加一个“取消”按钮b.setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {switch_remindButton.setChecked(false);}});// 创建对话框return b.create(); }elsereturn null;}//如果点击“关于我们”的TextView,则跳转public void click_us(View v){Intent intent = new Intent(SetActivity.this, AboutUsActivity.class);startActivity(intent);}//如果点击“版本支持”的TextView,则跳转public void click_version(View v){Intent intent = new Intent(SetActivity.this, VersionActivity.class);startActivity(intent);}public void click_revision(View v){Log.i("MyDebug", "revision");} }

布局文件,与文件对应
<?xml version="1.0" encoding="utf-8"?>                                                                                  

文件,设置上课自动将铃声转为震动的后台服务
package zyb.org.service;import java.util.Timer;import java.util.TimerTask;import temp.DataBase;import temp.ShareMethod;import android.app.Service;import android.content.Intent;import android.database.Cursor;import android.media.AudioManager;import android.os.IBinder;public class SetQuietService extends Service {//保存时间,temp[day][row][time]表示第day+1个tab选项卡中的第row+1个行中第time+1个表示时间的字符串String[][][] temp = new String[7][12][2];//取得数据库,并定义保存每张表数据的cursor集合DataBase db = new DataBase(SetQuietService.this);Cursor[] cursor = new Cursor[7];@Overridepublic IBinder onBind(Intent arg0){return null;}@Overridepublic void onCreate() {super.onCreate();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) { //声明一个获取系统音频服务的类的对象 final AudioManager audioManager = (AudioManager)getSystemService(Service.AUDIO_SERVICE); //获取手机之前设置好的铃声模式 final int orgRingerMode = audioManager.getRingerMode(); //每隔一分钟从数据库中取以此数据,获得一次当前的时间,并与用用户输入的上下课时间比较,如果相等,则执行相应的静音或者恢复铃声操作new Timer().schedule(new TimerTask() {@Overridepublic void run() { //取出数据库中每日的数据,保存在cursor数组中 for(int i=0;i<7;i++){cursor[i]=db.select(i);}//从数据库取出用户输入的上课和下课时间,用来设置上课自动静音for(int day=0;day<7;day++){ for(int row=0;row<12;row++){cursor[day].moveToPosition(row);for(int time=0;time<2;time++){temp[day][row][time] = cursor[day].getString(time+5);} if(!temp[day][row][0].equals(""))temp[day][row][0] = temp[day][row][0].substring(temp[day][row][0].indexOf(":")+2);}}//获取当前的是星期几int currentDay = ShareMethod.getWeekDay();for(int j=0;j<12;j++){//获取手机当前的铃声模式int currentRingerMode = audioManager.getRingerMode();  if(temp[currentDay][j][0].equals(ShareMethod.getTime()) && currentRingerMode!=AudioManager.RINGER_MODE_VIBRATE){audioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);//System.out.println("class is on");}if(temp[currentDay][j][1].equals(ShareMethod.getTime()) && currentRingerMode==AudioManager.RINGER_MODE_VIBRATE){audioManager.setRingerMode(orgRingerMode);//System.out.println("class is over");}   } }}, 0, 60000);return super.onStartCommand(intent, flags, startId);}}

文件,设置课前提醒的BroadcastReceiver类
package zyb.org.service;import java.util.Calendar;import java.util.Date;import temp.DataBase;import temp.ShareMethod;import zyb.org.editschedule.RemindActivity;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.SharedPreferences;import android.database.Cursor;public class RemindReceiver extends BroadcastReceiver {//定义保存每张表数据的cursor集合Cursor[] cursor = new Cursor[7];//保存时间,temp[day][row][hm]表示第day+1个tab选项卡中的第row+1个行中用户输入的第一个(即课程开始)时间拆分为时和分//hm为0时表示时,1表示分,2时代表时和分的组合,即未拆分前的字符串String[][][] temp = new String[7][12][3];//将temp数组中的字符串转化为相应的正数,这里去掉了时和分的组合int[][][] start_time = new int[7][12][2];private int advance_time;@Overridepublic void onReceive(Context arg0, Intent arg1) {//取得数据库DataBase db = new DataBase(arg0);//取出数据库中每日的数据,保存在cursor数组中for(int i=0;i<7;i++){cursor[i]=db.select(i);}//从数据库取出用户输入的上课的时和分,用来设置课前提醒for(int day=0;day<7;day++){ for(int row=0;row<12;row++){cursor[day].moveToPosition(row);temp[day][row][2] = cursor[day].getString(5); if(!temp[day][row][2].equals("")){ temp[day][row][2] = temp[day][row][2].substring(temp[day][row][2].indexOf(":")+2); temp[day][row][0] = temp[day][row][2].substring(0, temp[day][row][2].indexOf(":")); temp[day][row][1] = temp[day][row][2].substring(temp[day][row][2].indexOf(":")+1); } else{ temp[day][row][0] = temp[day][row][1] = "0"; } for(int hm=0;hm<2;hm++){ start_time[day][row][hm] = Integer.parseInt(temp[day][row][hm]); }}}//从该context中启动提醒的activity,根据SDK文档的说明,需要加上addFlags()一句Intent remind_intent = new Intent(arg0, RemindActivity.class);remind_intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//获取提前提醒的时间值,如果没有获取到则取默认值30分钟//int advance_time = arg1.getIntExtra("anvance_remindtime", 20);//这里模式一定要设置为MODE_MULTI_PROCESS,否则即使相应的xml文件中数据有更新,RemindReceiver中也不能获取更新后的数据,而是一直获取上次的数据, 除非清空缓存SharedPreferences pre = arg0.getSharedPreferences("time", Context.MODE_MULTI_PROCESS);advance_time = pre.getInt("time_choice", 30);int currentday = ShareMethod.getWeekDay();//System.out.println(advance_time);Calendar c = Calendar.getInstance();//获取当前的时和分int current_hourOfDay = c.get(Calendar.HOUR_OF_DAY);int current_minute = c.get(Calendar.MINUTE);//定义一个标志位,用来排除掉重复的提醒boolean flag = true;//循环判断当天的课前提醒for(int i=0;i<12;i++){if(!(start_time[currentday][i][0]==0 && start_time[currentday][i][1]==0)){//将calendar的时和分设置为提醒时候的时和分c.set(Calendar.HOUR_OF_DAY, start_time[currentday][i][0]);c.set(Calendar.MINUTE, start_time[currentday][i][1]);long remind_time = c.getTimeInMillis()-advance_time*60*1000;Date date=new Date(remind_time);c.setTime(date);//获取设置的提醒的时和分int hourOfDay = c.get(Calendar.HOUR_OF_DAY);int minute = c.get(Calendar.MINUTE);//如果到了设定的提醒时间,就启动提醒的activityif(hourOfDay==current_hourOfDay && minute==current_minute){if(flag){arg0.startActivity(remind_intent);//System.out.println("time remind" + i);flag = false;}}else{flag = true;}}}}}

文件,监听系统开机事件,设置是否开机自启动SetQuietService服务
package zyb.org.service;import android.app.AlarmManager;import android.app.PendingIntent;import android.app.Service;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.SharedPreferences;public class LauncherReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context arg0, Intent arg1) {//LauncherReceiver用来监听系统开机事件,如果之前已经设置了启动SetQuietService,即quiet_status为true,//而后来因为某种原因关机了,则开机启动SetQuietServiceSharedPreferences preferences = arg0.getSharedPreferences("switch", Context.MODE_MULTI_PROCESS);Boolean quiet_status = preferences.getBoolean("switch_quiet", false);Boolean remind_status = preferences.getBoolean("switch_remind", false);Intent quiet_intent = new Intent(arg0,SetQuietService.class);Intent remind_intent = new Intent(arg0,RemindReceiver.class);PendingIntent pi_remind = PendingIntent.getBroadcast(arg0, 0, remind_intent, 0);AlarmManager am = (AlarmManager)arg0.getSystemService(Service.ALARM_SERVICE);if(quiet_status){arg0.startService(quiet_intent);}if(remind_status){am.setRepeating(AlarmManager.RTC, System.currentTimeMillis(), 60000, pi_remind);}else{am.cancel(pi_remind);}}}

文件,该Activity对应的是一个悬浮的界面,当到了预设的课前提醒时间时,便启动该Activity
package zyb.org.editschedule;import zyb.org.androidschedule.R;import android.app.Activity;import android.app.AlertDialog;import android.app.Service;import android.content.Context;import android.content.DialogInterface;import android.content.SharedPreferences;import android.content.DialogInterface.OnClickListener;import android.os.Bundle;import android.os.Vibrator;public class RemindActivity extends Activity{private Vibrator vibrator;@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);SharedPreferences pre = getSharedPreferences("time", Context.MODE_MULTI_PROCESS);int advance_time = pre.getInt("time_choice", 30);//获取系统的vibrator服务,并设置手机振动2秒vibrator = (Vibrator)getSystemService(Service.VIBRATOR_SERVICE);vibrator.vibrate(2000);// 创建一个对话框final AlertDialog.Builder builder= new AlertDialog.Builder(RemindActivity.this);builder.setIcon(R.drawable.ic_launcher);builder.setTitle("温馨提示");builder.setMessage("童鞋,还有" + advance_time + "分钟就要上课了哦!");builder.setPositiveButton("确定" ,new OnClickListener(){@Overridepublic void onClick(DialogInterface dialog , int which){// 结束该ActivityRemindActivity.this.finish();}}).show();}@Overridepublic void onBackPressed() {super.onBackPressed();// 结束该ActivityRemindActivity.this.finish();}}

点击“关于作者”和“软件相关”,会分别跳转到文件和文件,这两个文件及其相应的布局文件比较简单,不再附上。

    网友提醒忘了附上list_v2.xml,list_v.xml和edit_shedule.xml三个布局文件,补充一点:list_v.xml是我第一次设定的listview内的每个item内的布局文件,后来改为了list_v2.xml,在项目中并没有引用list_v.xml文件,因此这里只贴出list_v2.xml和edit_shedule.xml两个布局文件,分别如下:  

 list_v2.xml文件

<?xml version="1.0" encoding="UTF-8"?>                                                                       

 

 edit_shedule.xml文件

<?xml version="1.0" encoding="utf-8"?>                                                                                                                                                                       


  



更多相关文章

  1. Android(安卓)APK权限提升到System
  2. Android(安卓)Studio第一次启动的Fetching android sdk componen
  3. Android中打电话的数据流程
  4. Android(安卓)属性动画 源码解析 深入了解其内部实现
  5. Android(安卓)10 创建文件失败
  6. Android下SQLite3数据库操作笔记
  7. mybatisplus的坑 insert标签insert into select无参数问题的解决
  8. python起点网月票榜字体反爬案例
  9. NPM 和webpack 的基础使用

随机推荐

  1. 《Android经验分享》周刊第8期
  2. android中Invalidate和postInvalidate的
  3. 加快Android单模块编译
  4. Android高效编程注意事项
  5. Android的SDK,NDK以及JNI
  6. Android(安卓)Studio快捷键设置成跟Eclip
  7. Android模拟器环境中安装和删除应用程序
  8. 浅谈android的selector,背景选择器
  9. Android中Launcher对于AppWidget处理的分
  10. android 获取uri的正确文件路径的办法