当前位置:  编程技术>移动开发
本页文章导读:
    ▪眼花缭乱的UI,蓝牙座落何方        眼花缭乱的UI,蓝牙位于何方我们在前面已经分析了Android启动中涉及蓝牙的各个方面,今天我们着重来看看,在蓝牙打开之前,我们能看到的蓝牙UI有哪些,这些UI又是如何实现的。 1,settings.........
    ▪ 关于Typedef的小结        关于Typedef的总结     不管实在C还是C++代码中,typedef这个词都不少见,当然出现频率较高的还是在C代码中。typedef与#define有些相似,但更多的是不同,特别是在一些复杂的用法上,就完全不.........
    ▪ 《猖獗猜单词CET4》的研发感触       《疯狂猜单词CET4》的研发感触公司以前一直在从事幼儿教育,针对的都是3-10的小孩子,但更多的是和出版社合作的方式。全省的教材光盘都是我们这个团队在做。这次,我们决定出一款自己.........

[1]眼花缭乱的UI,蓝牙座落何方
    来源: 互联网  发布时间: 2014-02-18
眼花缭乱的UI,蓝牙位于何方

我们在前面已经分析了Android启动中涉及蓝牙的各个方面,今天我们着重来看看,在蓝牙打开之前,我们能看到的蓝牙UI有哪些,这些UI又是如何实现的。

1,settings中UI的分析

         首先,最常见的也是我们通常情况下最新看到的,它就是Settings中蓝牙的显示代码,具体的图片如下:

 

图1,默认settings中的界面

这个界面的实现是在这个文件中:/packages/apps/Settings/res/xml/settings_headers.xml。它采用的是preference-headers来实现的,这样的实现好处就在于可以匹配不同的屏幕,比如pad和phone。我们来看一下,你就会发现其实还是蛮简单的:

<preference-headers
        xmlns:android="http://schemas.android.com/apk/res/android">

<!--这个就是那个“无线和网络”五个字了 -->
    <!-- WIRELESS and NETWORKS -->
    <header android:title="@string/header_category_wireless_networks" />
<!--这个是wifi --> <!-- Wifi -->
    <header
        android:id="@+id/wifi_settings"
        android:fragment="com.android.settings.wifi.WifiSettings"
        android:title="@string/wifi_settings_title"
        android:icon="@drawable/ic_settings_wireless" />
<!--这个是bluetooth --> <!-- Bluetooth -->
    <header
        android:id="@+id/bluetooth_settings"
<!—-这里的fragment是比较重要的-->
        android:fragment="com.android.settings.bluetooth.BluetoothSettings"
        android:title="@string/bluetooth_settings_title"
        android:icon="@drawable/ic_settings_bluetooth2" />
……

要显示这个preference-headers,需要重新实现 onBuildHeaders回调方法,毫无疑问,肯定是实现过了,我们来看一下具体的代码:

 @Override
    public void onBuildHeaders(List<Header> headers) {
        if(UNIVERSEUI_SUPPORT){
            loadHeadersFromResource(R.xml.settings_headers_uui, headers);
        }else{
//load的preference-headers xml文件
            loadHeadersFromResource(R.xml.settings_headers, headers);
        }
       
		//这个会根据支持的features来决定是否需要把一些list去除掉
        updateHeaderList(headers);

        mHeaders = headers;
    }

这样来看,这个preference-headers的显示还是比较简单的,细心的同学会发现,上面header只有title和icon啊,我们在界面上还有一个开关,这里怎么没有啊?呵呵,好问题,其实上面的代码并不是真正的UI上的显示代码,真正的UI显示代码在哪里呢,我们来慢慢看。

