2024年最全Android音视频开发之——音频非压缩编码和压缩编码,android设计计算器的界面

最后

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】

Android精讲视频领取学习后更加是如虎添翼!进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 开启录制线程,通过AudioRecord将录制的音频数据从缓存中读取并写入文件

  • 释放资源

在使用AudioRecord前需要先注意添加RECORD_AUDIO录音权限。

创建AudioRecord

我们先看看AudioRecord构造方法

public AudioRecord (int audioSource,

int sampleRateInHz,

int channelConfig,

int audioFormat,

int bufferSizeInBytes)

  • audioSource,从字面意思可知音频来源,由MediaRecorder.AudioSource提供,主要有以下内容

· CAMCORDER 与照相机方向相同的麦克风音频源

· DEFAULT 默认

· MIC 麦克风音频源

· VOICE_CALL 语音通话

这里采用MIC麦克风音频源

  • sampleRateInHz,采样率,即录制的音频每秒钟会有多少次采样,可选用的采样频率列表为:8000、16000、22050、24000、32000、44100、48000等,一般采用人能听到最大音频的2倍,也就是44100Hz。

  • channelConfig,声道数的配置,可选值以常量的形式配置在类AudioFormat中,常用的是CHANNEL_IN_MONO(单声道)、CHANNEL_IN_STEREO(双声道)

  • audioFormat,采样格式,可选值以常量的形式定义在类AudioFormat中,分别为ENCODING_PCM_16BIT(16bit)、ENCODING_PCM_8BIT(8bit),一般采用16bit。

  • bufferSizeInBytes,其配置的是AudioRecord内部的音频缓冲区的大小,可能会因为生产厂家的不同而有所不同,为了方便AudioRecord提供了一个获取该值最小缓冲区大小的方法getMinBufferSize

public static int getMinBufferSize (int sampleRateInHz,

int channelConfig,

int audioFormat)

在开发过程中需使用getMinBufferSize此方法计算出最小缓存大小。

切换录制状态

首先通过调用getState判断AudioRecord是否初始化成功,然后通过startRecording切换成录制状态

if (null!=audioRecord && audioRecord?.state!=AudioRecord.STATE_UNINITIALIZED){

audioRecord?.startRecording()

}

开启录制线程

thread = Thread(Runnable {

writeData2File()

})

thread?.start()

开启录音线程将录音数据通过AudioRecord写入文件

private fun writeData2File() {

var ret = 0

val byteArray = ByteArray(bufferSizeInBytes)

val file = File(externalCacheDir?.absolutePath + File.separator + filename)

if (file.exists()) {

file.delete()

} else {

file.createNewFile()

}

val fos = FileOutputStream(file)

while (status == Status.STARTING) {

ret = audioRecord?.read(byteArray, 0, bufferSizeInBytes)!!

if (ret!=AudioRecord.ERROR_BAD_VALUE || ret!=AudioRecord.ERROR_INVALID_OPERATION|| ret!=AudioRecord.ERROR_DEAD_OBJECT){

fos.write(byteArray)

}

}

fos.close()

}

释放资源

首先停止录制

if (null!=audioRecord && audioRecord?.state!=AudioRecord.STATE_UNINITIALIZED){

audioRecord?.stop()

}

然后停止线程

if (thread!=null){

thread?.join()

thread =null

}

最后释放AudioRecord

if (audioRecord != null) {

audioRecord?.release()

audioRecord = null

}

通过以上一个流程之后,就可以得到一个非压缩编码的PCM数据了。

但是这个数据在音乐播放器上一般是播放不了的,那么怎么验证我是否录制成功呢?当然是使用我们的AudioTrack进行播放看看是不是刚刚我们录制的声音了。

AudioTrack


由于AudioTrack是由Android SDK提供比较底层的播放API,也只能操作PCM裸数据,通过直接渲染PCM数据进行播放。当然如果想要使用AudioTrack进行播放,那就需要自行先将压缩编码格式文件解码。

AudioTrack的使用流程大致如下:

  • 根据音频参数创建AudioTrack

  • 调用play开始播放

  • 开启播放线程,循环想AudioTrack缓存区写入音频数据

  • 释放资源

创建AudioTrack

我们来看看AudioTrack的构造方法

public AudioTrack (int streamType,

int sampleRateInHz,

int channelConfig,

int audioFormat,

int bufferSizeInBytes,

int mode,

int sessionId)

  • streamType,Android手机上提供音频管理策略,按下音量键我们会发现由媒体声音管理,闹铃声音管理,通话声音管理等等,当系统有多个进程需要播放音频的时候,管理策略会决定最终的呈现效果,该参数的可选值将以常量的形式定义在类AudioManager中,主要包括以下内容:

