CSipSimple程序之基本功能(二)

3 添加用户

在Sip_Home中,有个添加用户的菜单项。对应的Class为AccountsEditList.class,而目的Class为AccountEditList-Fragment。添加完用户之后显示情况如下图4


图4:AccountsEditListFragmentacitivty界面

而这个class中,对添加用户这一项,如图5示:

    

图5添加用户界面

这里先说明进入AccountEditListFragment之后,程序是如何进入到图5这两步的。首先,添加按钮,然后程序startActivityForResult(new Intent(getActivity(),WizardChooser.class), CHOOSE_WIZARD),进入WizardChooser,WizardChooser是使用ExpandableListView实现的,对于ExpandableListView其实现很简单,其分成多个Group,每个Group又要一些Child数据。然后通过List<Map<>>和List<List<Map<>>>完成数据封装,接着使用适配器把相应的key和value适配到相应的layout上,从而就有图5(左)的情况。

在ExpandableListView中会根据GroupPosition和ChildPosition定位某个组的某个child。通过onChildClickListener来完成事件监听。这里,我们一般点击Generic wizards组下的Basic Child数据。点击完成之后,执行一切步奏之后,进入到这一步setResult(RESULT_OK, result)。从WizardChooser中携带action结果回到AccountsEditListFragment。在AccountsEditListFragment中,会根据前面的action结果,在onActivityResult函数中做action判断,判断完之后跳到BasePrefsWizard这个class,该BasePrefsWizard是继承自GenericPrefs。另外使用了Intent携带extract数据进入BasePrefsWizard的,所携带的数据为wizardId某一类型(这个类型即对应前面的点击Basic的类型),所以相关的Class为Basic.class.注意这里的Basic继承一个称为BaseImplementation的abstract类,该类又继承了WizardIface接口。而上面所说到的wizardId既可以通过这个Id,经过程序的某一函数来获取接口WizardIface实例化。其实这里之所以这样进行,是考虑到多态问题。我们可从左图5中可看出,这里有好多Group,Group下又有好多Child数据,即相应的wizardId很多,每个Id对应的实例有基本相同的地方,但又要区别,要完成所有的wizard显示,所以实现了WizardIface接口,然后虚拟类BaseImplementation又继承自WizardIface接口,而具体的wizard类又继承自BaseImplementation(可看Basicc.class)。这样,在Id传入之后,就可根据Id进行相应wizard的实例显示。

经过了上面的分析之后,我们知道,右图5主要和Basic这个类相关。当设置好上面的数据之后,点击保存按钮之后进入BasePrefsWizard下的saveAccount函数,在该函数中进行了getContentResolver().insert语句,即关于操作ContentProvider的语句。这里根据Uri查询后进入DBProvider的insert方法,进而执行广播命令getContext().sendBroadcast(publishIntent).

对于在系统执行的广播,我们知道只要先在系统注册了广播命令都可以接受广播信息,然后根据广播信息进行相应的操作。在这里,系统注册了很多广播信息,有动态注册的也有静态注册的。静态注册的可查看AndriodMainfest个xml文件中,如图6,动态注册的查看在service注册的页面,在CSipSimple中service为SipService,在registerBroadcasts()函数中完成广播接收注册,如图7。


<!-- Widget 
        	1.AccountWidgetProvider是AppWidgetProvider的一个子类,表明是一个receiver,并接受android.appwidget.action.APPWIDGET_UPDATE
        	2.meta-data为android.appwidget.provider
        	3.用一个xml文件来描述布局属性。这里xml文件为appwidget_info
        -->
        <receiver
            android:name="com.csipsimple.widgets.AccountWidgetProvider"
            android:icon="@drawable/appwidget_preview"
            android:label="@string/gadget_title" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                <action android:name="com.csipsimple.service.ACCOUNT_CHANGED" />
                <action android:name="com.csipsimple.service.REGISTRATION_CHANGED" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/appwidget_info" />
        </receiver>

图6.静态注册Reciever