我们知道settings其实最终调用的是setListAdapter,那么这个地方是如何实现的呢?我们来看源码:

  public void setListAdapter(ListAdapter adapter) {
        if (mHeaders == null) {
            mHeaders = new ArrayList<Header>();
            // When the saved state provides the list of headers, onBuildHeaders is not called
            // Copy the list of Headers from the adapter, preserving their order
            for (int i = 0; i < adapter.getCount(); i++) {
                mHeaders.add((Header) adapter.getItem(i));
            }
        }

        // Ignore the adapter provided by PreferenceActivity and substitute ours instead
//重点要关注这里,看HeaderAdapter是如何构建的
        super.setListAdapter(new HeaderAdapter(this, mHeaders));
    }

来看一下HeaderAdapter的构造

 public HeaderAdapter(Context context, List<Header> objects) {
            super(context, 0, objects);
            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            // Temp Switches provided as placeholder until the adapter replaces these with actual
            // Switches inflated from their layouts. Must be done before adapter is set in super
//从注释来看,这里只是占位而已,后面会被layout中的内容真正地覆盖的,我们后面会详细分析
            mWifiEnabler = new WifiEnabler(context, new Switch(context));
//这里就是要构造我们的BluetoothEnabler了,这个在1.1中进行分析,这里可以理解为蓝牙那边的一些初始化,那边的分析会陷入进去比较多,若是想从整体上先理解,请跳过1.1,直接看后面1.2的内容
            mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
        }

1.1 BluetoothEnabler的分析

BluetoothEnabler主要是用来管理蓝牙的on off的开关的。

public BluetoothEnabler(Context context, Switch switch_) {
        mContext = context;
        mSwitch = switch_;
		//local bluetooth manager就是在bluetooth api上面提供一个简单的接口
		//详见1.1.1分析
        LocalBluetoothManager manager = LocalBluetoothManager.getInstance(context);
        if (manager == null) {
            // Bluetooth is not supported
            mLocalAdapter = null;
            mSwitch.setEnabled(false);
        } else {
            mLocalAdapter = manager.getBluetoothAdapter();
        }
//加入对ACTION_STATE_CHANGED和ACTION_AIRPLANE_MODE_CHANGED的action的处理
        mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
        mIntentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
//btwifi的conexist是否被置位。若是没有,意味着wifi和bt只能有一个,则需要加一些action的处理
        if (SystemProperties.get("ro.btwifi.coexist", "true").equals("false")) {
            mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
            mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
            mIntentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
            mSupportBtWifiCoexist = false;
        }
    }

1.1.1 LocalBluetoothManager的分析

local bluetooth manager就是在bluetooth api上面提供一个简单的接口。也就是说他是封装在bluetooth提供的api之上的。

public static synchronized LocalBluetoothManager getInstance(Context context) {
        if (sInstance == null) {
			//调用LocalBluetoothAdapter,调用api得到对应的bluetooth adapter
            LocalBluetoothAdapter adapter = LocalBluetoothAdapter.getInstance();
            if (adapter == null) {
                return null;
            }
            // This will be around as long as this process is
			//得到整个应该的生命周期,所以运行够长时间
            Context appContext = context.getApplicationContext();
			//新建LocalBluetoothManager
            sInstance = new LocalBluetoothManager(adapter, appContext);
        }

        return sInstance;
    }

    private LocalBluetoothManager(LocalBluetoothAdapter adapter, Context context) {
        mContext = context;
        mLocalAdapter = adapter;
		//新建CachedBluetoothDeviceManager,用来管理远端设备的,就是对端
        mCachedDeviceManager = new CachedBluetoothDeviceManager(context);
		// BluetoothEventManager用来管理从bluetooth API那边传过来的broadcast和callback,并把他们分配到对应的class中去,详见1.1.2
        mEventManager = new BluetoothEventManager(mLocalAdapter,
                mCachedDeviceManager, context);
		//用来管理对bluetooth profile的访问的,详见1.1.3
        mProfileManager = new LocalBluetoothProfileManager(context,
                mLocalAdapter, mCachedDeviceManager, mEventManager);
    }

1.1.2BluetoothEventManager的分析