· STREAM_VOCIE_CALL:电话声音

· STREAM_SYSTEM:系统声音

· STREAM_RING:铃声

· STREAM_MUSCI:音乐声

· STREAM_ALARM:警告声

· STREAM_NOTIFICATION:通知声

因为这里是播放音频,所以我们选择STREAM_MUSCI

  • sampleRateInHz,采样率,即播放的音频每秒钟会有多少次采样,可选用的采样频率列表为:8000、16000、22050、24000、32000、44100、48000等,一般采用人能听到最大音频的2倍,也就是44100Hz。

  • channelConfig,声道数的配置,可选值以常量的形式配置在类AudioFormat中,常用的是CHANNEL_IN_MONO(单声道)、CHANNEL_IN_STEREO(立体双声道)

  • audioFormat,采样格式,可选值以常量的形式定义在类AudioFormat中,分别为ENCODING_PCM_16BIT(16bit)、ENCODING_PCM_8BIT(8bit),一般采用16bit。

  • bufferSizeInBytes,其配置的是AudioTrack内部的音频缓冲区的大小,可能会因为生产厂家的不同而有所不同,为了方便AudioTrack提供了一个获取该值最小缓冲区大小的方法getMinBufferSize

  • mode,播放模式,AudioTrack提供了两种播放模式,可选的值以常量的形式定义在类AudioTrack中,一个是MODE_STATIC,需要一次性将所有的数据都写入播放缓冲区中,简单高效,通常用于播放铃声、系统提醒的音频片段;另一个是MODE_STREAM,需要按照一定的时间间隔不间断地写入音频数据,理论上它可以应用于任何音频播放的场景。

  • sessionId,AudioTrack都需要关联一个会话Id,在创建AudioTrack时可直接使用AudioManager.AUDIO_SESSION_ID_GENERATE,或者在构造之前通过AudioManager.generateAudioSessionId获取。

上面这种构造方法已经被弃用了,现在基本使用如下构造(最小skd 版本需要>=21),参数内容与上基本一致:

public AudioTrack (AudioAttributes attributes,

AudioFormat format,

int bufferSizeInBytes,

int mode,

int sessionId)

通过AudioAttributes.Builder设置参数streamType

var audioAttributes = AudioAttributes.Builder()

.setLegacyStreamType(AudioManager.STREAM_MUSIC)

.build()

通过AudioFormat.Builder设置channelConfig,sampleRateInHz,audioFormat参数

var mAudioFormat = AudioFormat.Builder()

.setChannelMask(channel)

.setEncoding(audioFormat)

.setSampleRate(sampleRate)

.build()

切换播放状态

首先通过调用getState判断AudioRecord是否初始化成功,然后通过play切换成录播放状态

if (null!=audioTrack && audioTrack?.state != AudioTrack.STATE_UNINITIALIZED){

audioTrack?.play()

}

开启播放线程

开启播放线程

thread= Thread(Runnable {

readDataFromFile()

})

thread?.start()

将数据不断的送入缓存区并通过AudioTrack播放

private fun readDataFromFile() {

val byteArray = ByteArray(bufferSizeInBytes)

val file = File(externalCacheDir?.absolutePath + File.separator + filename)

if (!file.exists()) {

Toast.makeText(this, “请先进行录制PCM音频”, Toast.LENGTH_SHORT).show()

return

}

val fis = FileInputStream(file)

var read: Int

status = Status.STARTING

while ({ read = fis.read(byteArray);read }() > 0) {

var ret = audioTrack?.write(byteArray, 0, bufferSizeInBytes)!!

if (ret == AudioTrack.ERROR_BAD_VALUE || ret == AudioTrack.ERROR_INVALID_OPERATION || ret == AudioManager.ERROR_DEAD_OBJECT) {

break

}

}

fis.close()

}

释放资源

首先停止播放

if (audioTrack != null && audioTrack?.state != AudioTrack.STATE_UNINITIALIZED) {

audioTrack?.stop()

}

然后停止线程

if (thread!=null){

thread?.join()

thread =null

}

最后释放AudioTrack

if (audioTrack != null) {

audioTrack?.release()

audioTrack = null

}

经过这样几个步骤,我们就可以听到刚刚我们录制的PCM数据声音啦!这就是使用Android提供的AudioRecordAudioTrack对PCM数据进行操作。

但是仅仅这样是不够的,因为我们生活中肯定不是使用PCM进行音乐播放,那么怎么才能让音频在主流播放器上播放呢?这就需要我们进行压缩编码了,比如mp3或aac压缩编码格式。

