从零开始写安卓APP 《第一行代码》笔记 第一周

这是软件开发课的任务,本人其实不会java也不会安卓开发。以前只做过web端,因为某课程的爆炸实验单人撸了全栈。不过好在很早前就想学了,这里记录一下过程。放的主要是《第一行代码》的一些笔记,和一些遇到的小问题。我负责前端,后端的东西可能涉及比较少。
第一周的目标:完成登录界面,如果可以,做一下底层任务栏(类似微信)。因此大体上需要阅读第一到第三章的内容。

第一章 关于Android

1.1 Android系统架构

  • Linux内核层:底层驱动
  • 系统运行库层:特性支持
  • 应用框架层:API
  • 应用层:应用程序

1.2 Android应用开发特色

  • 四大组件:活动,门面;服务,后台;广播接收器,接受各处的广播消息,如电话;内容提供器,程序间共享数据。
  • 系统控件
  • SQLite数据库:支持标准SQL
  • 多媒体
  • 地理位置定位

搭建开发环境
之前已经弄好了,可以运行hello world程序。

2.1分析Android程序

  • .gradle .idea:自动生成的,不用管
  • app 开发工作基本上都在这个目录下进行
  • build 不用管
  • gradle: gradle wrapper的配置文件
  • .gitignore版本控制
  • build.gradle一般不用改
  • gradle.properties 全局gradle配置文件
  • gradlew gradlew.bat 在命令行界面执行gradle指令,后者在windows系统中使用
  • helloworld.iml 不需要修改
  • local.properties 不需要修改,跟SDK路径有关
  • settings.gradle指定项目中所有引入的模块,很少需要手动添加

2.2 展开app来看

  • build 不需要关心
  • libs 第三方jar包
  • androidTest 编写测试用例
  • java 放java代码
  • res 图片、布局、字符串等资源
  • .xml 项目的配置文件
  • test 测试用例2
  • .gitignore 与外层相似
  • .iml不关心
  • build.gradle 指定很多与项目构建相关的配置
  • proguard-rules.pro 混淆规则,防止破解

3 HelloWorld是怎么跑起来的?

  • 在.xml里面注册活动,HW是主活动
  • 该活动继承于AppCompatActivity(是Activity的子类)
  • 活动的两行代码:一行创建活动,一行将活动与对应的布局文件引入(逻辑与视图分离,我后面应该有很多工作是在布局文件里)
  • 在布局文件里面就可以看到textview啦

4.1 详解res

  • drawble 图片
  • mipmap 图标
  • values 字符串 样式 颜色
  • layout 布局文件
    为了兼容各种设备,会有各种文件夹,存不同分辨率。

4.2 如何使用这些资源?

  • 在代码中使用R.string.hello_world
  • 在XML中通过@string/hello_world

5.1 详解build.gradle
Android采用gradle来构建项目(这块儿先跳过了)

5.2 日志工具

  • Log.v() 最琐碎的 - verbose
  • Log.d() 调试信息 - debug
  • i 比较重要的 - info
  • w 警告信息 - warning
  • e 错误信息 - error
    eg. Log.d(“HelloWorldActivity”, “onCreate execute”);
    参数1:类名 参数2:msg
    展示在logcat中
    剩下的功能以后再看

第二章 活动

这章开头真的给我这个前端好大压力呀(笑)
希望做出来的成品能有我画出来的一半好看。

1.1 活动是什么
包含用户界面的组件,主要用于和用户进行交互

1.2 活动的基本用法
1.2.1 创建活动
从零开始写安卓APP 《第一行代码》笔记 第一周_第1张图片
在project视图下(这个视图确实看着更习惯),右键这个com.example.myapplication文件夹,创建活动,目前选择的是empty activity
从零开始写安卓APP 《第一行代码》笔记 第一周_第2张图片
勾选generate layout file自动生成布局文件,勾选launcher activity设置这个活动为主活动。点击Finish后,在对应的java文件里就有这样的内容:

public class Login extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
    }
}

