• 说明:只是爬虫的一个实现案例,所以没有多做功能,只做了登录跟课表功能,课表有修改周次,单击课程显示课程详细信息等功能。
  • 开发平台:Android Studio

界面

使用TimetableView android课程表控件,需要添加依赖
jsoup依赖:compile 'org.jsoup:jsoup:1.10.2'
界面控件依赖: compile 'com.zhuangfei:TimetableView:2.0.6'

界面效果如下:

实现原理(爬虫实现)

使用jsoup爬取教务系统数据,connect()方法连接教务系统,直接利用cookie连接学生课表页面,解析返回的HTML页面获取该用户的全部课程并封装为java对象,再存入数据库,可以使用java后台服务器传json数据给android客户端,android客户端解析json数据,然后将课表数据展示出来。由于本案例小而单一,因此没有配置服务器,改为将爬取的数据直接存入到android本地数据库SQLite,课表的展示去本地数据库查询即可。
(注:各个学校学院的教务系统不尽相同,具体如何爬取数据详见jsoup官方网站jsoup)

实体类:

public class MySubject implements ScheduleEnable {    public static final String EXTRAS_ID="extras_id";    public static final String EXTRAS_NUMBER="extras_number";//小班号    public static final String EXTRAS_AD_URL="extras_ad_url";//广告Url    private int id;    /*    * 班号    * */    private String number;    /**     * 课程名     */    private String name;    //无用数据    private String time;    /**     * 教室     */    private String room;    /**     * 教师     */    private String teacher;    /**     * 第几周至第几周上     */    private List weekList;    /**     * 开始上课的节次     */    private int start;    /**     * 上课节数     */    private int step;    /**     * 周几上     */    private int day;    private String term;    /**     *  一个随机数,用于对应课程的颜色     */    private int colorRandom = 0;    private String url;    public void setUrl(String url) {        this.url = url;    }    public String getUrl() {        return url;    }    public MySubject() {        // TODO Auto-generated constructor stub    }    public void setTime(String time) {        this.time = time;    }    public String getTime() {        return time;    }    public void setTerm(String term) {        this.term = term;    }    public String getTerm() {        return term;    }    public MySubject(String term,String name, String room, String teacher, List weekList, int start, int step, int day, int colorRandom,String time,String number) {        super();        this.term=term;        this.name = name;        this.room = room;        this.teacher = teacher;        this.weekList=weekList;        this.start = start;        this.step = step;        this.day = day;        this.colorRandom = colorRandom;        this.time = time;        this.number = number;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getRoom() {        return room;    }    public void setRoom(String room) {        this.room = room;    }    public String getTeacher() {        return teacher;    }    public void setTeacher(String teacher) {        this.teacher = teacher;    }    public void setWeekList(List weekList) {        this.weekList = weekList;    }    public List getWeekList() {        return weekList;    }    public int getStart() {        return start;    }    public void setStart(int start) {        this.start = start;    }    public int getStep() {        return step;    }    public void setStep(int step) {        this.step = step;    }    public int getDay() {        return day;    }    public void setDay(int day) {        this.day = day;    }    public int getColorRandom() {        return colorRandom;    }    public void setColorRandom(int colorRandom) {        this.colorRandom = colorRandom;    }    @Override    public Schedule getSchedule() {        Schedule schedule=new Schedule();        schedule.setDay(getDay());        schedule.setName(getName());        schedule.setRoom(getRoom());        schedule.setStart(getStart());        schedule.setStep(getStep());        schedule.setTeacher(getTeacher());        schedule.setWeekList(getWeekList());        schedule.setColorRandom(2);        schedule.putExtras(EXTRAS_ID,getId());        schedule.putExtras(EXTRAS_AD_URL,getUrl());        schedule.putExtras(EXTRAS_NUMBER,getNumber());        return schedule;    }    public void setId(int id) {        this.id = id;    }    public int getId() {        return id;    }    public String getNumber() {        return number;    }    public void setNumber(String number) {        this.number = number;    }}

课表界面,对依赖的课表控件进行了部分修改
数据源改为本地数据库查询,实现了动态获取数据源:mySubjects = getLocalSubjectData();

课表界面:

/** * 课表Activity *  */public class BaseFuncActivity extends AppCompatActivity implements View.OnClickListener{    private static final String TAG = "BaseFuncActivity";    //控件    TimetableView mTimetableView;    WeekView mWeekView;    Button moreButton;    LinearLayout layout;    TextView titleTextView;    List mySubjects;    //记录切换的周次,不一定是当前周    int target = -1;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_base_func);        moreButton = (Button) findViewById(R.id.id_more);        moreButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                showPopmenu();            }        });        //数据源//        mySubjects = SubjectRepertory.loadDefaultSubjects2();        //获取本地数据库数据        mySubjects = getLocalSubjectData();        //mySubjects.addAll(SubjectRepertory.loadDefaultSubjects());        titleTextView = (TextView) findViewById(R.id.id_title);        layout = (LinearLayout) findViewById(R.id.id_layout);        layout.setOnClickListener(this);        initTimetableView();//初始化        setMonthWidth();//设置月份宽度//        showTime();//显示时间        buildItemText();//设置课程文本内容    }   //获取本地数据库数据    private List getLocalSubjectData() {        List data = DaoImpl.GetCourceData();        if(!GetSaveStatus()){//非登录状态            DaoImpl.ClearCource();//清空表格        }        return data;    }    //判断登录状态    private boolean GetSaveStatus() {        SharedPreferences Preferences=getSharedPreferences("userInfo",MODE_PRIVATE);        String username=Preferences.getString("username","");        String password=Preferences.getString("password","");        if(username.equals("")&&password.equals("")){            return false;        }else{            return true;        }    }    /**     * 初始化课程控件     */    private void initTimetableView() {        //获取控件        mWeekView = (WeekView) findViewById(R.id.id_weekview);        mTimetableView = (TimetableView) findViewById(R.id.id_timetableView);        //设置周次选择属性        mWeekView.source(mySubjects)                .curWeek(getLocalWeek())                .callback(new IWeekView.OnWeekItemClickedListener() {                    @Override                    public void onWeekClicked(int week) {                        int cur = mTimetableView.curWeek();                        //更新切换后的日期,从当前周cur->切换的周week                        mTimetableView.onDateBuildListener()                                .onUpdateDate(cur, week);                        mTimetableView.changeWeekOnly(week);                    }                })                .callback(new IWeekView.OnWeekLeftClickedListener() {                    @Override                    public void onWeekLeftClicked() {                        onWeekLeftLayoutClicked();                    }                })                .isShow(false)//设置隐藏,默认显示                .showView();        mTimetableView.source(mySubjects)                .curWeek(getLocalWeek())                .curTerm("")                .maxSlideItem(16)                .monthWidthDp(30)                //透明度                //日期栏0.1f、侧边栏0.1f,周次选择栏0.6f                //透明度范围为0->1,0为全透明,1为不透明//                .alpha(0.1f, 0.1f, 0.6f)                .callback(new ISchedule.OnItemClickListener() {                    @Override                    public void onItemClick(View v, List scheduleList) {                        display(scheduleList);                    }                })                .callback(new ISchedule.OnItemLongClickListener() {                    @Override                    public void onLongClick(View v, int day, int start) {                        Toast.makeText(BaseFuncActivity.this,                                "长按:周" + day  + ",第" + start + "节",                                Toast.LENGTH_SHORT).show();                    }                })                .callback(new ISchedule.OnWeekChangedListener() {                    @Override                    public void onWeekChanged(int curWeek) {                        titleTextView.setText("第" + curWeek + "周");                    }                })                //旗标布局点击监听                .callback(new ISchedule.OnFlaglayoutClickListener() {                    @Override                    public void onFlaglayoutClick(int day, int start) {                        mTimetableView.hideFlaglayout();                        Toast.makeText(BaseFuncActivity.this,                                "点击了旗标:周" + (day + 1) + ",第" + start + "节",                                Toast.LENGTH_SHORT).show();                    }                })                .showView();    }    /*    获取周数    * */    private int getLocalWeek() {        int weekResult = -1;        SharedPreferences preferences=getSharedPreferences("userInfo",MODE_PRIVATE);        int startWeek = preferences.getInt("weekNumber",-1);//,起始周从SharedPreferences获取        //华软教务系统总共17周        if(startWeek<=17){            String startDay=preferences.getString("date","");//起始周的星期一,从SharedPreferences获取,为yyyy-MM-dd格式//            String endDay= CalendarUtil.getMondayOfWeek();//当前周的星期一,为yyyy-MM-dd格式            String endDay= CalendarUtil.getMondayOfWeek2();//当前周的星期一,为yyyy-MM-dd格式            SharedPreferences.Editor editor=getSharedPreferences("userInfo",MODE_PRIVATE).edit();            editor.putString("current", endDay);            editor.commit();            int tempweek=CalendarUtil.getTwoDay(endDay,startDay);//间隔天数            int week=tempweek/7;            if(week==0){                weekResult=startWeek;            }else{                int finalweek=startWeek+week;                if(finalweek>17){                    weekResult=17;                }else{                    weekResult=finalweek;                }            }            return weekResult;        }else{            weekResult=17;            return weekResult;        }    }    /**     * 周次选择布局的左侧被点击时回调
* 对话框修改当前周次 */ protected void onWeekLeftLayoutClicked() { final String items[] = new String[20]; int itemCount = mWeekView.itemCount(); for (int i = 0; i < itemCount; i++) { items[i] = "第" + (i + 1) + "周"; } target = -1; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("设置当前周"); builder.setSingleChoiceItems(items, mTimetableView.curWeek() - 1, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { target = i; } }); builder.setPositiveButton("设置为当前周", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (target != -1) { mWeekView.curWeek(target + 1).updateView(); mTimetableView.changeWeekForce(target + 1); //把修改的周次存入SharedPreferences中 SharedPreferences.Editor editor=getSharedPreferences("userInfo",MODE_PRIVATE).edit(); editor.putInt("weekNumber",target+1);// editor.putString("date", CalendarUtil.getMondayOfWeek()); editor.putString("date", CalendarUtil.getMondayOfWeek2()); editor.commit();// Log.d("info",Integer.toString(target+1)); } } }); builder.setNegativeButton("取消", null); builder.create().show(); } /** * 显示内容 * * @param beans */ protected void display(List beans) { String str = ""; for (Schedule bean : beans) { str += bean.getName() + ","+bean.getWeekList().toString()+","+bean.getTeacher()+",["+bean.getExtras().get(MySubject.EXTRAS_NUMBER)+"]\n"; } Toast.makeText(this, str, Toast.LENGTH_SHORT).show(); } /** * 显示弹出菜单 */ private void showPopmenu() { PopupMenu popup = new PopupMenu(this, moreButton); popup.getMenuInflater().inflate(R.menu.popmenu_base_func, popup.getMenu()); popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { /*case R.id.top1: addSubject(); break; case R.id.top2: deleteSubject(); break;*/ case R.id.top4: hideNonThisWeek(); break; case R.id.top5: showNonThisWeek(); break; /*case R.id.top6: setMaxItem(8); break; case R.id.top7: setMaxItem(10); break; case R.id.top8: setMaxItem(12); break;*/ case R.id.top9: showTime(); break; case R.id.top10: hideTime(); break; case R.id.top11: showWeekView(); break; case R.id.top12: hideWeekView(); break; /*case R.id.top13: setMonthWidth(); break; case R.id.top16: resetMonthWidth(); break;*/ case R.id.top14: hideWeekends(); break; case R.id.top15: showWeekends(); break; case R.id.top17: exitCurrentAccount(); break; default: break; } return true; } }); popup.show(); } /** * 退出当前账号 * 清空本地账号及SharedPreferences */ private void exitCurrentAccount() { //清空数据库 DaoImpl.ClearCource(); //清空SharedPreferences SharedPreferences.Editor editor=getSharedPreferences("userInfo",MODE_PRIVATE).edit(); editor.putInt("weekNumber",-1); editor.putString("date", ""); editor.putString("username",""); editor.putString("password",""); editor.putString("current", ""); editor.commit(); Intent intent=new Intent(BaseFuncActivity.this,MainActivity.class); startActivity(intent); finish(); } /** * 删除课程 * 内部使用集合维护课程数据,操作集合的方法来操作它即可 * 最后更新一下视图(全局更新) */ protected void deleteSubject() { int size = mTimetableView.dataSource().size(); int pos = (int) (Math.random() * size); if (size > 0) { mTimetableView.dataSource().remove(pos); mTimetableView.updateView(); } } /** * 添加课程 * 内部使用集合维护课程数据,操作集合的方法来操作它即可 * 最后更新一下视图(全局更新) */ protected void addSubject() { List dataSource = mTimetableView.dataSource(); int size = dataSource.size(); if (size > 0) { Schedule schedule = dataSource.get(0); dataSource.add(schedule); mTimetableView.updateView(); } } /** * 隐藏非本周课程 * 修改了内容的显示,所以必须更新全部(性能不高) * 建议:在初始化时设置该属性 *

* updateView()被调用后,会重新构建课程,课程会回到当前周 */ protected void hideNonThisWeek() { mTimetableView.isShowNotCurWeek(false).updateView(); } /** * 显示非本周课程 * 修改了内容的显示,所以必须更新全部(性能不高) * 建议:在初始化时设置该属性 */ protected void showNonThisWeek() { mTimetableView.isShowNotCurWeek(true).updateView(); } /** * 设置侧边栏最大节次,只影响侧边栏的绘制,对课程内容无影响 * * @param num */ protected void setMaxItem(int num) { mTimetableView.maxSlideItem(num).updateSlideView(); } /** * 显示时间 * 设置侧边栏构建监听,TimeSlideAdapter是控件实现的可显示时间的侧边栏 */ protected void showTime() { String[] times = new String[]{ "09:00", "10:20", "10:40", "12:00", "12:30", "13:50", "14:00", "15:20", "15:30", "16:50", "17:00", "18:20", "19:00", "20:20", "20:30", "21:50" }; OnSlideBuildAdapter listener = (OnSlideBuildAdapter) mTimetableView.onSlideBuildListener(); listener.setTimes(times) .setTimeTextColor(Color.BLACK); mTimetableView.updateSlideView(); } /** * 隐藏时间 * 将侧边栏监听置Null后,会默认使用默认的构建方法,即不显示时间 * 只修改了侧边栏的属性,所以只更新侧边栏即可(性能高),没有必要更新全部(性能低) */ protected void hideTime() { mTimetableView.callback((ISchedule.OnSlideBuildListener) null); mTimetableView.updateSlideView(); } /** * 显示WeekView */ protected void showWeekView() { mWeekView.isShow(true); } /** * 隐藏WeekView */ protected void hideWeekView() { mWeekView.isShow(false); } /** * 设置月份宽度 */ private void setMonthWidth() { mTimetableView.monthWidthDp(50).updateView(); } /** * 设置月份宽度,默认40dp */ private void resetMonthWidth() { mTimetableView.monthWidthDp(40).updateView(); } /** * 修改显示的文本 */ public void buildItemText() { mTimetableView.callback(new OnItemBuildAdapter() { @Override public String getItemText(Schedule schedule, boolean isThisWeek) { if (isThisWeek) return schedule.getName()+"["+schedule.getExtras().get(MySubject.EXTRAS_NUMBER)+"]"+"\n@"+schedule.getRoom(); return "[非本周]" + schedule.getName()+"["+schedule.getExtras().get(MySubject.EXTRAS_NUMBER)+"]"+"\n@"+schedule.getRoom(); } }) .updateView(); } /** * 隐藏周末 */ private void hideWeekends() { mTimetableView.isShowWeekends(false).updateView(); } /** * 显示周末 */ private void showWeekends() { mTimetableView.isShowWeekends(true).updateView(); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.id_layout: //如果周次选择已经显示了,那么将它隐藏,更新课程、日期 //否则,显示 if (mWeekView.isShowing()) { mWeekView.isShow(false); titleTextView.setTextColor(getResources().getColor(R.color.app_course_textcolor_blue)); int cur = mTimetableView.curWeek(); mTimetableView.onDateBuildListener() .onUpdateDate(cur, cur); mTimetableView.changeWeekOnly(cur); } else { mWeekView.isShow(true); titleTextView.setTextColor(getResources().getColor(R.color.app_red)); } break; } }}

登录:


如果勾选记住登录,则将学号以及密码存入SharedPreferences中,下次打开跳过登录直接显示课表,实现了离线操作,避免了需要再次联网登录爬取数据。

附:源码详见github

更多相关文章

  1. android 在listView中如果需要使用复选框功能,强烈建议使用图片作
  2. Android(安卓)StackView
  3. Android(安卓)说说钟表控件
  4. 【Android(安卓)Developers Training】 78. 序言:执行网络操作
  5. Android(安卓)EditText 点击时不弹出键盘但显示光标
  6. Android(安卓)画虚线显示实线的BUG
  7. Android(安卓)Dialog,Toast封装
  8. Android(安卓)M 新控件 TabLayout 与 NavigationView 实践
  9. Android(安卓)VectorDrawable与SVG 实现炫酷动画

随机推荐

  1. Android(安卓)Listview切换动画,扩展到任
  2. android 页面带值跳转
  3. android bitmap保存为文件及读取
  4. 使用Adb shell command直接送key event給
  5. ubuntu12.04 编译 ics android 4.0.4 日
  6. 【Android UI】自定义圆形Loading动画
  7. Android 判断是否是手机或平板。
  8. android 调用mail程序发送邮件
  9. Android Studio集成Library时报错,终极解
  10. 启动系统Camera拍照(Android)