上文已经讲过了,bluetoothEventManager是用来管理api那边传过来的broadcast和callback,他会根据各个broadcast进行最终的分配,我们来了解一下它究竟关注了哪些broadcast和callback。

 BluetoothEventManager(LocalBluetoothAdapter adapter,
            CachedBluetoothDeviceManager deviceManager, Context context) {
        mLocalAdapter = adapter;
        mDeviceManager = deviceManager;
        mAdapterIntentFilter = new IntentFilter();
        mProfileIntentFilter = new IntentFilter();
        mHandlerMap = new HashMap<String, Handler>();
        mContext = context;

        // Bluetooth on/off broadcasts
		// ACTION_STATE_CHANGED,在蓝牙的on和off的时候会发出
        addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());
		//这两个是扫描的broadcast,分别表示开始扫描和停止扫描
        // Discovery broadcasts
        addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));
        addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));
		//这是扫描到设备和设备消失的broadcast
        addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
        addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());
		//这个是设备名字改变的action
        addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());

        // Pairing broadcasts
		//这个是设备配对状态改变的action,比如正在配对,已经配对之类的
        addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());
		//取消配对的handler
        addHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, new PairingCancelHandler());

        // Fine-grained state broadcasts
		//CLASS和UUID改变的action
        addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());
        addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());

        // Dock event broadcasts
		//dock的event
        addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());
		//注册对这些action处理的receiver
        mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter);
    }

1.1.3 LocalBluetoothProfileManager的分析

         LocalBluetoothProfileManager是用来访问支持的bluetoothprofile的LocalBluetoothProfile的。具体的代码如下:

 LocalBluetoothProfileManager(Context context,
            LocalBluetoothAdapter adapter,
            CachedBluetoothDeviceManager deviceManager,
            BluetoothEventManager eventManager) {
        mContext = context;

        mLocalAdapter = adapter;
        mDeviceManager = deviceManager;
        mEventManager = eventManager;
        // pass this reference to adapter and event manager (circular dependency)
		//和localadapter以及eventmanager关联
        mLocalAdapter.setProfileManager(this);
        mEventManager.setProfileManager(this);

        ParcelUuid[] uuids = adapter.getUuids();

        // uuids may be null if Bluetooth is turned off
        if (uuids != null) {
//根据uuid刷新我们支持的profile,在蓝牙off的状态下(从没有打开过的情况下),他应该是null,这里我就暂时不详细介绍了,会在后面的文章中再详细介绍
            updateLocalProfiles(uuids);
        }

        // Always add HID and PAN profiles
		//HID和PAN总是会加入的,具体的后面的文章用到再详细介绍
        mHidProfile = new HidProfile(context, mLocalAdapter);
        addProfile(mHidProfile, HidProfile.NAME,
                BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);

        mPanProfile = new PanProfile(context);
        addPanProfile(mPanProfile, PanProfile.NAME,
                BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);

        Log.d(TAG, "LocalBluetoothProfileManager construction complete");
}

这里,我们总结一下,BluetoothEnabler构造所涉及的各类和他们的主要作用:

1)BluetoothEnabler—用于管理蓝牙的on/off开关操作。

2)LocalBluetoothManager—在framework的bluetooth api之上进行了重新封装,向该应用本身提供了一些简单的接口。

3)CachedBluetoothDeviceManager—用于管理远端设备的类,比如耳机,鼠标等

4)BluetoothEventManager—用于管理从framework的bluetooth api那边上来的broadcast和callback,并把这些反馈到对应的class中去。

5)LocalBluetoothProfileManager—管理对各个bluetoothprofile的访问和操作

1.2真正的开关实现