也就是创建活动,以及连接对应的layout。(书里要手动创建的,我就跳过了)
1.2.2 布局的创建与加载
从零开始写安卓APP 《第一行代码》笔记 第一周_第3张图片
布局在资源文件下。打开可以看到布局编辑器。在Design模式下,可以通过拖放的方式编辑布局!!!(我的梦想就是做一个只需要拖拉拽的工具,丢掉代码呜呜呜)在text模式下,写XML文件来编辑布局。
好吧,作者让我们打开text模式,我这里的代码如下:


<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Login">

androidx.constraintlayout.widget.ConstraintLayout>

跟书里作者手动创建的线性布局不一样,但是不要紧。我了解了一下,书里一共写了四种布局,而这里出现的constraintlayout不在其列,是新开发的一种布局,类似相对布局,但更强大。
参考这篇约束布局
还有这篇好像更好约束布局ConstraintLayout看这一篇就够了 - 简书
好了先不纠结布局。来试试其它内容。添加一个按钮。我试着拖动了一个button组件进去,再查看代码,有点QT那味儿。然后手动改了一下,让它能符合约束布局的设置,放在居中、页面中下方的位置(虽然还有点懵)。这就是登录按钮啦。

<Button
        android:id="@+id/login_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="登录"
        android:layout_marginTop="560dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:layout_editor_absoluteX="160dp"
        tools:layout_editor_absoluteY="560dp" />

关于布局的一些详细内容到第三章再学习。
接下来在活动中加载布局。因为我们前面勾选了generate layout file,所以它已经自动写好了setContentView连接上了。写一下原理,项目中每个资源会在R文件中生成对应的资源id。调用R.layout.layoutname就可以获取layoutname.xml布局的id,然后再将这个值传入setContentView()方法。
1.2.3 在AndroidManifest文件中注册

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".Login">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            intent-filter>
        activity>
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            intent-filter>
        activity>
    application>

这个好像已经自动注册了,来看看。
活动的注册声明放在标签里,每个活动的注册放在标签里。包括刚才创建的login和原来的helloworld活动。这是Android Studio自动帮忙注册的。
这里内是在配置主活动。helloworld的主活动设置没删,不知道跑起来会怎么样,还是别试错了,我后面删掉了。
还可以添加标题栏,所以再加一句话。
然后就可以试着跑一下了。
跑一次时间成本蛮高的,大概要两分钟左右(已经用了镜像),所以做的时候要小心些。跑出来长这样:
从零开始写安卓APP 《第一行代码》笔记 第一周_第4张图片
很显然布局有点不符合预期,登录按钮跑最下面去了。不过这不是这一章的重点,第三章再学。不过前面的那段代码大家也不要抄就是了,乖乖点进第二条链接学习。
跑了一次,我的小破电脑已经成了卡顿大师(不应该啊),可惜还没回学校,先将就一下。

1.2.4 在活动中使用Toast
Toast是一种提醒方式,将短小信息通知给用户,一段时间后自动消失,且不会占用任何屏幕空间(有点像alert?)。如何使用呢?

  1. 定义弹出Toast的触发点
    这里现成的就是点击按钮触发toast。在onCreate里面(这是个逻辑问题呢)添加代码。这一坨有点像web端里面,在botton里面设置onclick触发事件,此外获取一个元素也有类似getElementById的方法——findViewById()。在安卓这里是这样写的:
Button button1 = (Button)findViewById(R.id.login_button);
        button1.setOnClickListener(new View.OnClickListener(){
            @Override
            public  void onClick(View v){
                Toast.makeText(Login.this,"欢迎登录",
                        Toast.LENGTH_SHORT).show();
            }
        });

书写起来比alert复杂多了……毕竟那是JS嘛。
这一段的逻辑挺好懂的,跟web端的JS很像,但有点区别,JS更方便些,就不重复书上的原文啦。
Toast.makeText(Context上下文,显示的文本内容,显示的时长)。
然后它又要我们跑一跑。跑当然是能跑,显示时间比较短就不截图了。就是电脑又成了卡顿大师,缓了很久才正常。