MediaCodec编码AAC


AAC压缩编码是一种高压缩比的音频压缩算法,AAC压缩比通常为18:1;采样率范围通常是8KHz~96KHz,这个范围比MP3更广一些(MP3的范围一般是:16KHz~48KHz),所以在16bit的采样格式上比MP3更精细。

方便我们处理AAC编码,Android SDK中提供了MediaCodecAPI,可以将PCM数据编码成AAC数据。大概需要以下几个步骤:

  • 创建MediaCodec

  • MediaCodec配置音频参数

  • 启动线程,循环往缓冲区送入数据

  • 通过MediaCodec将缓冲区的数据进行编码并写入文件

  • 释放资源

创建MediaCodec

通过MediaCodec.createEncoderByType创建编码MediaCodec

mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC)

配置音频参数

// 配置采样率和声道数

mediaFormat = MediaFormat.createAudioFormat(MINE_TYPE,sampleRate,channel)

// 配置比特率

mediaFormat?.setInteger(MediaFormat.KEY_BIT_RATE,bitRate)

// 配置PROFILE,其中属AAC-LC兼容性最好

mediaFormat?.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC)

// 最大输入大小

mediaFormat?.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 10 * 1024)

mediaCodec!!.configure(mediaFormat,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE)

mediaCodec?.start()

inputBuffers = mediaCodec?.inputBuffers

outputBuffers = mediaCodec?.outputBuffers

启动线程

启动线程,循环读取PCM数据送入缓冲区

thread = Thread(Runnable {

val fis = FileInputStream(pcmFile)

fos = FileOutputStream(aacFile)

var read: Int

while ({ read = fis.read(byteArray);read }() > 0) {

encode(byteArray)

}

})

thread?.start()

AAC编码

将送入的PCM数据通过MediaCodec进行编码,大致流程如下:

  • 通过可用缓存去索引,获取可用输入缓冲区

  • 将pcm数据放入输入缓冲区并提交

  • 根据输出缓冲区索引,获取输出缓冲区

  • 创建输出数据data,并添加ADTS头部信息(有7byte)

  • outputBuffer编码后数据写入data(data有7byte偏移)

  • 将编码数据data写入文件

  • 重复以上过程

private fun encode(byteArray: ByteArray){

mediaCodec?.run {

//返回要用有效数据填充的输入缓冲区的索引, -1 无限期地等待输入缓冲区的可用性

val inputIndex = dequeueInputBuffer(-1)

if (inputIndex > 0){

// 根据索引获取可用输入缓存区

val inputBuffer = this@AACEncoder.inputBuffers!![inputIndex]

// 清空缓冲区

inputBuffer.clear()

// 将pcm数据放入缓冲区

inputBuffer.put(byteArray)

// 提交放入数据缓冲区索引以及大小

queueInputBuffer(inputIndex,0,byteArray.size,System.nanoTime(),0)

}

// 指定编码器缓冲区中有效数据范围

val bufferInfo = MediaCodec.BufferInfo()

// 获取输出缓冲区索引

var outputIndex = dequeueOutputBuffer(bufferInfo,0)

while (outputIndex>0){

// 根据索引获取可用输出缓存区

val outputBuffer =this@AACEncoder.outputBuffers!![outputIndex]

// 测量输出缓冲区大小

val bufferSize = bufferInfo.size

// 输出缓冲区实际大小,ADTS头部长度为7

val bufferOutSize = bufferSize+7

// 指定输出缓存区偏移位置以及限制大小

outputBuffer.position(bufferInfo.offset)

outputBuffer.limit(bufferInfo.offset+bufferSize)

// 创建输出空数据

val data = ByteArray(bufferOutSize)

// 向空数据先增加ADTS头部

addADTStoPacket(data, bufferOutSize)

// 将编码输出数据写入已加入ADTS头部的数据中

outputBuffer.get(data,7,bufferInfo.size)

// 重新指定输出缓存区偏移

outputBuffer.position(bufferInfo.offset)

// 将获取的数据写入文件

fos?.write(data)

// 释放输出缓冲区

releaseOutputBuffer(outputIndex,false)

// 重新获取输出缓冲区索引

outputIndex=dequeueOutputBuffer(bufferInfo,0)

}

}

}

释放资源

编码完成后,一定要释放所有资源,首先关闭输入输出流

fos?.close()

fis.close()

停止编码

if (mediaCodec!=null){

mediaCodec?.stop()

}

然后就是关闭线程

if (thread!=null){

thread?.join()

thread =null

}

最后释放MediaCodec