基本到bluetooth中兜了一圈,我们还是没有发现任何和那个开关相关的内容。没有关系,我们继续来分析Settings中的内容,我们突然发现它重写了getView,哈哈,大家都知道PreferenceActivity中每个list都是通过getView来得到对应要显示的内容的,所以我们有必要来看看这个内容。

   @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            HeaderViewHolder holder;
			//根据postition得到对应item
            Header header = getItem(position);
			//得到type,wifi和蓝牙是有swtich的,这个见1.2.1,很简单的
			//就是下面switch来判断用的,蓝牙是HEADER_TYPE_SWITCH,就是有个开关啦
            int headerType = getHeaderType(header);
            View view = null;

            if (convertView == null) {
                holder = new HeaderViewHolder();
                switch (headerType) {
                    case HEADER_TYPE_CATEGORY:
……
//bluetooth是witch的type哦
                    case HEADER_TYPE_SWITCH:
						//找到preference_header_switch_item这个layout
                        view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
                                false);
//细心的你一定发现这里的icon和title神马的好像和我们真正要显示的不太一样啊?别急,继续看下面你就明白了
                        holder.icon = (ImageView) view.findViewById(R.id.icon);
                        holder.title = (TextView)
                                view.findViewById(com.android.internal.R.id.title);
                        holder.summary = (TextView)
                                view.findViewById(com.android.internal.R.id.summary);
//这里就是开关了
                        holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
                        break;

                    case HEADER_TYPE_NORMAL:
……
                        break;
                }
			//这里把这个holder加入到view,需要注意的这个holder还是会变的哦
                view.setTag(holder);
            } else {
                view = convertView;
                holder = (HeaderViewHolder) view.getTag();
            }

            // All view fields must be updated every time, because the view may be recycled
            switch (headerType) {
                case HEADER_TYPE_CATEGORY:
                    holder.title.setText(header.getTitle(getContext().getResources()));
                    break;

                case HEADER_TYPE_SWITCH:
                    // Would need a different treatment if the main menu had more switches
                    if (header.id == R.id.wifi_settings) {
                        mWifiEnabler.setSwitch(holder.switch_);
                    } else {
						//这里会把这个开关和bluetoothEnabler中的开关相关联,具体见1.2.2,这样对这个开关的操作才能真正有所反应,所以这个很关键哦
                        mBluetoothEnabler.setSwitch(holder.switch_);
                    }
                    // No break, fall through on purpose to update common fields
				//同样注意的是这里没有break
                    //$FALL-THROUGH$
                case HEADER_TYPE_NORMAL:
				//这里就是把我们每个header对应的icon,title重新设置一下哦。
				//这样每个header都可以使用自己独有的资源了,了解了吧,呵呵
                    holder.icon.setImageResource(header.iconRes);
                    holder.title.setText(header.getTitle(getContext().getResources()));
                    CharSequence summary = header.getSummary(getContext().getResources());
                    if (!TextUtils.isEmpty(summary)) {
                        holder.summary.setVisibility(View.VISIBLE);
                        holder.summary.setText(summary);
                    } else {
                        holder.summary.setVisibility(View.GONE);
                    }
                    break;
            }
		//把这个view返回就可以显示了
            return view;
        }

1.2.1 getHeaderType

这个函数用于得到不同header的类型,我们关注的蓝牙是有一个开关的。这个其实从上面图1也是可以看出来的,只有wifi和蓝牙后面有一个开关的按钮,我们来看具体的代码:

static int getHeaderType(Header header) {
            if (header.fragment == null && header.intent == null) {
                return HEADER_TYPE_CATEGORY;
            } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
				//wifi和蓝牙就是switch的类型
                return HEADER_TYPE_SWITCH;
            } else {
                return HEADER_TYPE_NORMAL;
            }
        }

1.2.2 bluetoothEnabler的setSwitch分析

         这个函数的大概作用就是为了把我们ui上的switch和bluetoothEnabler相关联,这样我们在ui上点击这个开关的时候才能真正地去打开/关闭蓝牙。具体代码如下:

