2023年7月7日发(作者:)
Android多功能课程表项⽬实现(完整版) 鉴于很多⽹友发私信或者留⾔想我所要课程表项⽬源码,我这⾥将其开源到我的Github上: ⼯欲善其事,必先利其器,刚接触Android⼀个⽉的时候,便准备做⼀款Android平台下的多功能课程表,做了⼀周多,便出去实习了,近⼏个⽉⼀直在忙公司(实习)的事情,利⽤断断续续的闲暇时间,将该APP做出来了,虽说这东东不算难做,但真要做起来,遇到的问题还是蛮多的,在不断的发现问题与解决问题中成长,也是对⾃⼰的⼀种锻炼。【基本功能】
编辑、添加、删除和查看课程表;
【核⼼功能】
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保存⼀标志位,判断是否是第⼀次创建数据库表。详细的⼯程⽂件截图如下:
各⽂件的源代码如下,详细的注释代码⾥⾯都有,这⾥不再详细说明:<>⽂件
android:name="Activity" android:theme="@android:style/" > android:name="Receiver" android:process=":remote"> android:name="erReceiver" android:process=":remote">
android:name="etService" >
<>⽂件,⽤来设置启动画⾯ package ;import tivity;import dschedule.R;import ty;import ;import ormat;import ;import r;import Manager;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) { te(savedInstanceState);
getWindow().setFormat(_8888); getWindow().addFlags(_DITHER); setContentView(ty_load);
new Handler().postDelayed(new Runnable() { public void run() { //Go to main activity, and finish load activity Intent mainIntent = new Intent(, ); ctivity(mainIntent); (); } }, LOAD_DISPLAY_TIME);
}}
package dschedule;import se;import ication;import og;import ethod;import ivity;import anager;import ;import ty;import ialog;import ialog;import e;import t;import Interface;import ;import Preferences;import ;import CursorAdapter;import ;import eDetector;import ;import em;import Event;import ;import kListener;import hListener;import rView;import ClickListener;import ew;import t;import get;import ew;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;
@Override protected void onCreate(Bundle savedInstanceState) { te(savedInstanceState); setContentView(ty_main);
//将该activity加⼊到MyApplication对象实例容器中 tance().addActivity(this);
db=new DataBase(); pre=getSharedPreferences("firstStart",_PRIVATE); /* * 判断程序是否第⼀次运⾏,如果是创建数据库表 */ if(lean("firstStart", true)){ Table(); (()).putBoolean("firstStart",false).commit();// finish();
}
exitButton = (TextView)findViewById(tton); setButton = (TextView)findViewById(ton); list[0] = (ListView)findViewById(0); list[1] = (ListView)findViewById(1);
list[2] = (ListView)findViewById(2); list[3] = (ListView)findViewById(3);
list[4] = (ListView)findViewById(4);
list[5] = (ListView)findViewById(5); list[5] = (ListView)findViewById(5); list[6] = (ListView)findViewById(6);
tabs = (TabHost)findViewById(t); //创建⼿势检测器 detector = new GestureDetector(this, new DetectorGestureListener());
//在配置任何的TabSpec之前,必须在TabHost上调⽤该⽅法 ();
//为主界⾯注册七个选项卡 c spec = null; addCard(spec,"tag1",0,"⽇"); addCard(spec,"tag2",1,"⼀"); addCard(spec,"tag3",2,"⼆"); addCard(spec,"tag4",3,"三"); addCard(spec,"tag5",4,"四"); addCard(spec,"tag6",5,"五"); addCard(spec,"tag7",6,"六");
//修改tabHost选项卡中的字体的颜⾊ TabWidget tabWidget = Widget(); for(int i=0;i } //设置打开时默认的选项卡是当天的选项卡 rentTab(kDay()); //⽤适配器为各选项卡添加所要显⽰的内容 for(int i=0;i<7;i++){ cursor[i]=(i); list[i].setAdapter(adapter(i)); } //声明⼀个获取系统⾳频服务的类的对象 final AudioManager audioManager = (AudioManager)getSystemService(_SERVICE); //获取⼿机之前设置好的铃声模式,该数据将⽤来传递给activity_set final int orgRingerMode = gerMode(); //为退出按钮绑定监听器 lickListener(new OnClickListener() { @Override public void onClick(View v) { //创建r对象,该对象是AlterDialog的创建器,AlterDialog⽤来创建弹出对话框 final r builder = new r(); exit(builder); } }); //为设置按钮绑定监听器 lickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(, ); //将orgRingerMode数据传给activity_set ra("mode_ringer", orgRingerMode); startActivity(intent); } }); for( int day=0;day<7;day++){ //为七个ListView绑定触碰监听器,将其上的触碰事件交给GestureDetector处理 //此监听器是必须的,不然滑动⼿势只在ListView下的空⽩区域有效,⽽在ListView上⽆效 //此监听器是必须的,不然滑动⼿势只在ListView下的空⽩区域有效,⽽在ListView上⽆效 list[day].setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return hEvent(event); } }); //为每个ListView的每个item绑定监听器,点击则弹出由AlertDialog创建的列表对话框进⾏选择 list[day].setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView> arg0, View arg1, final int id, long arg3) { final int currentDay=rentTab(); final int n=id; final r builder = new r(); n(_launcher); le("选择"); TextView tv=(TextView)ewById(0); Log.i("Test",(t().toString().equals(""))+""); //如果课程栏⽬为空就启动添加对话框 if((t()).toString().equals("")){ //通过数组资源为对话框中的列表添加选项内容,这⾥只有⼀个选项 ms(_options1, new kListener() { @Override public void onClick(DialogInterface dialog, int which) { //如果单击了该列表项,则跳转到编辑课程信息的界⾯ if(which == 0){ new MyDialog().add(currentDay,n); } } }); ().show(); } //否则启动修改对话框,或直接删除数据 else{ ms(_options2, new kListener() { @SuppressWarnings("deprecation") @Override public void onClick(DialogInterface dialog, int which) { //如果单击了该列表项,则跳转到编辑课程信息的界⾯ if(which == 0){ new MyDialog().modify(currentDay,n); } if(which == 1){ cursor[currentDay].moveToPosition(n); int n1=nt(cursor[currentDay].getString(7));//课程的总节数 int n2=nt(cursor[currentDay].getString(8));//选中的为该课程的第⼏节 switch(n2){ case 0: for(int m=0;m case 1: Data(currentDay,n); for(int m=1;m case 2: Data(currentDay,n-1); Data(currentDay,n-1); Data(currentDay,n); for(int m=2;m } //内部类,实现ureListener接⼝ class DetectorGestureListener implements ureListener{ @Override public boolean onDown(MotionEvent e) { return false; } //当⽤户在触屏上“滑过”时触发此⽅法 @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { int i = rentTab(); //第⼀个触点事件的X坐标值减去第⼆个触点事件的X坐标值超过FLIP_DISTANCE,也就是⼿势从右向左滑动 if(() - () > FLIP_DISTANCE){ if(i<6) rentTab(i+1); // float currentX = (); // list[i].setRight((int) (inialX - currentX)); return true; } //第⼆个触点事件的X坐标值减去第⼀个触点事件的X坐标值超过FLIP_DISTANCE,也就是⼿势从左向右滑动 else if(() - () > FLIP_DISTANCE){ if(i>0) rentTab(i-1); return true; } return false; } @Override public void onLongPress(MotionEvent e) { } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; return false; } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { return false; } } //覆写Activity中的onTouchEvent⽅法,将该Activity上的触碰事件交给GestureDetector处理 @Override public boolean onTouchEvent(MotionEvent event) { return hEvent(event); } //设置菜单按钮 @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(ty_main, menu); return true; } //当点击菜单中的“退出”键时,弹出提⽰是否退出的对话框 @Override public boolean onOptionsItemSelected(MenuItem item) { //创建r对象,该对象是AlterDialog的创建器,AlterDialog⽤来创建弹出对话框 final r builder = new r(this); if(mId() == _exit){ exit(builder); return true; } if(mId() == _settings){ Intent intent = new Intent(, ); startActivity(intent); return true; } return onsItemSelected(item); } //⼦ ⽅法:为主界⾯添加选项卡 public void addCard(c spec,String tag,int id,String name){ spec = Spec(tag); tent(id); icator(name); (spec); } //⼦⽅法:⽤来弹出是否退出程序的对话框,并执⾏执⾏是否退出操作 public void exit(r builder){ //为弹出的对话框设置标题和内容 n(_launcher); le("退出程序"); sage("确定要退出随⾝课程表吗?"); //设置左边的按钮为“确定”键,并且其绑定监听器,点击后退出 itiveButton("确定", new kListener() { @Override public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) { //退出应⽤程序,即销毁地所有的activity tance().exitApp(); } }); //设置右边的按钮为“取消”键,并且其绑定监听器,点击后仍然停留在当前界⾯ ativeButton("取消", new kListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); //创建并显⽰弹出的对话框 ().show(); } /* * 为每⼀个list提供数据适配器 */ @SuppressWarnings("deprecation") public SimpleCursorAdapter adapter(int i){ return new SimpleCursorAdapter(this, _v2,cursor[i],new String[]{"_id","classes","location", "teacher","zhoushu"},new int[]{,0,1,6,7} ); } /* * 第⼀次运⾏时创建数据库表 */ static class SingleInstance{ static SingleInstance si; private SingleInstance(){ for(int i=0;i<7;i++){ Table(i); } } static SingleInstance createTable(){ if(si==null) return si=new SingleInstance(); return null; } }} android:id="@+id/tabhost" android:layout_width="match_parent" android:layout_height="match_parent" > android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" > android:id="@android:id/tabs" android:background="@drawable/tab_bar" android:layout_width="match_parent" android:layout_height="50dip"/> android:id="@android:id/tabcontent" android:background="@drawable/menu_bg" android:layout_width="match_parent" android:layout_height="match_parent" > android:id="@+id/list0" android:scrollbars="none" android:layout_width="match_parent" android:layout_height="wrap_content" android:divider="#0099ff" android:dividerHeight="0.5dip" /> android:id="@+id/list1" android:scrollbars="none" android:layout_width="match_parent" android:layout_height="wrap_content" android:divider="#0099ff" android:dividerHeight="0.5dip" /> android:dividerHeight="0.5dip" /> android:id="@+id/list2" android:scrollbars="none" android:layout_width="match_parent" android:layout_height="wrap_content" android:divider="#0099ff" android:dividerHeight="0.5dip" /> android:id="@+id/list3" android:scrollbars="none" android:layout_width="match_parent" android:layout_height="wrap_content" android:divider="#0099ff" android:dividerHeight="0.5dip" /> android:id="@+id/list4" android:scrollbars="none" android:layout_width="match_parent" android:layout_height="wrap_content" android:divider="#0099ff" android:dividerHeight="0.5dip" /> android:id="@+id/list5" android:scrollbars="none" android:layout_width="match_parent" android:layout_height="wrap_content" android:divider="#0099ff" android:dividerHeight="0.5dip" /> android:id="@+id/list6" android:scrollbars="none" android:layout_width="match_parent" android:layout_height="wrap_content" android:divider="#0099ff" android:dividerHeight="0.5dip" /> package temp;import tValues;import t;import ;import Database;import OpenHelper;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); } @Override public 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))"; L(sql); } } @Override public void onUpgrade(SQLiteDatabase db, int oleVersion, int newVersion) { for(int i=0;i<7;i++){ String sql="DROP TABLE IF EXISTS "+TB_NAME[i]; L(sql); } onCreate(db); } public Cursor select(int i){ SQLiteDatabase db=dableDatabase(); Cursor cursor=(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=tableDatabase(); ContentValues cv=new ContentValues(); (CLASS,cla); (LOCA, loca); (TEACHER,tea); (ZHOUSHU,zhou); (JIESHU,jie); (TIME1,time1); (TIME2,time2); (WHICH,which); long row=(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=tableDatabase(); String where="_id = ?"; String[] whereValues={ng(_id)}; ContentValues cv=new ContentValues(); if(!("")) (CLASS,cla); if(!("")) (LOCA, loca); if(!("")) (TEACHER,tea); if(!("")) (ZHOUSHU,zhou); if(!("")) (JIESHU,jie); if(!("")) (TIME1,time1); if(!("")) (TIME2,time2); if(!("")) (WHICH,which); (TB_NAME[i], cv, where, whereValues); } public void deleteData(int i,int _id){ SQLiteDatabase db=tableDatabase(); String where="_id = ?"; String[] whereValues={ng(_id)}; ContentValues cv=new ContentValues(); ("classes",""); ("location",""); ("teacher",""); ("zhoushu",""); ("jieshu",""); ("time1",""); ("time2",""); ("which",""); (TB_NAME[i], cv, where, whereValues); } public void delete(int i,int _id){ SQLiteDatabase db=tableDatabase(); String where="_id = ?"; String[] whereValues={ng(_id)}; (TB_NAME[i], where, whereValues); } public void createTable(int j){ for(int i=1;i<=12;i++) insert(j,"", "", "","","","","",""); } }<>⽂件package temp;import tivity;import t;public class MyAdapter { private Context context; private MainActivity main; public MyAdapter(Context context){ t=context; main=(MainActivity) context; } }<>⽂件,定义编辑课表信息时显⽰的对话框 package temp;import ar;import tivity;import dschedule.R;import ialog;import r;import ckerDialog;import t;import Interface;import kListener;import ;import Inflater;import ;import ;import ;import xt;import ew;import cker;import ;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){ t=context; main=(MainActivity) context; adapter=new MyAdapter(context); } /* * 点击未编辑的课程列表跳出”添加课程“对话框 */ public void add(final int day,final int n){ //填装对话框的view inflater=(context); view=e(_shedule,null); findWidgetes();//取部件 final Button course_time1=(Button)ewById(1); final Button course_time2=(Button)ewById(2); //为两个输⼊时间的按钮绑定监听器 course_lickListener(new kListener() { @Override public void onClick(View v) { TimeSet_Dialog(course_time1); } }); course_lickListener(new kListener() { @Override public void onClick(View v) { TimeSet_Dialog(course_time2); } }); builder=new r(context) .setIcon(_launcher) .setTitle("编辑课程信息") .setView(view) .setPositiveButton("确认",new OnClickListener(){ @SuppressWarnings("deprecation") @Override public void onClick(DialogInterface arg0, int arg1) { if(!(s1=course_t().toString()).equals("")) s1="课程: "+s1; if(!(s2=course_t().toString()).equals("")) s2="地点: "+s2; if(!(s2=course_t().toString()).equals("")) s2="地点: "+s2; if(!(s3=course_t().toString()).equals("")) s3="⽼师: "+s3; if(!(s4=course_t().toString()).equals("")) s4="周数: "+s4; if(!(s6=course_t().toString()).equals("")) s6="时间: "+s6; if(!(s7=course_t().toString()).equals("")) ; if((s5=course_t().toString()).equals("")||("")) { xt(context, "请正确输⼊课程及节数!", 3000).show(); return; } else { int i=nt(());//i为节数 for(int m=0;m } [day].requery(); [day].invalidate(); } }) .setNegativeButton("取消", new OnClickListener(){ @Override public void onClick(DialogInterface arg0, int arg1) { } }); ().show(); } /* * 点击已编辑的课程列表跳出”修改课程信息或删除课程信息“对话框 */ public void modify(final int day,final int n){ //填装对话框的view inflater=(context); view=e(_shedule,null); findWidgetes();//取部件 final Button course_time1=(Button)ewById(1); final Button course_time2=(Button)ewById(2); //为两个输⼊时间的按钮绑定监听器 course_lickListener(new kListener() { @Override public void onClick(View v) { TimeSet_Dialog(course_time1); } }); course_lickListener(new kListener() { @Override public void onClick(View v) { TimeSet_Dialog(course_time2); } }); //从数据库取出旧数据 [day].moveToPosition(n); String [] temp=new String[8]; for(int i=0;i<8;i++) {temp[i]=[day].getString(i+1);} for(int i=0;i<8;i++) {temp[i]=[day].getString(i+1);} //将旧数据显⽰在编辑对话框 if(!temp[0].equals("")) course_t(temp[0].substring(temp[0].indexOf(":")+2)); if(!temp[1].equals("")) course_t(temp[1].substring(temp[1].indexOf(":")+2)); if(!temp[2].equals("")) course_t(temp[2].substring(temp[2].indexOf(":")+2)); if(!temp[3].equals("")) course_t(temp[3].substring(temp[3].indexOf(":")+2)); if(!temp[4].equals("")) course_t(temp[4].substring(temp[4].indexOf(":")+2)); course_t(temp[5]); course_t(temp[6]); date(); builder=new r(context) .setIcon(_launcher) .setTitle("修改课程信息") .setView(view) .setPositiveButton("确认",new OnClickListener(){ @SuppressWarnings("deprecation") @Override public void onClick(DialogInterface arg0, int arg1) { if(!(s1=course_t().toString()).equals("")) s1="课程: "+s1; if(!(s2=course_t().toString()).equals("")) s2="地点: "+s2; if(!(s3=course_t().toString()).equals("")) s3="⽼师: "+s3; if(!(s4=course_t().toString()).equals("")) s4="周数: "+s4; if(!(s6=course_t().toString()).equals(""))s6="时间: "+s6; if(!(s7=course_t().toString()).equals("")); s5=course_t().toString(); [day].moveToPosition(n); int n1=nt([day].getString(7).trim());//课程的总节数 int n2=nt([day].getString(8).trim());//选中的为该课程的第⼏节 Log.i("kkk",[day].getString(7)); //如果没有再次输⼊节数或节数没有变化,根据选中的为第⼏节更新前后节的数据即可 if(("")||n1==nt(())) { switch(n2){ case 0: for(int m=0;m case 1: (day,n,s1,s2,s3,s4,s5,s6,s7,"0"); for(int m=1;m case 2: (day,n-1,s1,s2,s3,s4,s5,s6,s7,"0"); (day,n,s1,s2,s3,s4,s5,s6,s7,"1"); for(int m=2;m } //若节数有变化,先确定新节数并赋予旧的数据再更新数据 else{ int n3=nt(()); //扩充节数 //扩充节数 if(n3>n1){ switch(n2){//更新数据 case 0: for(int m=0;m case 1: (day,n,s1,s2,s3,s4,s5,s6,s7,"0"); for(int m=1;m case 2: (day,n-1,s1,s2,s3,s4,s5,s6,s7,"0"); (day,n,s1,s2,s3,s4,s5,s6,s7,"1"); for(int m=2;m } //缩减节数:删除旧数据再根据新的节数赋予旧数据最后更新新数据 if(n3 for(int m=0;m case 1: Data(day,n); for(int m=1;m case 2: Data(day,n-1); Data(day,n); for(int m=2;m switch(n2){//更新数据 case 0: case 0: for(int m=0;m case 1: (day,n,s1,s2,s3,s4,s5,s6,s7,"0"); for(int m=1;m case 2: (day,n-1,s1,s2,s3,s4,s5,s6,s7,"0"); (day,n,s1,s2,s3,s4,s5,s6,s7,"1"); for(int m=2;m } } [day].requery(); [day].invalidate(); } }) .setNegativeButton("取消", new OnClickListener(){ @Override public void onClick(DialogInterface arg0, int arg1) { } }); ().show(); } private void findWidgetes(){ course_name=(EditText)ewById(xt1); course_address=(EditText)ewById(xt2); course_teacher=(EditText)ewById(xt3); course_week=(EditText)ewById(xt4);// course_time1=(EditText)ewById(1);// course_time2=(EditText)ewById(2); course_count=(EditText)ewById(); } public void TimeSet_Dialog(final TextView text){ Calendar c = tance(); // 创建⼀个TimePickerDialog实例,并把它显⽰出来。 new TimePickerDialog(main, // 绑定监听器 new SetListener() { @Override public void onTimeSet(TimePicker tp, int hourOfDay,int minute){ public void onTimeSet(TimePicker tp, int hourOfDay,int minute){ //获取完整的时间,在只有⼀位的数字前⾯加0 StringBuffer s_hour = new StringBuffer(); StringBuffer s_minute = new StringBuffer(); s_(hourOfDay); s_(minute); if(hourOfDay<10){ s_(0,"0"); } if(minute<10){ s_(0,"0"); } //将结果显⽰在edit中 t(s_ng() + ":" + s_ng()); } } //设置初始时间 , (_OF_DAY) , () //true表⽰采⽤24⼩时制 , true).show(); }}<>⽂件,主要在其中定义⼀个放置Activity的容器,没建⽴⼀个Activity,便将其放⼊其中,在退出应⽤程序时候,遍历销毁所有的Activity package temp;import List;import ;import ty;import ation;//MyApplication类⽤来存储每⼀个activity,并实现关闭所有activity的操作public class MyApplication extends Application { //定义容activity容器 private List private MyApplication(){} //单例设计模式中取得唯⼀的MyApplication实例 public static MyApplication getInstance(){ if(instance == null) instance = new MyApplication(); return instance; } //添加activity到容器中 public void addActivity(Activity activity){ (activity); } //遍历所有的activity并finish public void exitApp(){ for(Activity activity : activityList){ if(activity != null) (); } (0); } //清空缓存 @Override public void onLowMemory() { emory(); (); } }<>⽂件,定义⼀些公⽤的⽅法,这些⽅法主要在后⾯的Service及BroadcastReceiver相关类中⽤到 package temp;import ar;import ;public class ShareMethod { //获取当天是星期⼏,这⾥星期七、⼀......分别为数字0、1...... public static int getWeekDay(){ Calendar calendar=tance(); Date date=new Date(tTimeMillis()); e(date); int weekDay=(_OF_WEEK)-1; return weekDay; } //获取当前的时间,并以字符串"xx:xx"的形式返回 public static String getTime(){ Calendar c=tance(); int hourOfDay = (_OF_DAY); int minute = (); //获取完整的时间,在只有⼀位的数字前⾯加0 StringBuffer s_hour = new StringBuffer(); StringBuffer s_minute = new StringBuffer(); s_(hourOfDay); s_(minute); if(hourOfDay<10){ s_(0,"0"); } if(minute<10){ s_(0,"0"); } return s_ng() + ":" + s_ng(); } }<>⽂件,设置类,点击“设置”按钮,便跳转到该Activity package hedule;import ication;import sActivity;import dschedule.R;import Receiver;import nActivity;import ty;import anager;import ialog;import ;import gIntent;import e;import r;import t;import Interface;import ;import Preferences;import anager;import ;import ;import ;import kListener;import ndButton;import ndButton;import kedChangeListener;import ;import ew;import ;public class SetActivity extends Activity { //声明⼀个SharedPreferences对象,⽤来保存switch组件的开关信息 private SharedPreferences preferences = null; //editor对象⽤来向preferences中写⼊数据 private editor = null; //声明⼀个SharedPreferences对象,⽤来保存time_choice的值 private SharedPreferences pre = null; //pre_editor对象⽤来向pre中写⼊数据 private 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; @Override protected void onCreate(Bundle savedInstanceState) { te(savedInstanceState); setContentView(ty_set); //将该activity加⼊到MyApplication对象实例容器中 tance().addActivity(this); //声明⼀个获取系统⾳频服务的类的对象 final AudioManager audioManager = (AudioManager)getSystemService(_SERVICE); //从MainAcivity中获取原始设置的铃声模式 Intent intent = getIntent(); final int orgRingerMode = Extra("mode_ringer", _MODE_NORMAL); //获取系统的闹钟定时服务 alarmManager = (AlarmManager)getSystemService(_SERVICE); //指定alarmManager要启动的组件 alarm_receiver = new Intent(,);// alarm_ra("anvance_remindtime", time_choice); pi = adcast(, 0, alarm_receiver, 0); //取出各组件 TextView backButton = (TextView)findViewById(MainButton); switch_quietButton = (Switch)findViewById(_quiet); switch_remindButton = (Switch)findViewById(_remind); = redPreferences("time", _MULTI_PROCESS); _editor = (); //指定该SharedPreferences数据可以跨进称调⽤ ences = redPreferences("switch", _MULTI_PROCESS); = (); //每次创建该activity时,从preferences中读取switch_quietButton和switch_remindButton的开关信息的数据 Boolean quiet_status = lean("switch_quiet", false); //这⾥模式⼀定要设置为MODE_MULTI_PROCESS,否则即使相应的xml⽂件中数据有更新,RemindReceiver中也不能获取更新后的数据,⽽是⼀直获取上次的数据 Boolean quiet_status = lean("switch_quiet", false); Boolean remind_status = lean("switch_remind", false); switch_cked(quiet_status); switch_cked(remind_status); //为返回按钮绑定监听器 lickListener(new OnClickListener() { @Override public void onClick(View v) { finish();// Intent intent = new Intent(,);// gs(_ACTIVITY_CLEAR_TOP);//刷新// startActivity(intent); } }); //为⾃动静⾳开关按钮绑定监听器 switch_heckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { //启动⾃动静⾳的service Intent intent = new Intent(); ion("_SERVICE"); if(isChecked){ if(startService(intent) != null) xt(, "成功开启,上课期间的来电将⾃动转为振动模式", 3000).show(); else{ xt(, "未能成功开启,请重新尝试", 3000).show(); switch_cked(false); } } else{ if(stopService(intent)) xt(, "成功关闭,恢复到原来的响铃模式", 3000).show(); else{ xt(, "未能成功关闭,请重新尝试", 3000).show(); switch_cked(true); } gerMode(orgRingerMode); } //将开关信息数据保存进preferences中 lean("switch_quiet", isChecked); (); } }); //为课前提醒开关按钮绑定监听器 switch_heckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if(isChecked){ showDialog(SINGLE_DIALOG); } else{ (pi); } //将开关信息数据保存进preferences中 lean("switch_remind", isChecked); (); } }); } @Override //该⽅法返回的Dialog将被showDialog()⽅法回调 protected Dialog onCreateDialog(int id, Bundle args) { //判断⽣成何种类型的对话框 if(id == SINGLE_DIALOG){ Builder b = new r(this); // 设置对话框的标题 le("选择课前提醒时间"); // 为对话框设置多个列表,参数-1表⽰默认不选中任何选项 gleChoiceItems(_remind, -1, new kListener(){ @Override public 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; } } }); // 添加⼀个“确定”按钮,⽤于关闭该对话框 itiveButton("确定", new kListener() { @Override public void onClick(DialogInterface dialog, int which) {// n("SetActivity:" + time_choice); if(time_choice == 0){ xt(, "请选择课前提醒的时间", 3000).show(); switch_cked(false); }else{ _("time_choice", time_choice); pre_(); //从当前时间开始,每隔⼀分钟启动⼀次pi指定的组件,即发送⼀次⼴播 eating(_WAKEUP, tTimeMillis(), 60000, pi); xt(, "设置成功,系统将在课前" + time_choice + "分钟提醒您", _LONG).show(); } } }); //添加⼀个“取消”按钮 ativeButton("取消", new kListener() { @Override public void onClick(DialogInterface dialog, int which) { switch_cked(false); switch_cked(false); } }); // 创建对话框 return (); } else return null; } //如果点击“关于我们”的TextView,则跳转 public void click_us(View v){ Intent intent = new Intent(, ); startActivity(intent); } //如果点击“版本⽀持”的TextView,则跳转 public void click_version(View v){ Intent intent = new Intent(, ); startActivity(intent); } public void click_revision(View v){ Log.i("MyDebug", "revision"); } } android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="@drawable/edit_background" > android:paddingLeft="10dp" android:text="@string/revision" android:textSize="20sp" android:clickable="true" android:textColor="#058" android:onClick="click_version" /> package e;import ;import ask;import se;import ethod;import e;import ;import ;import anager;import r;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(); Cursor[] cursor = new Cursor[7]; @Override public IBinder onBind(Intent arg0){ return null; } @Override public void onCreate() { te(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { //声明⼀个获取系统⾳频服务的类的对象 final AudioManager audioManager = (AudioManager)getSystemService(_SERVICE); //获取⼿机之前设置好的铃声模式 final int orgRingerMode = gerMode(); //每隔⼀分钟从数据库中取以此数据,获得⼀次当前的时间,并与⽤⽤户输⼊的上下课时间⽐较,如果相等,则执⾏相应的静⾳或者恢复铃声操作 new Timer().schedule(new TimerTask() { @Override public void run() { //取出数据库中每⽇的数据,保存在cursor数组中 for(int i=0;i<7;i++){ cursor[i]=(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 = kDay(); for(int j=0;j<12;j++){ //获取⼿机当前的铃声模式 int currentRingerMode = gerMode(); if(temp[currentDay][j][0].equals(e()) && currentRingerMode!=_MODE_VIBRATE){ gerMode(_MODE_VIBRATE);// n("class is on"); } if(temp[currentDay][j][1].equals(e()) && currentRingerMode==_MODE_VIBRATE){ gerMode(orgRingerMode);// n("class is over"); } } } }, 0, 60000); return tCommand(intent, flags, startId); } }<>⽂件,设置课前提醒的BroadcastReceiver类 package e;import ar;import ;import se;import ethod;import Activity;import astReceiver;import t;import ;import Preferences;import ;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; @Override public void onReceive(Context arg0, Intent arg1) { //取得数据库 //取得数据库 DataBase db = new DataBase(arg0); //取出数据库中每⽇的数据,保存在cursor数组中 for(int i=0;i<7;i++){ cursor[i]=(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] = nt(temp[day][row][hm]); } } } //从该context中启动提醒的activity,根据SDK⽂档的说明,需要加上addFlags()⼀句 Intent remind_intent = new Intent(arg0, ); remind_gs(_ACTIVITY_NEW_TASK); //获取提前提醒的时间值,如果没有获取到则取默认值30分钟// int advance_time = Extra("anvance_remindtime", 20); SharedPreferences pre = redPreferences("time", _MULTI_PROCESS); advance_time = ("time_choice", 30); int currentday = kDay();// n(advance_time); Calendar c = tance(); //获取当前的时和分 int current_hourOfDay = (_OF_DAY); int current_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的时和分设置为提醒时候的时和分 (_OF_DAY, start_time[currentday][i][0]); (, start_time[currentday][i][1]); long remind_time = eInMillis()-advance_time*60*1000; Date date=new Date(remind_time); e(date); //获取设置的提醒的时和分 int hourOfDay = (_OF_DAY); int minute = (); //如果到了设定的提醒时间,就启动提醒的activity if(hourOfDay==current_hourOfDay && minute==current_minute){ if(flag){ ctivity(remind_intent); // n("time remind" + i); flag = false; } }else{ //这⾥模式⼀定要设置为MODE_MULTI_PROCESS,否则即使相应的xml⽂件中数据有更新,RemindReceiver中也不能获取更新后的数据,⽽是⼀直获取上次的数据 }else{ flag = true; } } } }}<>⽂件,监听系统开机事件,设置是否开机⾃启动SetQuietService服务 package e;import anager;import gIntent;import e;import astReceiver;import t;import ;import Preferences;public class LauncherReceiver extends BroadcastReceiver { @Override public void onReceive(Context arg0, Intent arg1) { //LauncherReceiver⽤来监听系统开机事件,如果之前已经设置了启动SetQuietService,即quiet_status为true, //⽽后来因为某种原因关机了,则开机启动SetQuietService SharedPreferences preferences = redPreferences("switch", _MULTI_PROCESS); Boolean quiet_status = lean("switch_quiet", false); Boolean remind_status = lean("switch_remind", false); Intent quiet_intent = new Intent(arg0,); Intent remind_intent = new Intent(arg0,); PendingIntent pi_remind = adcast(arg0, 0, remind_intent, 0); AlarmManager am = (AlarmManager)temService(_SERVICE); if(quiet_status){ ervice(quiet_intent); } if(remind_status){ eating(, tTimeMillis(), 60000, pi_remind); }else{ (pi_remind); } }}<>⽂件,该Activity对应的是⼀个悬浮的界⾯,当到了预设的课前提醒时间时,便启动该Activity package hedule;import dschedule.R;import ty;import ialog;import e;import t;import Interface;import Preferences;import kListener;import ;import or;public class RemindActivity extends Activity{ private Vibrator vibrator; @Override public void onCreate(Bundle savedInstanceState) { te(savedInstanceState); SharedPreferences pre = getSharedPreferences("time", _MULTI_PROCESS); int advance_time = ("time_choice", 30); //获取系统的vibrator服务,并设置⼿机振动2秒 vibrator = (Vibrator)getSystemService(OR_SERVICE); e(2000); // 创建⼀个对话框 final r builder= new r(); n(_launcher); le("温馨提⽰"); sage("童鞋,还有" + advance_time + "分钟就要上课了哦!"); itiveButton( "确定" , new OnClickListener() { @Override public void onClick(DialogInterface dialog , int which) { // 结束该Activity (); } } ) .show(); } @Override public void onBackPressed() { Pressed(); // 结束该Activity (); } }点击“关于作者”和“软件相关”,会分别跳转到<>⽂件和<>⽂件,这两个⽂件及其相应的布局⽂件⽐较简单,不再附上。 ⽹友提醒忘了附上list_,list_和edit_三个布局⽂件,补充⼀点:list_是我第⼀次设定的listview内的每个item内的布局⽂件,后来改为了list_,在项⽬中并没有引⽤list_⽂件,因此这⾥只贴出list_和edit_两个布局⽂件,分别如下: list_⽂件 xmlns:tools="/tools"> edit_⽂件 android:layout_width="match_parent" android:layout_height="wrap_content"> android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" > android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" > android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" > android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" > android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" >
发布者:admin,转转请注明出处:http://www.yc00.com/web/1688675569a161695.html
评论列表(0条)