if (mediaCodec!=null){

mediaCodec?.release()

mediaCodec = null

mediaFormat = null

inputBuffers = null

outputBuffers = null

}

通过以上一个流程,我们就可以得到一个AAC压缩编码的音频文件,可以听一听是不是自己刚刚录制的。我听了一下我自己唱的一首歌,觉得我的还是可以的嘛,也不是那么五音不全~~

Android NDK


虽然我们通过压缩编码生成了AAC音频文件,但是有个问题:毕竟AAC音频不是主流的音频文件呀,我们最常见的是MP3的嘛,可不可以将PCM编码成MP3呢?

当然是可以的,但是Android SDK没有直接提供这样的API,只能使用Android NDK,通过交叉编译其他C或C++库来进行实现。

Android NDK 是由Google提供一个工具集,可让您使用 C 和 C++ 等语言实现应用。

Android NDK 一般有两个用途,一个是进一步提升设备性能,以降低延迟,或运行计算密集型应用,如游戏或物理模拟;另一个是重复使用您自己或其他开发者的 C 或 C++ 库。当然我们使用最多的应该还是后者。

想使用Android NDK调试代码需要以下工具:

  • Android 原生开发套件 (NDK):这套工具使您能在 Android 应用中使用 C 和 C++ 代码。

  • CMake:一款外部编译工具,可与 Gradle 搭配使用来编译原生库。如果您只计划使用 ndk-build,则不需要此组件。

  • LLDB:Android Studio 用于调试原生代码的调试程序。

可以进入Tools > SDK Manager > SDK Tools 选择 NDK (Side by side) 和 CMake 应用安装

在应用以上选项之后,我们可以看到SDK的目录中多了一个ndk-bundle的文件夹,大致目录结构如下

  • ndk-build:该Shell脚本是Android NDK构建系统的起始点,一般在项目中仅仅执行这一个命令就可以编译出对应的动态链接库了,后面的编译mp3lame 就会使用到。

  • platforms:该目录包含支持不同Android目标版本的头文件和库文件,NDK构建系统会根据具体的配置来引用指定平台下的头文件和库文件。

  • toolchains:该目录包含目前NDK所支持的不同平台下的交叉编译器——ARM、x86、MIPS,其中比较常用的是ARM和x86。不论是哪个平台都会提供以下工具:

·CC:编译器,对C源文件进行编译处理,生成汇编文件。

·AS:将汇编文件生成目标文件(汇编文件使用的是指令助记符,AS将它翻译成机器码)。

·AR:打包器,用于库操作,可以通过该工具从一个库中删除或者增加目标代码模块。

·LD:链接器,为前面生成的目标代码分配地址空间,将多个目标文件链接成一个库或者是可执行文件。

·GDB:调试工具,可以对运行过程中的程序进行代码调试工作。

·STRIP:以最终生成的可执行文件或者库文件作为输入,然后消除掉其中的源码。

·NM:查看静态库文件中的符号表。

·Objdump:查看静态库或者动态库的方法签名。

了解Android NDK 之后,就可新建一个支持C/C++ 的Android项目了:

  • 在向导的 Choose your project 部分中,选择 Native C++ 项目类型。

  • 点击 Next。

  • 填写向导下一部分中的所有其他字段。

  • 点击 Next。

  • 在向导的 Customize C++ Support 部分中,您可以使用 C++ Standard 字段来自定义项目。使用下拉列表选择您想要使用哪种 C++ 标准化。选择 Toolchain Default 可使用默认的 CMake 设置。

  • 点击 Finish,同步完成之后会出现如下图所示的目录结构,即表示原生项目创建完成

编译Lame


LAME是一个开源的MP3音频压缩库,当前是公认有损质量MP3中压缩效果最好的编码器,所以我们选择它来进行压缩编码,那如何进行压缩编码呢?主流的由两种方式:

  • Cmake

  • ndk-build

下面就详细讲解这两种方式

Cmake编译Lame

配置Cmake之后可以直接将Lame代码运行于Android中

准备

下载Lame-3.100并解压大概得到如下目录

然后将里面的libmp3lame文件夹拷贝到我们上面创建的支持c/c++项目,删除其中的i386和vector文件夹,以及其他非.c 和 .h 后缀的文件

需要将以下文件进行修改,否则会报错

  • 将util.h中570行

extern ieee754_float32_t fast_log2(ieee754_float32_t x)

替换成

总结

其实客户端开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

Android大厂面试真题全套解析

2017-2020字节跳动Android面试真题解析PDF
然而Android架构学习进阶是一条漫长而艰苦的道路,不能靠一时激情,更不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

ild

下面就详细讲解这两种方式

Cmake编译Lame

