短信 ContentObserver onChange() 触发多次
Posted
技术标签:
【中文标题】短信 ContentObserver onChange() 触发多次【英文标题】:Sms ContentObserver onChange() fires multiple times 【发布时间】:2012-02-25 11:18:57 【问题描述】:我知道这个问题已经被问过很多次了,但没有人能够根据我所看到的情况得出一个有效的答案。
我正在开发一个应用程序来拦截短信,并根据发送 # 弹出自定义警报。我让它与广播接收器一起工作得很好,但是如果用户安装了 goSms,则永远不会调用 onReceive()
方法,因为 goSms 在它到达我的应用程序之前会中止它。
为了解决这个问题,我在 content://sms/
上尝试了一个内容观察者
它工作得很好,但是 onChange()
被调用了两次,参数完全相同。我尝试检查时间戳,但它们是相同的,类型和我设置的所有其他参数也是如此。
据我所见,这是一个常见问题,但我在任何地方都没有看到答案。
@Override
public void onChange(boolean selfChange)
super.onChange(selfChange);
querySMS();
protected void querySMS()
Cursor cur = getContentResolver().query(u, null, null, null, null);
cur.moveToNext(); // this will make it point to the first record, which is the last SMS sent
String type = cur.getString(cur.getColumnIndex("type"));
String body = cur.getString(cur.getColumnIndex("body")); //content of sms
String add = cur.getString(cur.getColumnIndex("address")); //phone num
if (type.equals("1"))
if (add.equals(Test.SENDER))
String[] bodys = body.split(" ", 7);
if (bodys[0].equals("test"))
test = true;
cat = bodys[1];
level = bodys[2];
urgency = bodys[3];
certainty = bodys[4];
carrier = bodys[5];
message = bodys[6];
final Intent intent = new Intent(context, AlertActivity.class);
Bundle b = new Bundle();
b.putString("title", cat);
b.putString("certainty", certainty);
b.putString("urgency", urgency);
b.putString("level", level);
b.putString("message", message);
b.putBoolean("test", test);
intent.putExtras(b);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
carrierName = manager.getNetworkOperatorName();
if (carrierName.replaceAll(" ", "").equals(carrier))
context.startActivity(intent);
else
//testing
Toast.makeText(context, carrierName.replaceAll(" ", ""), Toast.LENGTH_LONG).show();
由于onChange()
被触发了两次,我也收到了两次警报。我一辈子都想不出办法来解决这个问题。
【问题讨论】:
其他(不完整)答案的链接会有所帮助 【参考方案1】:如果两者相同: 存储接收到的每条消息 将其与以前接收的消息进行比较 如果没有找到,处理 如果找到,丢弃该消息
存储的消息的寿命应该是无限小的,5 条消息的小循环缓冲区应该没问题。
【讨论】:
该消息只被接收一次。它不会进来两次。 tbh,我什至不知道第二个onChange
是从什么触发的。
啊。将您的想法与***.com/questions/7012703/… 结合起来,我得到了它的工作。我想我在第一次阅读时误解了你的意思。我创建了一个静态 arrayList
并用它来检查。 if (!ids.contains(id)) ids.add(id);context.startActivity(intent);
【参考方案2】:
这是我的代码,对我来说很好用
public class SmsObserver extends ContentObserver
private Context context;
private static int initialPos;
private static final String TAG = "SMSContentObserver";
private static final Uri uriSMS = Uri.parse("content://sms/sent");
public SmsObserver(Handler handler, Context ctx)
super(handler);
context = ctx;
initialPos = getLastMsgId();
@Override
public void onChange(boolean selfChange)
super.onChange(selfChange);
queryLastSentSMS();
public int getLastMsgId()
Cursor cur = context.getContentResolver().query(uriSMS, null, null, null, null);
cur.moveToFirst();
int lastMsgId = cur.getInt(cur.getColumnIndex("_id"));
Log.i(TAG, "Last sent message id: " + String.valueOf(lastMsgId));
return lastMsgId;
protected void queryLastSentSMS()
new Thread(new Runnable()
@Override
public void run()
Cursor cur =
context.getContentResolver().query(uriSMS, null, null, null, null);
if (cur.moveToNext())
try
if (initialPos != getLastMsgId())
// Here you get the last sms. Do what you want.
String receiver = cur.getString(cur.getColumnIndex("address"));
System.out.println(" Receiver Ph no :"+receiver);
// Then, set initialPos to the current position.
initialPos = getLastMsgId();
catch (Exception e)
// Treat exception here
cur.close();
).start();
//End of class SmsObserver
【讨论】:
【参考方案3】:您可以保存最后一条消息的 id 并将其与 cur
返回的消息的 id 进行比较,该消息在 onChange
中。然后,如果 id 相同,您可以简单地忽略该消息。
// might contain mistakes, but you'll get the idea:
protected void querySMS()
Cursor cur = getContentResolver().query(u, null, null, null, null);
cur.moveToNext();
if (lastId == cur.getLong(cur.getColumnIndex("_id")))
return;
lastId = cur.getLong(cur.getColumnIndex("_id"));
... //continue as it was
但是 - 如果用户选择此选项(接收设置 - 禁用其他消息通知),GO SMS 只会阻止其他应用接收广播 - 因此,如果用户不希望其他应用打扰他 -我认为最好不要这样做。
【讨论】:
我正在开发的应用程序从来都不是应该被忽略的。它会预装在设备上,并且完全优先于当前在手机上运行的任何其他内容。我做了与此类似的事情,如果您查看下面答案的 cmets,您可以看到。 您确实明白,您发布的 sn-p 应该还有很长的路要走才能用于预安装的应用程序,不是吗? 哦,当然。我才刚刚开始这个项目。它还有很长的路要走【参考方案4】:我只是使用 SharedPreference 来备注最后的 SMS 信息(例如:id\type
...)。如果一样,我会return
。
【讨论】:
以上是关于短信 ContentObserver onChange() 触发多次的主要内容,如果未能解决你的问题,请参考以下文章
安卓ContentObserver模式获取短信用正则自己主动填充验证码
短信 ContentObserver onChange() 触发多次