public void setSwitch(Switch switch_) {
//已经关联过了,就不需要再次关联了
        if (mSwitch == switch_) return;
	//把原来开关的监听先清除掉
        mSwitch.setOnCheckedChangeListener(null);
        mSwitch = switch_;
	//这里把开关的操作和自身关联起来,这样你的点击才会真正地起作用
        mSwitch.setOnCheckedChangeListener(this);
	//得到当前蓝牙的状态
	//整个这个地方的state是在开机后所做的操作来实现的,我们在之前的文章中有详细介绍过
        int bluetoothState = BluetoothAdapter.STATE_OFF;
        if (mLocalAdapter != null) bluetoothState = mLocalAdapter.getBluetoothState();
        boolean isOn = bluetoothState == BluetoothAdapter.STATE_ON;
        boolean isOff = bluetoothState == BluetoothAdapter.STATE_OFF;
//若是当前蓝牙是打开的,这里就会把开关移到打开的那个位置了,所以,我们可以看到,若是蓝牙默认是打开的,ui上开关就是打开的,它的实现就是在这里喽
        mSwitch.setChecked(isOn);
        if (WirelessSettings.isRadioAllowed(mContext, Settings.System.RADIO_BLUETOOTH)) {
//允许蓝牙,开关肯定是可见的
            mSwitch.setEnabled(isOn || isOff);
        } else {
//若是不运行蓝牙,这个开关就不可见了
            mSwitch.setEnabled(false);
        }

        if (mSupportBtWifiCoexist == false && isWifiAndWifiApStateDisabled() == false) {
//wifi打开了,这里就不能用蓝牙了,当然这个是在wifi和蓝牙不能共存的设置中。。悲催
            mSwitch.setChecked(false);
            mSwitch.setEnabled(false);
        }
}

至此,在打开Settings的时候,我们看到的ui上蓝牙相关的内容已经全部讲解完毕了。回顾一下,总得来说,就是首先有一个header的列表,然后在onBuildHeaders中会把这个列表加载进来,然后根据每个header不同的类型决定是否加入一些别的元素,比如按钮之类的。然后具体关联到bluetooth中去,根据bluetooth当时处于的状态显示对应的按钮状况,如实是否处于打开之类的。大概的流程就是这样了。


若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·


    
[2] 关于Typedef的小结
    来源: 互联网  发布时间: 2014-02-18
关于Typedef的总结

    不管实在C还是C++代码中,typedef这个词都不少见,当然出现频率较高的还是在C代码中。typedef与#define有些相似,但更多的是不同,特别是在一些复杂的用法上,就完全不同了,看了网上一些C/C++的学习者的博客,其中有一篇关于typedef的总结还是很不错,由于总结的很好,我就不加修改的引用过来了,以下是引用的内容(红色部分是我自己写的内容)。

用途一:

定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:

char* pa, pb; // 这多数不符合我们的意图,它只声明了一个指向字符变量的指针,

// 和一个字符变量;

以下则可行:

typedef char* PCHAR;

PCHAR pa, pb;  

这种用法很有用,特别是char* pa, pb的定义,初学者往往认为是定义了两个字符型指针,其实不是,而用typedef char* PCHAR就不会出现这样的问题,减少了错误的发生。

用途二:
用在旧的C代码中,帮助struct。以前的代码中,声明struct新对象时,必须要带上struct,即形式为: struct 结构名对象名,如:

struct tagPOINT1

 {
    int x;

    int y; 
};

struct tagPOINT1 p1;

而在C++中,则可以直接写:结构名对象名,即:tagPOINT1 p1;

typedef struct tagPOINT
{
    int x;

    int y;
}POINT;

POINT p1; // 这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时

候,或许,在C++中,typedef的这种用途二不是很大,但是理解了它,对掌握以前的旧代

码还是有帮助的,毕竟我们在项目中有可能会遇到较早些年代遗留下来的代码。

用途三:

用typedef来定义与平台无关的类型。

比如定义一个叫 REAL 的浮点类型,在目标平台一上,让它表示最高精度的类型为:

typedef long double REAL;

在不支持 long double 的平台二上,改为:

typedef double REAL;

在连 double 都不支持的平台三上,改为:

typedef float REAL;

也就是说,当跨平台时,只要改下 typedef 本身就行,不用对其他源码做任何修改。