配置Cmake之后可以直接将Lame代码运行于Android中

准备

下载Lame-3.100并解压大概得到如下目录

然后将里面的libmp3lame文件夹拷贝到我们上面创建的支持c/c++项目,删除其中的i386和vector文件夹,以及其他非.c 和 .h 后缀的文件

需要将以下文件进行修改,否则会报错

  • 将util.h中570行

extern ieee754_float32_t fast_log2(ieee754_float32_t x)

替换成

总结

其实客户端开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

[外链图片转存中…(img-mPcrZLmp-1715857597464)]

[外链图片转存中…(img-w6QIm9Fr-1715857597465)]
然而Android架构学习进阶是一条漫长而艰苦的道路,不能靠一时激情,更不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
简易计算机的设计 摘要:Android是当今最重要的手机开发平台之一,它是建立在Java基础之上的,能 够迅速建立手机软件的解决方案。Android的功能十分强大,成为当今软件行业的一股新 兴力量。Android基于Linux平台,由操作系统、中间件、用户界面和应用软件组成,具 有以下5个特点:开放性、应用程序无界限、应用程序是在平等条件下创建的、应用程序 可以轻松的嵌入网络、应用程序可以并行运行。 一、实训目的 1、了解Android系统,学会Android开发环境的搭建。 2、了解Eclipse,学会用Eclipse和Java 开发一个Android程序。 3、进一步巩固课堂上所学到的知识,深刻把握Java语言的重要概念及其面向对象的特性 ,能够熟练的应用面向对象的思想和设计方法解决实际问题的能力。 4、巩固所学Java语言基本知识,增进Java语言编辑基本功,掌握JDK、Editplus、Ecli pse、JCreator等开发工具的运用,拓宽常用类库的应用。 二、实训任务 1、Activity的相关知识 简单理解Activity 代表一个用户所能看到的屏幕,Activity 主要是处理一个应用的整体性工作。Activity是最基本的Android 应用程序组件,应用程序中,一个活动通常就是一个单独的屏幕。每一个活动都被实现 为一个独立的类,并且从活动基类中继承而来,活动类将会显示由视图控件组成的用户 接口,并对事件做出响应。大多数的应用是由多个屏幕显示组成,因而要用到多个Acti vity。 (1)Activity的相关方法及相关函数:void onCreate(Bundle)首次启动时调用,接受参数:Null or savedInstanceState(保存的以前某些状态信息); void onStart() 说明了将要显示给用户的活动;void onRestart()将处于停止状态的活动重新显示给用户;void onResume()用户可以开始与活动进行交互时调用。如动画播放和音乐播放;void onPause()活动将要进入后台运行时调用。(此时前台启动了另一个活动);void onStop()不需要某个活动了,就调用;void onDestroy()销毁活动。 (2)多个Activity之间的跳转:通过Intent类实现屏幕之间的跳转(包括没有参数关系 和需要传递参数两种情况)。 (3)两个Activity之间进行数据交换:startActivity() 只有Intent一个参数;public void startSubActivity(Intent intent, int requestCode) (requestCode:用来标识某一个调用,一般定义一个常量)。传过去:函数原型为: public Intent setData(ContentURI data) 然后,参数带到新的Activity后,同样用Activity.getIntent()函数可得到当前过来的 Intent对象,然后用getData()就取到参数了。 传回来:函数原型为: public final void setResult(int resultCode, String data)。 2、Intent的相关知识 Intent 是描述应用想要做什么。Android 使用了Intent 这个特殊类,实现在屏幕与屏幕之间移动。Intent 数据结构两个最重要的部分是动作和动作对应的数据。Intent类绑定一次操作,它负责 携带这次操作所需要的数据以及操作的类型等。 3、Layout 用于用户界面设计。包含AbsoluteLayout, FrameLayout,GridView, LinearLayout, ListLayout, RadioGroup, TableLayout等等。 (1)线性布局LinearLayout:垂直:android:orientation="vertical";水平:andro id:orientation="horizontal" (2)相对布局RelativeLayout:让子元素指定它们相对于其他元素的位置(通过ID 来指定)或相对于父布局对象。在RelativeLayout布局里的控件包含丰富的排列属性:L ayout above:控件在指定控件的上方;Layout below:控件在指定控件的下方;Layout to left of…… 根据要求,系统实现以下功能:计算器界面友好,具有基本的加、减、乘、除功能, 支持触屏手机,整个程序基于android技术开发。 三、设计流程 1、系统的软件结构图 2、功能的操作流程 得出程序结果后,输入数据,选择运算符号,再输入数据,选择等号,即可得到结果 。 3、计算

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值