当前位置:  编程技术>移动开发
本页文章导读:
    ▪win8开发(10)——怎么共享文本内容        win8开发(10)——如何共享文本内容 首先请各位看下面的图。     相信微博的这个功能,大家不陌生吧。那么它是怎么实现的呢? 首先,我们要了解一个东西,应用程序协定,名称不好.........
    ▪ printf 函数中\r的含意        printf 函数中\r的含义\r   转义序列。表示carriage   return(回车键) \n是另起一行,\r的话回车回到本行的开头,如果继续输入的话会把先前的覆盖掉    Turbo   C2.0中有些常用的字符用以下特殊.........
    ▪ Box2d源码学习<2>内存管理之SOA的实现       Box2d源码学习<二>内存管理之SOA的实现本系列博客是由扭曲45原创,欢迎转载,转载时注明出处,http://blog.csdn.net/cg0206/article/details/8258166 SOA,全称small object allocator,中文意思是小对象分配器.........

[1]win8开发(10)——怎么共享文本内容
    来源: 互联网  发布时间: 2014-02-18
win8开发(10)——如何共享文本内容


首先请各位看下面的图。

 
 

相信微博的这个功能,大家不陌生吧。那么它是怎么实现的呢?

首先,我们要了解一个东西,应用程序协定,名称不好理解,也很难翻译,这样吧,我们看看它是

在哪里设置的,也许你会有点感悟。

用VS2012新建windows store应用后,你会看到项目中有个清单文件,用于配置与应用程序包相关

的信息。



[attach]223  [/attach]


双击打开它。
切换到“声明”选项卡

[attach]  220[/attach]

这就是应用程序协定,你可以理解为为你的应用程序声明多种启动方式,并作为特定的目标使用

,如上面图片中,新浪微博为什么可以在其它应用程序中启动,并且可以共享信息,这样,我们可以理解为应用程序之间数据的传递,而我们最常见的一种方式就是复制-粘贴,这是利用剪贴板作为载体实现应用程序之间 的数居共享。


如果还是觉得很抽象,那最好的办法就是用实例来说明,我们来模拟刚才新浪微博的功能,一个

我们需要建两个项目,一个是共享源,即发送共享数据的一方;另一个是共享目标,即接受共享数据的一方。


首先我们来实现共享源,即发送方。
1、启动VS,新建项目。
2、在MainPage.xaml中输入以下XAML代码。
    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel>
            <TextBox Name="txtContent" Height="285"/>
            <Button Margin="12,15,0,0" Content="共享" Click="onShare"/>
        </StackPanel>
    </Grid>

3、然后,我们要处理按钮的Click事件。
        private void onShare(object sender, RoutedEventArgs e)
        {
            DataTransferManager.ShowShareUI();
        }

ShowShareUI方法是静态的,可以直接调用,DataTransferManager位于命名空间

Windows.ApplicationModel.DataTransfer,发送共享数据正是通过它来完成。

那,什么时候设置我们要发送的数据呢?例如,现在我要共享目标共享一条文本信息,

设置数据是在DataTransferManager类的DataRequested事件中处理的。


通过GetForCurrentView方法获得DataTransferManager的实例,故在MainPage类

的构造函数加入以下代码。

        public MainPage()
        {
            this.InitializeComponent();
            DataTransferManager.GetForCurrentView().DataRequested += MainPage_DataRequested;
        }
4、处理DataRequested事件。
        void MainPage_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
        {
            var defl = args.Request.GetDeferral();
            // 设置数据包
            DataPackage dp = new DataPackage();
            dp.Properties.Title = "共享文本";
            dp.Properties.Description = "分享一些字符串。";
            dp.SetText(txtContent.Text);
            args.Request.Data = dp;
            // 报告操作完成
            defl.Complete();
        }

OK,现在我要完成共享目标。

在资源管理器”节点上右击,在弹出菜单中依次选择“添加”->“新建项目”

,再建一个App,它就是数据的接收方。

1、打开清单文件,切换到“声明”选项卡,在下拉列表中选择“共享目标”,并单击

“添加”按钮。


 

在右面的面板中,找到“数据格式”节,单击“新增”按钮。

 

因为只需传递文本信息,因此,输入 Text 即可。

 

保存,关闭清单文件。

2、新建一个空白页,命名为SharedPage.xaml,XAML代码如下。
    <Grid Background="#FF0B4C81">
        <TextBlock Margin="10,15,0,0"
                   FontSize="28"
                   VerticalAlignment="Top"
                   HorizontalAlignment="Left"
                   x:Name="tbShareText"/>
    </Grid>