标准库就广泛使用了这个技巧,比如size_t。另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健。
     这个优点在我们写代码的过程中可以减少不少代码量哦!

用途四:

为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部

分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化

版。举例: 

 原声明:void (*b[10]) (void (*)());

变量名为b,先替换右边部分括号里的,pFunParam为别名一:

typedef void (*pFunParam)();

再替换左边的变量b,pFunx为别名二:

typedef void (*pFunx)(pFunParam);

原声明的最简化版:

pFunx b[10];
 
原声明:doube(*)() (*e)[9];

变量名为e,先替换左边部分,pFuny为别名一:

typedef double(*pFuny)();

再替换右边的变量e,pFunParamy为别名二

typedef pFuny (*pFunParamy)[9];

原声明的最简化版:

pFunParamy e;

理解复杂声明可用的“右左法则”:从变量名看起,先往右,再往左,碰到一个圆括号

就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直

到整个声明分析完。举例:

int (*func)(int *p);

首先找到变量名func,外面有一对圆括号,而且左边是一个*号,这说明func是一个指针

;然后跳出这个圆括号,先看右边,又遇到圆括号,这说明(*func)是一个函数,所以

func是一个指向这类函数的指针,即函数指针,这类函数具有int*类型的形参,返回值

类型是int。

int (*func[5])(int *);

func右边是一个[]运算符,说明func是具有5个元素的数组;func的左边有一个*,说明

func的元素是指针(注意这里的*不是修饰func,而是修饰func[5]的,原因是[]运算符

优先级比*高,func先跟[]结合)。跳出这个括号,看右边,又遇到圆括号,说明func数

组的元素是函数类型的指针,它指向的函数具有int*类型的形参,返回值类型为int。

这种用法是比较复杂的,出现的频率也不少,往往在看到这样的用法却不能理解,相信以上的解释能有所帮助。

*****以上为参考部分,以下为本人领悟部分*****

使用示例:

1.比较一:

#include <iostream>

using namespace std;

typedef int (*A) (char, char);

int ss(char a, char b)
{
    cout<<"功能1"<<endl;

    cout<<a<<endl;

    cout<<b<<endl;

    return 0;
}
 
int bb(char a, char b)
{

    cout<<"功能2"<<endl;

    cout<<b<<endl;

    cout<<a<<endl;

    return 0;

}

void main()
{

    A a;

    a = ss;

    a('a','b');

    a = bb;

    a('a', 'b');
}

2.比较二:

typedef int (A) (char, char);

void main()
{

    A *a;

    a = ss;

    a('a','b');

    a = bb;

    a('a','b');
}
 

两个程序的结果都一样:

功能1

a

b

功能2

b

a

 

*****以下是参考部分*****

参考自:http://blog.hc360.com/portal/personShowArticle.do?articleId=57527

typedef 与 #define的区别:

案例一:

通常讲,typedef要比#define要好,特别是在有指针的场合。请看例子:

typedef char *pStr1;

#define pStr2 char *;

pStr1 s1, s2;

pStr2 s3, s4;
在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们

所预期的指针变量,根本原因就在于#define只是简单的字符串替换而typedef则是为一

个类型起新名字。

案例二:

下面的代码中编译器会报一个错误,你知道是哪个语句错了吗?

typedef char * pStr;

char string[4] = "abc";

const char *p1 = string;

const pStr p2 = string;

p1++;

p2++;

  是p2++出错了。这个问题再一次提醒我们:typedef和#define不同,它不是简单的

文本替换。上述代码中const pStr p2并不等于const char * p2。const pStr p2和

const long x本质上没有区别,都是对变量进行只读限制,只不过此处变量p2的数据类

型是我们自己定义的而不是系统固有类型而已。因此,const pStr p2的含义是:限定数

据类型为char *的变量p2为只读,因此p2++错误。虽然作者在这里已经解释得很清楚了,可我在这个地方仍然还是糊涂的,真的希望哪位高手能帮忙指点一下,特别是这一句“只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已”,难道自己定义的类型前面用const修饰后,就不能执行更改运算,而系统定义的类型却可以?