/**
	 * 在SipService注册了DynamicReceiver4广播接收器
	 * Register broadcast receivers.
	 */
	private void registerBroadcasts() {
		// Register own broadcast receiver
		if (deviceStateReceiver == null) {
			IntentFilter intentfilter = new IntentFilter();
			/*
			 * 只要是下面这些地址的广播,deviceStateReceiver都能接收得到
			 */
			intentfilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
			intentfilter.addAction(SipManager.ACTION_SIP_ACCOUNT_CHANGED);
			intentfilter.addAction(SipManager.ACTION_SIP_CAN_BE_STOPPED);
			intentfilter.addAction(SipManager.ACTION_SIP_REQUEST_RESTART);
			intentfilter.addAction(DynamicReceiver4.ACTION_VPN_CONNECTIVITY);
			if(Compatibility.isCompatible(5)) {
			    deviceStateReceiver = new DynamicReceiver5(this);
			}else {
			    deviceStateReceiver = new DynamicReceiver4(this);
			}
			/*
			 * 在这里动态注册broadcastReceiever。
			 */
			registerReceiver(deviceStateReceiver, intentfilter);
			deviceStateReceiver.startMonitoring(); //从这里启动检测器
		}
		// Telephony
		if (phoneConnectivityReceiver == null) {
			Log.d(THIS_FILE, "Listen for phone state ");
			phoneConnectivityReceiver = new ServicePhoneStateReceiver();
			
			telephonyManager.listen(phoneConnectivityReceiver, /*PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
					| */PhoneStateListener.LISTEN_CALL_STATE );
		}
		// Content observer
		if(statusObserver == null) {
			/*
			 * 注册内容观察者,所观察的URI为content://com.sipsimple.db/account_status
			 */
        	statusObserver = new AccountStatusContentObserver(serviceHandler);
    		getContentResolver().registerContentObserver(SipProfile.ACCOUNT_STATUS_URI, true, statusObserver);
		}
		
	}

图7,动态注册Reciever

当上面分析的发出广播信息后,主要有两个reciever会做出相应的操作,分别DynamicReceiver4和AccountWidgetProvider。

在DynamicReceiver4中重写了onReceive,即也是接收信息的函数。然后进入判断语句,上面发送的广播所携带的信息为ACTION_SIP_ACCOUNT_CHANGED这样的action,根据这个action,执行了SipService.setAccountRegistration()这个函数,从而跳转到service中执行。这里也就是用户开始注册的位置。

在AccountWidgetProvider这个类中,当接受到ACCOUNT_CHANGED这样的action时,就会进行相应的操作。这里,AccountWidgetProvider是继承了AppWidgetProvider的子类。讲到AppWidgetProvider就必须涉及AppWidget,AppWidgetService以及AppWidgetManager。

AppWidget是个窗口小部件,实现了桌面(Luanch)上显示控件的机制,并能响应用户的点击请求操作,但提供显示的UI元素和对点击事件的相应由Remote端的AppWidgetProvider实现,具体显示是Local的AppWidgetHost通过AppWidgetHostView实现。显示的UI界面如图8所示:


图8 AppWidgetHostView显示

         至于AppWidget系统框架可以查看相关的资料。这里用通俗的语言说下整体的步骤。首先一般情况下本地端有个触发按钮或者触发事件,如一个Button按钮,该按钮在XML文件夹下的某个xml文件中定义。然后如图6所示的,在AndriodManifest文件静态注册。因为是远程更新本地Local的UI界面的,所以可想而知是在远端通过一些操作来进行更新的,而这个远程更新就在继承了AppWidgetProvider的子类中实现的,其一般情况下重写了onUpdate()和onReciever()方法。一般情况下,在首次把view显示在界面的时候,会调用onUpdate(),在本地触发事件的时候,会调用onReciever()方法,该方法通过action判断进行相应界面的RemoteView操作,实现更新。某个事情触发之后,更新后的界面如下图9:


图9 远程更新UI

         另外对于上图的更新,在CSipSimple中也使用了ContentObserver进行更新。ContentObserver是个内容观察者。看过HeadFirst模式的话就知道,其实ContentObserver正是基于观察者模式实现的。所谓观察者,目的就是观察(捕捉)特定的Uri引起的数据库变化,当其所观察的Uri发生改变了,便进行触发。正是因为ContentObserver的实现是基于观察者模式的,所以其使用显得尤其简单,我们只需创建一个特定的ContentObserver派生类(如图10),重载父类构造函数以及onChang()方法处理回调后的功能实现(即观察者模式中某一事件发生变化之后进行notify),然后要进行相应的注册,即注册内容观察者和取消注册的步骤即基本完成操作。如图11:

        