3、打开SharedPage.xaml.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.ApplicationModel.Core;
// “空白页”项模板在 http://go.microsoft.com/fwlink/?LinkId=234238 上有介绍
namespace ShareTargetSample
{
    /// <summary>
    /// 可用于自身或导航至 Frame 内部的空白页。
    /// </summary>
    public sealed partial class SharedPage : Page
    {
        public SharedPage()
        {
            this.InitializeComponent();
        }
        /// <summary>
        /// 在此页将要在 Frame 中显示时进行调用。
        /// </summary>
        /// <param name="e">描述如何访问此页的事件数据。Parameter
        /// 属性通常用于配置页。</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            if (CoreApplication.Properties.ContainsKey("value"))
            {
                this.tbShareText.Text = CoreApplication.Properties["value"].ToString();
            }
        }
    }
}

我们并不是在该页面上取共享数据,该页只是负责显示。我们取得的共享数据保存在

CoreApplication.Properties集合中,该页面便从该集合中取得数据并显示。


4、打开App.xaml.cs

我们在App类中重写OnShareTargetActivated方法,如果应用程序由用户启动,

则调用OnLaunched方法,但如果是共享源调用导致应用程序启动,则调用

OnShareTargetActivated方法,这就是应用程序协定的作用。


        protected async override void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
        {
            var opr = args.ShareOperation;
            // 开始取数据
            opr.ReportStarted();
            DataPackageView pv = opr.Data;
            if (pv.Contains(StandardDataFormats.Text))
            {
                CoreApplication.Properties["value"] = await pv.GetTextAsync();
            }
            opr.ReportDataRetrieved();
            Frame root = Window.Current.Content as Frame;
            if (root == null)
            {
                root = new Frame();
                root.Navigate(typeof(SharedPage));
            }
            Window.Current.Content = root;
            Window.Current.Activate();
            //opr.ReportCompleted();
            //opr.ReportError("无法共享。");
        }

好的,完成,但是,我们必须以正常启动运行一次共享目标程序,不然,它不会安装到

系统的应用列表中。在资源管理器中,选中共享目标项目,右击,选择“调试”-“启动新实例”。

待程序运行后,再把它结束,这时候,打开电脑设置(鼠标移到右上角或右

下角,从出现的侧边栏中点击“设置”,点击下方的“更多电脑设置”),选择“共享”,

这时我们看到,共享目标的共享功能已经打开。

这时我们看到,共享目标的共享功能已经打开。
 

现在,运行共享源项目,在页面上随便输入一些内容。点击共享按钮。

 

然后点击我们的应用程序,

 


这样,我们的共享目标示例程就接收到共享数据了。


还没完,大家可能注意,上面App.xaml.cs中,有两行代码我故意注释掉了,

现在我们看看分别取消这两行代码,会发生什么。

1、取消第一行
            opr.ReportCompleted();
            //opr.ReportError("无法共享。");

然后,按上面的方法运行,我们发现,共享目标一收到数据就退出了,对的,在共享目标中,

我们对接收的共享数据进行处理,处理完后,一旦调用ShareOperation的ReportCompleted

方法报告共享操作完成,那么共享目标程序就会自动退出。 

同样道理,注释掉第一行,取消第二行的注释,我们让它共享失败。
//opr.ReportCompleted();
            opr.ReportError("无法共享。");
记住,现在要以正常启动方式运行一次共享目标程序,因为这样做,新的修改才会生效。
 

报告错误后,就会收到上面的提示。

    
[2] printf 函数中\r的含意
    来源: 互联网  发布时间: 2014-02-18
printf 函数中\r的含义
\r   转义序列。表示carriage   return(回车键)
\n是另起一行,\r的话回车回到本行的开头,如果继续输入的话会把先前的覆盖掉 

  Turbo   C2.0中有些常用的字符用以下特殊规定来表示:   
    
                      规定符                         等价于                       含义   
                      '\f'                               '\X0C'                     换页   
                      '\r'                               '\X0D'                     回车   
                      '\t'                               '\X09'                     制表键   
                      '\n'                               '\X0A'                     换行   
                      '\\'                               '\X5C'                     \符   
                      '\''                               '\X27'                     '符   
                      '\"'                               '\X22'                     "符  

    
[3] Box2d源码学习<2>内存管理之SOA的实现
    来源: 互联网  发布时间: 2014-02-18
Box2d源码学习<二>内存管理之SOA的实现

