Android 小应用:“自动拨打电话app”制作心得

时间:2022-11-10 10:10:00

前言

最近做了一个Android小应用,可以接受短信或服务器发来的指令,根据指令自动拨打保存在app里面对应的电话号码,觉得挺有意思的。而且通过这个app,让我熟悉了很多Android的知识,在这里分享并记录一下。

功能

  • 保存电话号码及对应的指令。
  • 指令可以从短信获取,也可以从服务器获取。
  • 根据指令,获取相应的电话号码,并轮流拨打。
  • 可以设置号码保护时间,在这个时间以内,即使获取到相应的指令,也不会拨打此号码。
  • 可以设置从服务器获取指令的间隔。
  • 可以打开或关闭从服务器获取指令。
  • 可以打开或关闭从短信息获取指令。

知识点

实现思路

1.添加\修改\删除一条号码及对应的指令

  • 将number和sms封装成bean;
  • 创建ItemsDBHelper类,继承SQLiteOpenHelper;
  • 使用ItemsDBHelper创建表items,列名分别为:number,sms;
  • ItemsDBHelper判断数据库中有没有这条数据:
    public boolean hasItem(ItemBean itemBean) {
        String selection = COLUMN_SMS + "=? AND " + COLUMN_NUMBER + "=?";
        String[] selectionArgs = new String[] {itemBean.getSms(), itemBean.getNumber()};
        Cursor cursor = this.db.query(TABLE_NAME, null, selection, selectionArgs, null, null,null);
        if(cursor == null || cursor.getCount() == 0) {
            return false;
        } else {
            return true;
        }
    }
  • ItemsDBHelper封装添加\修改\删除方法:
    public void saveItem(ItemBean itemBean) {
        if(hasItem(itemBean)) {
            return;
        }
        ContentValues values = new ContentValues();
        values.put(COLUMN_SMS, itemBean.getSms());
        values.put(COLUMN_NUMBER, itemBean.getNumber());
        db.insert(TABLE_NAME, "", values);
    }

    public void deleteItem(ItemBean itemBean) {
        String selection = COLUMN_SMS + "=? AND " + COLUMN_NUMBER + "=?";
        String[] selectionArgs = {itemBean.getSms(), itemBean.getNumber()};
        this.db.delete(TABLE_NAME, selection, selectionArgs);
    }

    public void updateItem(ItemBean oldItemBean, ItemBean newItemBean) {
        deleteItem(oldItemBean);
        saveItem(newItemBean);
    }

2.在主界面上显示所有号码及对应的指令。

  • 在ItemsDBHelper创建查询方法:
    public ArrayList<ItemBean> loadItems() {
        ArrayList<ItemBean> itemBeans = new ArrayList<ItemBean>();
        Cursor cursor = this.db.query(TABLE_NAME, null, null, null, null, null,null);
        if(cursor != null) {
            while (cursor.moveToNext()) {
                ItemBean itemBean = new ItemBean();
                itemBean.setSms(cursor.getString(cursor.getColumnIndex(COLUMN_SMS)));
                itemBean.setNumber(cursor.getString(cursor.getColumnIndex(COLUMN_NUMBER)));
                itemBeans.add(itemBean);
            }
        }
        Log.i(Config.TAG, "ItemsDBHelper->loadItems: " + itemBeans);
        return itemBeans;
    }
  • 在Adapter中,将数据取出,并显示。
mItems = mItemsDBHelper.loadItems();

getView() 中将值赋给每一行:

holder.tvSms.setText(mItems.get(position).getSms());
holder.tvNumber.setText(mItems.get(position).getNumber());

3.拦截短信息,获取到指令

4.不间断请求服务器,获取到指令

  • 开启一个前台Service,每过一段时间请求一次服务器:
    private void executeNetListen() {
        new Handler().postDelayed(new Runnable() {
            public void run() {
                if(getIsReceiveServerMsg()) {
                    requestServer();
                }
                executeNetListen();
            }
        }, getIntervalTime());
    }

5.根据指令获取到相应的号码

  • 在ItemsDBHelper中,创建方法getNumbers(String sms),返回一个放号码的ArrayList:
    public ArrayList<String> getNumbers(String sms) {
        ArrayList<String> sNumbers = new ArrayList<String>();

        String selection = COLUMN_SMS + "=?";
        String[] selectionArgs = new String[] {sms};
        Cursor cursor = this.db.query(TABLE_NAME, null, selection, selectionArgs, null, null,null);
        if(cursor != null) {
            while (cursor.moveToNext()) {
                String sNumber = cursor.getString(cursor.getColumnIndex(COLUMN_NUMBER));
                sNumbers.add(sNumber);
            }
        }
        return sNumbers;
    }

6.创建表current_task

  • 表current_task用来存放当前需要打的电话,相当于一个队列的概念;
  • 创建CurrentTaskDBHelper类,继承SQLiteOpenHelper;
  • 使用CurrentTaskDBHelper创建表current_task,列名分别为:phone_number,add_time;

7.将号码添加到表current_task

  • 如果当前要插入的号码,在表中已经存在,那么不再插入;

8.从表current_task提取一条号码出来

  • 根据add_time,提取最先添加的一条号码;
  • 提取出来以后,说明这个号码要被执行,可以从表中删掉;

9.创建表done_task

  • 表done_task用来存放拨打过的电话,相当于一个历史记录的概念;
  • 创建CurrentTaskDBHelper类,继承SQLiteOpenHelper;
  • 使用CurrentTaskDBHelper创建表current_task,列名分别为:phone_number,add_time;

10.将号码同表done_task的号码做比较

  • 将current_task提取的号码拿到done_task中查询;
  • 离上次拨打过去的时间s_time,s_time =(当前时间 - add_time);
  • 如果号码在dome_task中没有找到,或者s_time>号码保护时间,执行第11步,并跟新add_time为当前时间;
  • 如果s_time<号码保护时间,执行第8步;

11.执行打电话的动作

  • 系统将自动拨打电话;

12.监听到挂断状态

  • 当通话界面收起的时候(通常是对方挂断电话,语音提示结束以后),挂断状态被监听到;
  • 继续执行第8步;

13.拨打保护

  • 创建标志位FLAG_IS_ON_CALL_TASK,保存在SharedPreferences 中,用来表示是否正在执行拨打任务;
  • 当拨打任务开始时,FLAG_IS_ON_CALL_TASK 为true;任务结束后FLAG_IS_ON_CALL_TASK 为false;
  • 如果任务执行过程中,接受到新的指令,则只把号码添加到current_task中(第7步),而不调用电话拨打(第八步);
  • 这样可以防止通话被干扰;

14.拨打任务结束

  • 表current_task中的号码,会在任务执行过程中越来越少;
  • 表current_task一条号码也没有时,从方法中return,结束当前任务;

总结

  • 短信的拦截;
  • 后台不断监听服务器信息;
  • SQLite的查询、添加、修改、删除;
  • current_task是一个队列,按顺序拨打;
  • done_task会记录号码上次拨打的时间;
  • 拨打任务的执行中,添加标志位,防止通话被干扰;
  • current_task中没有号码,结束通话任务;

附上代码地址
https://github.com/deeepthinking/AutoPhoneCall