法則:右左法則        从变量开始,从右下角开始,按逆时针旋转,看到符合进行释义。其中()作为括号时,为分界符不用释义,作为函数时释义为“返回××类型的函数”。

实例1
int (*pA[10])(int,int);
分析结果: pA开始首先看到的是[],说明pA是一个数组,逆时针旋转,看到的是×,说明数组内元素是指针,再看到的是括号,继续旋转,看到的是函数,因此说明这个指针指向函数。以此pA的含义是,10个函数指针的数组。 利用typedef定义此实例。typedef int(*MyType)(int,int);MyType pA[10]; 实例2
int *Fun(int,int)[10];
分析结果:Fun,开始首先看到的是函数,说明Fun是一个函数,然后看到的是指针,说明Fun函数的功能返回一个指针,然后看到的是数组,说明返回的指针是一个10个元素数组的指针。即Fun是一个返回指向10个元素数组指针的函数。利用typedef定义 typedef int *MyType[10]; MyType Fun(int,int); 

说明:         其实这些复杂符号在编程过程中不应该频繁出现,这样程序可读性会变得生涩难懂。基本上都是通过 typedef 来定义说明增加其可读性。例如上面的两个实例可以用 typedef 按如下模式定义。程序可读性就大大增强。
//实例1的typedef实现
typedef int(*MyType)(int,int);      //typedef 一个函数指针
MyType pA[10];                      //定义函数指针数组。
//实例2的typedef实现
typedef int *MyType[10];            //定义数组指针
MyType Fun(int,int);                //定义返回数组指针的函数。


    
[3] 《猖獗猜单词CET4》的研发感触
    来源: 互联网  发布时间: 2014-02-18
《疯狂猜单词CET4》的研发感触

公司以前一直在从事幼儿教育,针对的都是3-10的小孩子,但更多的是和出版社合作的方式。全省的教材光盘都是我们这个团队在做。这次,我们决定出一款自己真真正正的产品,我们突破不只做幼儿教育的思维,《疯狂猜单词》这款产品就这么诞生了。

当时在和同事讨论时,有人提出,我们做教育,为什么不做一款《疯狂猜单词》,让大家看图猜单词,然后在乐趣中学习单词,全国每年都会有很多人要考四六级,而词汇量作为一个刚性需求,很多人都在拿着词汇表来背单词,既枯燥,又容易忘。最近一段时间,疯狂猜图,疯狂猜音乐非常火爆,用户迅速的达到了上千万,经过综合评估后,公司开始立项,整个项目启动。

以前做的是外包多一些,策划美术基本上都是人家提供好的,而这次,一切从零开始。

由于我们是成立不久的公司,公司没有真正意义上的策划,所以项目经理和美术更多就扮演了策划的角色,这可能也是很多刚起来的小公司面临的问题。

策划对一个项目来说至关重要,如果前期策划没有写好,那么包括数据库设计,程序设计,就会出现很多问题,最痛苦的就是策划没考虑周全,数据库设计好了,程序写了一大半再改策划。

所以这次我们在策划上下了很多功夫,然后才开始设计数据库,接下来就是程序。一款产品想起来简单,但真正做起来,会有很多小细节,包括跨平台问题,android下面的多分辨率问题,内支付问题(移动支付,支付宝,91,appstore),分享,包括微博,微信,不同ios平台和android平台都要研究。美术在设计的过程中,做了好多版。这一个产品做下来,着实感觉到一个好的产品多么不容易。不知道修改了多少bug,完善了多少细节,我们平时玩人家的游戏,总是各种吐糟,真正做的时候,才发现其中的艰难。现在,我们的《疯狂猜单词》总算问世了,作为公司公司第一款独立研发的产品,有很多感触,有很多心酸,我相信接下来我们的产品会越来越好,这次是一个很宝贵的经验。现在就把相关截图分享出来。还希望大家多多体验,多提意见~





    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3