本系列博客是由扭曲45原创,欢迎转载,转载时注明出处,http://blog.csdn.net/cg0206/article/details/8258166

SOA,全称small object allocator,中文意思是小对象分配器。box2d虽然是用c++写的,但是并没有使用c++自带的new/delete实现内存管理,而是使用在c的malloc/free做法的基础上封装了类b2BlockAllocator进行内存管理,使得分配和使内存变得更加高效、快速。其中b2BlockAllocator就是一个SOA,下面我们就对源码进行分析。


一、b2BlockAllocator类的头文件

首先我们对头文件b2BlockAllocator.h进行大致的了解一遍。不多说,上代码:

//一次分配内存大小
const int32 b2_chunkSize = 16 * 1024;
//块子节点大小的最大值
const int32 b2_maxBlockSize = 640;
//可以申请块子节点大小的类型总数
const int32 b2_blockSizes = 14;
//块空间增量
const int32 b2_chunkArrayIncrement = 128;
//块子节点结构体[链表实现]声明
struct b2Block;
//块结构体声明
struct b2Chunk;

//这是一个小型的对象分配器,用于一次分配多个小对象
class b2BlockAllocator
{
public:
	b2BlockAllocator();
	~b2BlockAllocator();

	//分配内存,当size>b2_maxBlockSize则直接用b2Alloc分配
	void* Allocate(int32 size);

	//释放内存,当size>b2_maxBlockSize则直接用b2Free释放
	void Free(void* p, int32 size);
	//清空内存
	void Clear();

private:
	//当前块的头指针
	b2Chunk* m_chunks;
	//当前已使用的块空间节点总数
	int32 m_chunkCount;
	//当前已申请的块空间节点总数
	int32 m_chunkSpace;
	//未被使用的内存块链表类型数组,保存了其不同类型链表的头指针
	b2Block* m_freeLists[b2_blockSizes];
	//申请的块大小类型数组
	static int32 s_blockSizes[b2_blockSizes];
	//根据要申请块的大小获取其类型索引的数组
	static uint8 s_blockSizeLookup[b2_maxBlockSize + 1];
	//是否已初始化s_blockSizeLookup数组,标志变量
	static bool s_blockSizeLookupInitialized;
};

上面文字是对相关字段及方法的注释,我们就不对其进行讲解了。


二、b2BlockAllocator的.c文件

下面我们看该类的具体实现,看b2BlockAllocator.c文件,
1、变量的定义

映入我们眼帘的是一些变量或结构的定义,如下代码:

int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] = 
{
    16,        // 0
    32,        // 1
    64,        // 2
    96,        // 3
    128,    // 4
    160,    // 5
    192,    // 6
    224,    // 7
    256,    // 8
    320,    // 9
    384,    // 10
    448,    // 11
    512,    // 12
    640,    // 13
};
uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1];
bool b2BlockAllocator::s_blockSizeLookupInitialized;

struct b2Chunk
{
    int32 blockSize;
    b2Block* blocks;
};

struct b2Block
{
    b2Block* next;
};

s_blockSizes       :是申请的块子节点大小类型数组,主要负责将相应大小的子节点分类;
blockSizeLookup:是根据要申请的子节点size获取s_blockSizes数组的索引,并保持到该数组中;
s_blockSizeLookupInitialized:是否已初始化s_blockSizeLookup数组,标志变量,用于只需要初始化很少次数的变量,可以人为控制【但是最好还是不要那么做】,默认值是false,也许大家感到奇怪,这个变量在哪初始化的,大家可以猜猜看。
b2Chunk是块结构体,其中blockSize表示块子节点大小,blocks表示块头指针;
b2Block表示块子节点结构体,next表示下一个块头指针,如果你感觉到很熟悉的话,那就对了,这是典型的链表定义,将会用链表将子节点链接起来。


2、函数的实现
    1)、构造函数和析构函数
接下来就是该类的构造函数和析构函数了,同样我们也看代码。

b2BlockAllocator::b2BlockAllocator()
{
	b2Assert(b2_blockSizes < UCHAR_MAX);

	m_chunkSpace = b2_chunkArrayIncrement;
	m_chunkCount = 0;
	m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
	
	memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
	memset(m_freeLists, 0, sizeof(m_freeLists));

	if (s_blockSizeLookupInitialized == false)
	{
		int32 j = 0;
		for (int32 i = 1; i <= b2_maxBlockSize; ++i)
		{
			b2Assert(j < b2_blockSizes);
			if (i <= s_blockSizes[j])
			{
				s_blockSizeLookup[i] = (uint8)j;
			}
			else
			{
				++j;
				s_blockSizeLookup[i] = (uint8)j;
			}
		}

		s_blockSizeLookupInitialized = true;
	}
}

