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
相关产品推荐
相关产品推荐