1.2.5 在活动中使用Menu
菜单能得到展示的同时不占用任何屏幕空间。
这个后面肯定是需要做的,学习一下,有点复杂。这里步骤完全follow书,没有什么问题。onCreateOptionsMenu和onOptionsItemSelected有点难找,在android.app.Activity下面。
getMenuInflater().inflate(通过哪一个资源文件来创建菜单, 菜单项添加到哪一个Menu对象中);
然后再跑一跑。
从零开始写安卓APP 《第一行代码》笔记 第一周_第5张图片
1.2.6 销毁一个活动
按下Back键就可以销毁了。
也可以使用finish()方法,在按下某个按钮时,监听到按钮被按下就执行。

1.2.7 使用Intent在活动之间穿梭(眼拙一开始看成Internet了)
如何从主活动跳转到其它活动呢?intent用于在各组件中进行交互,这里用到了启动活动的功能。
1.2.7.1使用显示intent
先创建一个新的activity,但不要勾上让它成为主活动。
编辑一下新活动里面的布局,剩下的android studio基本上都帮你做了。
用startActivity()方法,接收一个Intent参数,然后启动目标活动。假设我们点击登录按钮后跳转到第二个活动,那么修改按钮的监听事件如下:

button1.setOnClickListener(new View.OnClickListener(){
            @Override
            public  void onClick(View v){
                Intent intent = new Intent(Login.this,countdown.class);
                startActivity(intent);
            }
        });

先构建一个intent,其中老活动作为上下文,新活动作为目标活动,就是在老活动的基础上打开新活动,然后通过startActivity来执行。
再跑一跑,就可以看到效果了。

1.2.7.2隐式intent
在电脑卡成狗的期间先看看隐式的理论。
我个人理解的是,有的时候我们跳转到哪个活动去不一定是可以写死的,所以需要通过一些抽象的action和category信息,去判断下一个活动。
首先要配置一下我们的新活动,让它可以响应一个Intent。在新活动的下面配置如下:

            <intent-filter>
                <action android:name="com.example.activitytest.ACTION_START" />
                <category android:name="android.intent.category.DEFAULT"/>
            intent-filter>

当action和category都能匹配上intent当中指定的内容时,这个活动才能响应该intent.
同时修改老活动里面的登录按钮。

Intent intent = new Intent("com.example.activitytest.ACTION_START");

跟刚才的区别在于,这次只指定了action,没有指定category那就是默认值,startActivity()方法会自动添加上去。
再跑跑,应该跟刚才效果是一样的。
每个Intent当中只能指定一个action,但可以指定多个category,因此可以在新活动中添加一些category,然后在老活动里这样设置:

Intent intent = new Intent("com.example.activitytest.ACTION_START");
intent.addCategory("com.example.activitytest.MY_CATEGORY");
startActivity(intent);

PS:后端瞒着我没有看书直接硬撸,进度起飞,不过他们搞数据库还要折腾一会儿。前三章看完之后跳转到十二章继续。

1.2.7.3 更多隐式intent的用法
可以跳转到其它程序去,尤其是打开一个浏览器,这次我们应该用不上,先跳过。

1.2.7.4 向下一个活动传递数据 P50
思路:将想要传递的数据暂存在intent当中,启动另一个活动后,将数据从intent当中取出即可。
在老活动的按钮事件里:putExtra(键,数据)
在新页面的onCreate里面:getIntent()获取intent,然后用getStringExtra()或者是getIntExtra()或者是getBooleanExtra()方法来获取传递的数据。

1.2.7.5 返回数据给上一个活动 P51
startActivityForResult(intent,请求码) 请求码用于在之后的回调中判断数据来源。
在老活动的按钮事件里:startActivityForResult(intent,请求码)
在新页面的按钮事件/onBackPressed()里:

  • 构建Intent
  • putExtra 放入数据
  • setResult(返回处理结果RESULT_OK/RESULT_CANCELED,把带数据的intent传递回去)
  • 调用finish()销毁当前活动

此外,在老活动里面要重写onActivityResult()方法,比如如果收到RESULT_OK,就读取数据。
onActivityResult(请求码,处理结果,intent)
根据请求码可以判断数据来源,然后做对应的处理。