b2BlockAllocator::~b2BlockAllocator()
{
	for (int32 i = 0; i < m_chunkCount; ++i)
	{
		b2Free(m_chunks[i].blocks);
	}

	b2Free(m_chunks);
}
在构造函数b2BlockAllocator()中我们初始化相关变量,例如一开始我们就判断b2_blockSizes的有效性,接着为m_chunkSpace、m_chunkCount、m_chuns、m_freeLists、和s_blockSizeLookup的初始化。我们主要说说s_blockSizeLookup的初始化是怎样完成的。
a)、用s_blockSizeLookupInitialized判断s_blockSizeLookup是否已初始化,若没有则进入。大家猜到绿色部分的疑问了没,如果你的答案是编译器,那就恭喜你了。
b)、里面的for循环主要是根据块的大小,将块分类成以上14中类型,并设置索引值,保存到s_blockSizeLookup数组中,j保存的是s_blockSizes数组的索引值。
c)、接着判断j的有效性,这里用的是assert断言,关于assert断言的又不懂的童鞋可以参照维基百科上面的解释http://zh.wikipedia.org/wiki/Assert.h
d)、if/else中i不大于j索引对应的块大小类型的数组,则将j索引的值赋给类型索引数组,例如,j = 0时,i的值可以是 1-16。否则i>j索引对应的块大小类型的数组,则将j索引自增,赋值。上面代码可以简化成:

if(i > s_blockSizes[j])
{
	++j;
}
s_blockSizeLookup[i] = (uint8)j;
虽然效率差了点:-D,但这样更易于理解。
e)、将标志变量置s_blockSizeLookupInitialized为true,表示已经初始化在析构函数~b2BlockAllocator()我们释放了当前块的每个子节点,和整个块。


2)、内存管理函数内存管理函数分为三个:Allocate分配函数;Free释放函数;Clear清理内存函数
关于Allocate函数,代码如下:
void* b2BlockAllocator::Allocate(int32 size)
{
	if (size == 0)
		return NULL;
	//验证size的有效性
	b2Assert(0 < size);
	//申请的空间大于规定的最大值,
	//直接申请,不放到块的链表中去【即m_chunks】
	if (size > b2_maxBlockSize)
	{
		return b2Alloc(size);
	}
	//根据要申请的内存大小获取内存类型索引值,并判断有效性
	int32 index = s_blockSizeLookup[size];
	b2Assert(0 <= index && index < b2_blockSizes);
	//查看是否有同类型的未被使用的内存块
	if (m_freeLists[index])
	{
		b2Block* block = m_freeLists[index];
		m_freeLists[index] = block->next;
		return block;
	}
	else
	{
		//已使用的大小与已申请的块大小相等
		//重新申请空间
		if (m_chunkCount == m_chunkSpace)
		{
			//获取原来的块头,并保存到oldChunks中
			b2Chunk* oldChunks = m_chunks;
			//扩充块空间的大小
			m_chunkSpace += b2_chunkArrayIncrement;
			//申请空间,并重新赋值给m_chunks变量
			m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
			//拷贝内存到m_chunks中
			memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk));
			//将最新申请的内存的最后b2_chunkArrayIncrement置,防止程序中读取脏数据
			//个人感觉如下写法更易于理解,只是效率要慢一点点啦
			///memset(m_chunks , 0,m_chunkSpace * sizeof(b2Chunk));
			///memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk));
			memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk));
			//释放原来的块空间
			b2Free(oldChunks);
		}
		//获取已使用块空间的尾指针
		b2Chunk* chunk = m_chunks + m_chunkCount;
		//申请n个块子节点内存
		//并将地址赋值给块头指针
		//这样的好处是不需要频繁的去内存中申请空间,不必每个节点都去申请,提高了效率
		chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize);
                //用于调试,正式版本中将关闭_DEBUG宏,故不存在相关代码,以后我们遇到相关代码块也将忽略
