You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Studio实现摇一摇给已存联系人发送SOS短信

实现摇一摇触发批量短信发送方案

1. 封装数据库操作工具类

把零散的数据库操作封装成可复用工具类,方便在SensorService中调用获取所有联系人号码:

public class ContactDBHelper extends SQLiteOpenHelper {
    private static final String DB_NAME = "NumDB";
    private static final int DB_VERSION = 1;
    private static final String TABLE_NAME = "details";
    private static final String COLUMN_NAME = "name";
    private static final String COLUMN_NUMBER = "number";

    public ContactDBHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // 创建联系人表
        String createTableSql = "CREATE TABLE " + TABLE_NAME + " ("
                + COLUMN_NAME + " VARCHAR, "
                + COLUMN_NUMBER + " VARCHAR)";
        db.execSQL(createTableSql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // 版本升级逻辑(暂不需要)
    }

    // 获取所有保存的联系人号码
    public List<String> getAllContactNumbers() {
        List<String> numbers = new ArrayList<>();
        SQLiteDatabase db = getReadableDatabase();
        Cursor cursor = db.query(TABLE_NAME, new String[]{COLUMN_NUMBER},
                null, null, null, null, null);

        if (cursor.moveToFirst()) {
            do {
                String number = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_NUMBER));
                numbers.add(number);
            } while (cursor.moveToNext());
        }
        cursor.close();
        db.close();
        return numbers;
    }

    // 保存联系人(替代原有storeInDB方法)
    public boolean saveContact(String name, String number) {
        SQLiteDatabase db = getWritableDatabase();
        // 检查现有联系人数量
        Cursor cursor = db.query(TABLE_NAME, null, null, null, null, null, null);
        if (cursor.getCount() >= 3) {
            cursor.close();
            db.close();
            return false;
        }

        ContentValues values = new ContentValues();
        values.put(COLUMN_NAME, name);
        values.put(COLUMN_NUMBER, number);
        long result = db.insert(TABLE_NAME, null, values);
        cursor.close();
        db.close();
        return result != -1;
    }
}

修改原有storeInDB方法,使用封装好的工具类:

public void storeInDB(View v) {
    Toast.makeText(getApplicationContext(), "保存开始", Toast.LENGTH_LONG).show();

    EditText nameEt = findViewById(R.id.textView1);
    EditText numberEt = findViewById(R.id.textView2);
    String name = nameEt.getText().toString().trim();
    String number = numberEt.getText().toString().trim();

    if (name.isEmpty() || number.isEmpty()) {
        Toast.makeText(getApplicationContext(), "请填写完整信息", Toast.LENGTH_SHORT).show();
        return;
    }

    ContactDBHelper dbHelper = new ContactDBHelper(this);
    boolean saved = dbHelper.saveContact(name, number);
    if (saved) {
        Toast.makeText(getApplicationContext(), "保存成功", Toast.LENGTH_SHORT).show();
        // 清空输入框
        nameEt.setText("");
        numberEt.setText("");
    } else {
        Toast.makeText(getApplicationContext(), "已达到最大保存数量(3个)", Toast.LENGTH_SHORT).show();
    }
}

2. 修改SensorService,添加短信发送逻辑

在摇一摇回调onShake中读取数据库号码并发送短信,同时修正原有代码中传感器监听器重复注册的问题:

@Override
public void onCreate() {
    super.onCreate();

    // 启动前台服务
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        startMyOwnForeground();
    else
        startForeground(1, new Notification());

    // 初始化摇一摇检测器
    mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    mShakeDetector = new ShakeDetector();
    mShakeDetector.setOnShakeListener(new ShakeDetector.OnShakeListener() {
        @SuppressLint("MissingPermission")
        @Override
        public void onShake(int count) {
            if (count == 3) {
                vibrate();

                // 读取所有联系人号码
                ContactDBHelper dbHelper = new ContactDBHelper(getApplicationContext());
                List<String> contactNumbers = dbHelper.getAllContactNumbers();

                if (contactNumbers.isEmpty()) {
                    Toast.makeText(getApplicationContext(), "没有保存的联系人", Toast.LENGTH_SHORT).show();
                    return;
                }

                // 自定义短信内容,可结合位置信息(原有代码的FusedLocationClient可补充此处逻辑)
                String smsContent = "我需要帮助!";

                // 逐个发送短信
                SmsManager smsManager = SmsManager.getDefault();
                for (String number : contactNumbers) {
                    try {
                        smsManager.sendTextMessage(number, null, smsContent, null, null);
                    } catch (Exception e) {
                        e.printStackTrace();
                        Toast.makeText(getApplicationContext(), "发送给" + number + "失败", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        }
    });

    // 仅注册一次传感器监听器(修正原有代码的位置错误)
    mSensorManager.registerListener(mShakeDetector, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
}

3. 配置必要权限

在AndroidManifest.xml中添加权限声明:

<!-- 发送短信权限 -->
<uses-permission android:name="android.permission.SEND_SMS" />
<!-- 振动权限 -->
<uses-permission android:name="android.permission.VIBRATE" />
<!-- 获取位置权限(如需在短信中添加位置) -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 前台服务权限(Android 12+) -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

Android 6.0及以上版本需动态申请危险权限,可在启动功能的Activity中添加权限申请逻辑:

private static final int REQUEST_PERMISSIONS = 100;
private String[] requiredPermissions = {
        Manifest.permission.SEND_SMS,
        Manifest.permission.VIBRATE,
        Manifest.permission.ACCESS_FINE_LOCATION
};

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

    // 检查并申请权限
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        List<String> missingPermissions = new ArrayList<>();
        for (String perm : requiredPermissions) {
            if (checkSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
                missingPermissions.add(perm);
            }
        }
        if (!missingPermissions.isEmpty()) {
            requestPermissions(missingPermissions.toArray(new String[0]), REQUEST_PERMISSIONS);
        }
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_PERMISSIONS) {
        boolean allGranted = true;
        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                allGranted = false;
                break;
            }
        }
        if (!allGranted) {
            Toast.makeText(this, "需要授予所有权限才能正常使用功能", Toast.LENGTH_SHORT).show();
        }
    }
}

关键注意事项

  • 传感器监听器仅注册一次,避免重复注册导致性能问题或错误
  • 短信发送需处理号码格式错误、网络异常等失败场景
  • 如需添加位置信息,需确保位置权限已授予,并处理位置获取失败的情况
  • Android 13及以上版本,SEND_SMS权限必须动态申请

内容的提问来源于stack exchange,提问作者Salma Abakil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 19:10:30