安卓中的漫游检测

12

我正在尝试检测漫游激活的发生。到目前为止,我已经使用了以下代码片段,但因为我还没有能够测试它,所以我不知道它的正确性。

TelephonyManager telephonyManager = TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE); 

PhoneStateListener cellLocationListener = new PhoneStateListener() {
public void onCellLocationChanged(CellLocation location) {
  if(telephonyManager.isNetworkRoaming()
  {
    Toast.makeText(getApplicationContext(),"in roaming",Toast.LENGTH_LONG).show();
   }
 }
};

telephonyManager.listen(cellLocationListener, PhoneStateListener.LISTEN_CELL_LOCATION);

我写了这段代码,认为漫游激活需要先更换信号单元。请告诉我我的推论是否正确,如果不是,我该如何实现它。


1
我认为您可以在模拟器中轻松测试此功能。如果您在Eclipse中切换到DDMS调试视图,可以选择您的模拟器,然后从数据选择器中选择漫游控件,这应该会触发漫游状态的切换。问题是它可能使用与实际设备不同的方式进行状态转换。它在模拟器中工作吗? - Janusz
我正在使用另一个IDE而不是Eclipse,这个IDE没有这个选项。 - klaus johan
你可以通过模拟器控制台上的telnet执行相同的操作。请参考http://developer.android.com/intl/fr/guide/developing/tools/emulator.html#telephony,您可以使用gsm命令启用漫游。 - Janusz
6个回答

16

如果您想知道是否有语音漫游,即使接收器是由 android.net.conn.CONNECTIVITY_CHANGE触发的,您还可以在TelephonyManager中测试 isNetworkRoaming()

我认为这也将避免 getActiveNetworkInfo()返回null时出现错误。

public class RoamingListener extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        TelephonyManager telephony =
            (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        if (telephony.isNetworkRoaming())
            Toast.makeText(context, "Is on TelephonyM Roaming", Toast.LENGTH_LONG).show();
    }
}

我不确定为什么你认为你的方法只适用于监视“语音漫游”?isNetworkRoaming()的文档并没有做出任何这样的区分。 - Tom
想到了同样的解决方案,我不明白为什么他们在上面的答案中没有这样做。 - Matthew Quiros
4
无法只开启语音漫游而不开启数据漫游。http://stackoverflow.com/questions/2783120/data-roaming-in-android - Matthew Quiros
对于 SingleSIM,你是正确的。但是对于 Dual,这是错误的。 - chksr

15

我认为您想要使用NetworkInfo类中的isRoaming()方法。但首先,您需要注册一个变化广播监听器:

<receiver android:name="YourListener">
  <intent-filter>
    <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />

这会给你一个动作名称:ConnectivityManager.CONNECTIVITY_ACTION。

ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
//[edit: check for null]
if(ni != null) {
  //...Here check if this is connected and available...
  return ni.isRoaming();
}

[编辑:已知问题] 注意:在某些版本中似乎存在一个bug,当漫游时,getActiveNetworkInfo()返回null。请参见此处:http://code.google.com/p/android/issues/detail?id=11866

希望这可以帮到你!

Emmanuel


如果我将模拟器切换到漫游,ni 将返回 null。嗯... 顺便提醒一下,最后一行要小心 NullPointerException。 - Artem Russakovskii
好的,我会在答案中进行更正。此外,某些版本似乎存在一个错误。 - Emmanuel

2
可靠的获取漫游状态变化事件的方法是:
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        PhoneStateListener phoneStateListener = new PhoneStateListener() {
            @Override
            public void onServiceStateChanged(ServiceState serviceState) {
                super.onServiceStateChanged(serviceState);
                if (telephonyManager.isNetworkRoaming()) {
                    // In Roaming
                } else {
                    // Not in Roaming
                }
                // You can also check roaming state using this
                if (serviceState.getRoaming()) {
                    // In Roaming
                } else {
                    // Not in Roaming
                }
            }
        };

每当检测到漫游状态时,PhoneListener 将使用 serviceStateChanged 方法得到通知。
我通过查看 AOSP 源代码确认了这一点。
CDMA

https://android.googlesource.com/platform/frameworks/opt/telephony/+/master/src/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java

CDMA LTE

https://android.googlesource.com/platform/frameworks/opt/telephony/+/master/src/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java

GSM

https://android.googlesource.com/platform/frameworks/opt/telephony/+/master/src/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java

检查方法pollStateDone(),这是设置TelephonyManager漫游状态的地方。


0
在我的情况下,我已经使用TelephonyManager和PhoneStateListener监听网络状态的变化,所以像原问题提问者一样,我想知道是否可以在那里检测漫游事件。
(这将是使用ConnectivityManager / NetworkInfo解决方案的替代方法,在接受的答案中。)
为了检测更改,原问题建议监听单元位置的更改,但我想知道是否会导致更多的事件。
我想象一下,漫游状态的更改只能随着网络状态的更改而发生。
protected PhoneStateListener psl = new PhoneStateListener() {
    public void onDataConnectionStateChanged(int state, int networkType) {
        if (TelephonyManager.DATA_CONNECTED == state)
            isRoaming = teleman.isNetworkRoaming();
                // teleman is an instance of TelephonyManager
    }
}

public static final int pslEvents = PhoneStateListener.LISTEN_DATA_CONNECTION_STATE;

TelephonyManager teleman = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
teleman.listen( psl, pslEvents );

这种方法有两个注意事项,但我认为ConnectivityManager解决方案(在被接受的答案中)也有同样的问题:

  1. 我正在监听DATA网络状态的更改。如果用户没有建立数据连接(例如,他们只是语音漫游),那么它不起作用,但我不认为这是一个问题,因为我们大多数人都希望检测数据漫游(例如,当用户漫游时,我们的应用程序不使用数据)。

  2. 我不确定当用户开始漫游时,数据连接状态是否必须发生变化——这只是我的理论,如果有人知道得更好,我会很感兴趣。

最后,让我补充说,可能监听PhoneStateListener :: onServiceStateChanged()是最好的解决方案:简单且不需要多余的事件(这应该很少触发),但我发现文档很模糊,无法确定PSL事件是否会触发ServiceState对象的任何属性(例如漫游)的更改,还是只会触发ServiceState的服务状态属性。


你会在哪里使用这个???在主 Activity 中。但是如果我的 Activity 在后台,因为它不包括清单,它会工作吗?我有一个在后台运行的服务,由于处理器低内存而再次崩溃。 - sheetal
如果你希望即使在你的活动不在前台时也能运行,那么你应该将它放在你的服务中,但即使在你的服务中,也不能保证它会一直运行(正如你所注意到的)。我想你需要找到一个可以列在你的清单中的意图,当漫游状态改变时触发 - 所以基于PSL的我的解决方案不适合你。 - Tom

0

SubscriptionInfo getDataRoaming() 会返回用户在设置中是否启用了数据漫游,而不是设备当前是否实际正在漫游。 - Vitaliy

-1

这个程序可以完美地工作,没有任何监听器 1 表示漫游,0 表示非漫游

try {
            int roaming=    Settings.Secure.getInt(getContentResolver(), Settings.Secure.DATA_ROAMING);
            Log.e("roaming","roaming"+roaming);

        }
        catch (Exception e)
        {
            Log.e("Exception","Exception"+e.getLocalizedMessage());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接