#if defined(_DEBUG)
memset(chunk->blocks, 0xcd, b2_chunkSize);
#endif
		//获取根据索引块大小,并赋值给块的大小
		int32 blockSize = s_blockSizes[index];
		chunk->blockSize = blockSize;
		//获取子节点个数
		//并防止转换时出现错误【个人猜测,有待考证】
		int32 blockCount = b2_chunkSize / blockSize;
		b2Assert(blockCount * blockSize <= b2_chunkSize);
		//将子节点用链表的方式串起来
		//有人不禁疑惑,这不是刚刚申请的一个连续的内存块吗?
		//用头指针可以直接访问呀?干嘛要串起来?
		//好处:
		//可以自由的操作每个子节点,例如、释放、访问、其它方式链接等,在后面我们将看见
		for (int32 i = 0; i < blockCount - 1; ++i)
		{
			b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i);
			b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1));
			block->next = next;
		}
		//获取最后一个内存块的子节点
		//并将子节点的下一个节点置空
		b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1));
		last->next = NULL;
		//将申请且未使用的指针保存到m_freeLists对应类型的数组中
		m_freeLists[index] = chunk->blocks->next;
		//当前已使用的块空间节点总数
		++m_chunkCount;
		//返回块的头指针
		return chunk->blocks;
	}

代码的解释如上述,在此就不啰嗦了,不过我们总体分析一下,它的逻辑是:

a)、将内存按大小分为16,32,64,96,128,160,192,224,256...640等b2_blockSizes【即14】类,并按照顺序保存到数组s_blockSizes中。

b)、通过申请size的大小,判断是否大于b2_maxBlockSize,如果大于则直接分配。

c)、否则通过size,传递给s_blockSizeLookup数组找到所需要申请的类型index,将index的值在传递给链表数组m_freelists[index],查找是否有子节点,有则直接返回子节点。

d)、否则将判断m_chunks指向的动态数组是否已用完,若用完则扩充块空间大小加b2_chunkArrayIncrement,重新申请空间,并将空间的内存拷贝到现在的空间中,并释放原内存空间。

e)、通过m_chunks+m_chunkCount获取块空间的m_chunks动态数组的未被使用的空间元素,申请大小为b2_chunkSize的内存,并将其分成对应类型的n块空间,并将这n个子节点串链起来,形成链表。将链表的下一个指针保存到对应类型的m_freeLists数组中,同时返回头指针作为申请的内存地址。

关于Free函数,代码和注释如下:

void b2BlockAllocator::Free(void* p, int32 size)
{
	//判断检测size是否有效
	//并作相应的处理
	if (size == 0)
	{
		return;
	}

	b2Assert(0 < size);

	if (size > b2_maxBlockSize)
	{
		b2Free(p);
		return;
	}
	//根据内存大小获取索引值,并判断是否有效
	int32 index = s_blockSizeLookup[size];
	b2Assert(0 <= index && index < b2_blockSizes);

#ifdef _DEBUG
	// Verify the memory address and size is valid.
	int32 blockSize = s_blockSizes[index];
	bool found = false;
	for (int32 i = 0; i < m_chunkCount; ++i)
	{
		b2Chunk* chunk = m_chunks + i;
		if (chunk->blockSize != blockSize)
		{
			b2Assert(	(int8*)p + blockSize <= (int8*)chunk->blocks ||
						(int8*)chunk->blocks + b2_chunkSize <= (int8*)p);
		}
		else
		{
			if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize)
			{
				found = true;
			}
		}
	}

	b2Assert(found);

	memset(p, 0xfd, blockSize);
#endif
	//获取块的块的头指针并插入到相应的空闲链表的头部【注意是子节点从链表头部插入】,并保存相应的头指针到m_freeLists中去
	b2Block* block = (b2Block*)p;
	block->next = m_freeLists[index];
	m_freeLists[index] = block;
}

同样,_DEBUG宏类的我们不做讨论。这里说明一下,若内存小于等于b2_maxBlockSize时,此时内存空间并没有释放,而是将链接到相应类型的空闲链表中,并且是从链表头部插入此节点的,对此这也是很容易做到的,这也是刚刚申请空间将连续的空间分割,再次链接成链表的原因。


再看Clear函数
void b2BlockAllocator::Clear()
{
	//释放当前已使用的块空间大小
	for (int32 i = 0; i < m_chunkCount; ++i)
	{
		b2Free(m_chunks[i].blocks);
	}

	m_chunkCount = 0;
	//清空块
	memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
	//清空未被使用的内存块链表类型数组
	memset(m_freeLists, 0, sizeof(m_freeLists));
}

只是释放了形成链表的块内存,m_chunks和m_freeLists也只是清空其内容,真正释放它们是在上面说的类的析构函数中。

ok,不多说了,有什么错误、不妥之处,希望大家能多多指正。也希望和大家多多交流。





    
最新技术文章:
▪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