1.2.8活动的生命周期
写到这里发现这一章的编号前面的1.有点多余,先不管了。
android是用任务来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈。每启动一个新活动,就入栈,且处于栈顶;每销毁一个活动,处于栈顶的活动就会出栈,而前一个活动就会处于栈顶。

活动状态:

  1. 运行状态:栈顶
  2. 暂停状态:不处于栈顶但可见
  3. 停止状态:不处于栈顶且不可见
  4. 销毁状态:不在栈中

活动的生存期
见书P55 共7个方法。
这一块儿就暂时不体验了,后面用到的时候再做。

活动被回收了怎么办?
如果一个活动因为内存不足被回收了,后续会再次onCreat(),但是其中暂存的数据怎么办呢?
Activity里面提供一个onSaveInstanceState()的回调方法,通过一个bundle类型的参数传递数据。Intent还可以结合bundle一起传递数据。

1.2.9 活动的启动模式
共4种:standard singleTop singleTask singleInstance

  • standard模式
    默认模式,每启动一个新活动,入栈且处于栈顶。不考虑是否已经存在于栈顶,每次都创建新实例。
  • singleTop
    与标准模式不同的是,若已经在栈顶,不会再创建相同的实例。
  • singleTask
    若在栈中存在该活动的实例,不会再创建相同的实例。
  • singleInstance
    若有一个活动允许其它程序共享其实例,则需要用一个单独的返回栈来管理这个活动的实例。

1.2.10 活动的最佳实践
介绍了几种关于活动的运用机巧,mark一下,需要的时候回来看。

  • 查看当前是什么活动
  • 一键退出程序
  • 启动活动的最佳写法

第三章 UI开发

1 常用控件
1.1 TextView
android:layout_width/layout_height 控件的宽度和高度

  • match_parent
    与父布局一致
  • fill_parent
    与match一样,但不建议使用
  • wrap_content
    当前控件大小刚好可以包含住里面的内容

android:gravity 文字对齐方式

  • center = center_vertical | center_horizontal
  • top bottom left right等

android:testSize = “24sp”
android:textColor = “#00ff00”

1.2 Button
禁用英文默认大写
android:textAllCaps = “false”

1.3 EditText

  • 提示性内容
    android:hint = “xxxxxxxx”
  • 指定最大行数:
    android:maxLines = “2”
    超过两行时,文本就会向上滚动,而不会继续拉伸
  • 点击按钮时获取EditText中输入的内容
    findViewById()
    getText()
    toString()

1.4ImageView
android:src = “@drawable/img_1” 指定图片

imageView = (ImageView) findViewById*R.id.image_view);
imageView.setImageResource(R.drawble.img_2) 动态更改图片

1.5 ProgressBar 进度条
style = “?android:attr/progressBarStyleHorizontal” 设置样式为水平
还可以设置最大值,动态地改变进度

加载完毕进度条不可见
android:visibility-> visible invisible gone
方法:setVisibility(View.VISIBLE);

1.6 AlertDialog
弹出对话框。原来真正的alert在这里,但是显然更复杂。

case R.id.button:
	AlertDialog.Builder dialog = ew AlertDialog.Builder (MainActivity.this);
	dialog.setTitle("This is Dialog");
	dialog.setMessage("Something.");
	dialog.setPositiveButton("OK", new DialogInterface.			//设置确定按钮事件
		onClickListener(){
			@Override
			public void onClick(DialogInterface dialog,int which){
			});
	dialog.setNegativeButton("Cancel", new DialogInterface.			//设置取消按钮事件
		onClickListener(){
			@Override
			public void onClick(DialogInterface dialog,int which){
			});
	dialog.show();
	break;
default:
	break;

1.7 ProgressDialog
多一个进度条,表示当前操作比较耗时,请用户耐心等待。
如果在setCancelable()中传入false,表示不能通过Back键取消掉。

1.8 四种布局
先跳过,我应该会用约束布局比较多,前文给了几个参考文的链接。

1.9 ListView
完了,我也要用这个的。
我直接实战了,就不写在这里了。

好了,准备得差不多,我先去实战了。继续加油。

你可能感兴趣的:(从零开始开发安卓APP全记录)