class AccountStatusContentObserver extends ContentObserver {
		
		public AccountStatusContentObserver(Handler h) {
			super(h);
		}

		/*
		 * 当观察到的Uri发生变化时,回调该方法去处理
		 * 使用ContentObserver的情况主要有一下两者情况:
		 * 1、需要频繁检测的数据库或者某个数据是否发生改变,如果使用线程去操作,很不经济而且很耗时 ;
		 * 2、在用户不知晓的情况下对数据库做一些事件,比如:悄悄发送信息、拒绝接受短信黑名单等;
		 * @see android.database.ContentObserver#onChange(boolean)
		 */
		public void onChange(boolean selfChange) {
			System.out.println("to check if the ContentObserver recieve the change signal");
			Log.d(THIS_FILE, "Accounts status.onChange( " + selfChange + ")");
			((BaseAdapter) getListAdapter()).notifyDataSetChanged(); //观察者模式
		}
	}

图10 ContentObserver派生类

// Content observer
		if(statusObserver == null) {
			/*
			 * 注册内容观察者,所观察的URI为content://com.sipsimple.db/account_status
			 */
        	statusObserver = new AccountStatusContentObserver(serviceHandler);
    		getContentResolver().registerContentObserver(SipProfile.ACCOUNT_STATUS_URI, true, statusObserver);
		}

图11ContentObserver注册

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
### 回答1: SIP电话是一种基于SIP(会话初始化协议)技术的电话系统,它可以通过Internet连接来进行语音通话和视频通话。SIP电话通常以软件形式运行在Android设备上,使用户可以使用移动网络或Wi-Fi进行通信。 在Android平台上,有许多SIP电话应用程序可用。这些应用程序通常允许用户注册SIP账户并与其他用户进行语音或视频通话。用户可以通过输入对方的SIP地址或用户名进行通信,也可以通过通讯录中的联系人选择进行通话。 使用SIP电话应用程序,在Android设备上可以实现免费或便宜的国际长途通话。用户只需在拨打电话前连接到互联网,并确保对方也拥有SIP电话应用程序或相关服务即可。 SIP电话应用程序还提供了一些其他功能,如即时消息、文件传输和会议呼叫等。用户可以通过消息功能与其他用户进行实时文本交流,也可以通过文件传输功能共享文件。此外,用户还可以使用会议呼叫功能进行多方通话。 对于企业用户来说,SIP电话应用程序也可以作为企业通信系统的一部分。借助SIP电话应用程序,员工可以在不同地点使用他们的Android设备进行公司内部通话,从而提高沟通效率和灵活性。 总的来说,SIP电话是一种便捷的通信方式,可以在Android设备上随时随地进行语音通话和视频通话。它为用户提供了更多的选择,不仅可以节省通话费用,还可以方便地进行国际通话和实时文本交流。 ### 回答2: SIP电话是指使用会话初始协议(Session Initiation Protocol,简称SIP)进行语音通话的一种电话系统。SIP电话可以在基于IP网络的各种设备上使用,包括Android手机。 Android平台提供了SIP API,使得开发者可以在Android设备上实现SIP电话功能。用户可以通过在Android设备上下载并安装支持SIP协议的手机软件,如Zoiper、Linphone、CSipSimple等来实现SIP电话功能。 使用SIP电话,用户可以利用互联网进行免费或低成本的语音通话。用户只需在SIP电话软件中输入对方的SIP地址,即可与对方进行语音通话。用户还可以利用SIP电话拨打普通电话号码,只需要连接到一个SIP服务提供商的服务器,通过服务器将SIP电话转换成普通电话信号,实现与普通电话用户之间的通话。 SIP电话在Android设备上的应用范围很广。除了一般用户可以通过SIP电话实现语音通话外,企业也可以利用SIP电话实现统一通信系统,提高内部沟通效率。此外,SIP电话也可以与其他通信应用集成,如短信、邮件等,实现更多功能。 需要注意的是,使用SIP电话需要有可靠的网络连接,以及稳定的带宽和网络延迟。由于SIP电话基于IP网络,它对网络质量和稳定性要求较高。同时,使用SIP电话还需要与SIP服务提供商建立账号并进行注册。 总体来说,SIP电话在Android设备上提供了一种便捷的语音通话方式,可以满足个人和企业通讯需求,带来更加灵活和经济高效的通信体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值