版本选择

Android 开发 SDK一般选择用最新的SDK版本, 这是Google官方建议的, App能运行的Android版本不是由SDK决定的, 是由每一个项目的minSDK决定的. SDK都是向下兼容的, SDK在不断改进中, 新的SDK会提供更强大开发工具, 而且用4.0的SDK编译的2.1的apk的执行效率会比用2.1的SDK编译的更高.

至于每个app应该用什么 minSDK, 应该根据应用具体的API来, 如果app没有用到1.6以上SDK新提供的API, 那么用1.6会在提供相同体验下兼容更多机型.

最外层项目结构

android-BasicNetworking$ tree
.
├── app
├── build
├── build.gradle
├── gradle
│   └── wrapper
│   ├── gradle-wrapper.jar
│   └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── local.properties
├── packaging.yaml
└── settings.gradle

app: 实际开发的应用所在目录, gradle需要构建的子目录
build: 构建产生的文件存放目录
build.gradle: 放置全局的gradle构建配置, 这里只会指定少量配置
gradle: gradle wrapper目录
gradlew, gradlew.bat: gradle构建脚本
local.properties: 用于存放开发者本地的gradle路径信息. This file must *NOT* be checked into Version Control Systems, as it contains information specific to your local configuration. Location of the SDK. This is only used by Gradle.
packaging.yaml: 可以忽略
settings.gradle: 用于指示gradle 构建时应该包含哪个子目录, 本例中是 Application

内层项目结构

.

android-BasicNetworking$ tree
.
├── app
│   ├── build
│   ├── build.gradle
│   ├── src
│   │   └── main
│   │   ├── AndroidManifest.xml
│   │   ├── java
│   │   │   └── com
│   │   │   └── example
│   │   │   └── android
│   │   │   ├── basicnetworking
│   │   │   │   ├── MainActivity.java
│   │   │   │   └── SimpleTextFragment.java
│   │   │   └── common
│   │   │   └── logger
│   │   │   ├── LogFragment.java
│   │   │   ├── Log.java
│   │   │   ├── LogNode.java
│   │   │   ├── LogView.java
│   │   │   ├── LogWrapper.java
│   │   │   └── MessageOnlyLogFilter.java
│   │   └── res
│   │   ├── drawable-hdpi
│   │   │   ├── ic_launcher.png
│   │   │   └── tile.9.png
│   │   ├── drawable-mdpi
│   │   │   └── ic_launcher.png
│   │   ├── drawable-xhdpi
│   │   │   └── ic_launcher.png
│   │   ├── drawable-xxhdpi
│   │   │   └── ic_launcher.png
│   │   ├── layout
│   │   │   └── sample_main.xml
│   │   ├── menu
│   │   │   └── main.xml
│   │   ├── values
│   │   │   ├── base-strings.xml
│   │   │   ├── strings.xml
│   │   │   ├── styles.xml
│   │   │   ├── template-dimens.xml
│   │   │   └── template-styles.xml
│   │   ├── values-sw600dp
│   │   │   ├── template-dimens.xml
│   │   │   └── template-styles.xml
│   │   ├── values-v11
│   │   │   └── template-styles.xml
│   │   └── values-v21
│   │   ├── base-colors.xml
│   │   └── base-template-styles.xml
│   └── tests
│   ├── AndroidManifest.xml
│   └── src
│   └── com
│   └── example
│   └── android
│   └── basicnetworking
│   └── tests
│   └── SampleTests.java

build: 构建产生文件的目录
build.gradle: gradle的构建配置
src: 源文件, 其中
src.main.java
src.main.res.drawable-*: 针对不同分辨率的图片素材
src.main.res.layout: 布局文件
src.main.res.menu: 菜单配置
src.main.res.values*: string, style等文本
src.main.AndroidManifest.xml 应用的入口
tests: 测试文件

应用冷启动

冷启动是指app从0启动, 此时app进程还没有被系统进程创建. 如果系统刚启动或app进程被kill时的启动都是冷启动, 这种启动会花费最多的时间.
在冷启动期间, 系统会处理三件事:

  1. 载入并启动app.
  2. 在启动后立即显示空白的开始界面
  3. 创建app进程

一旦app进程已经创建, app进程就会负责下一阶段的启动, 其工作主要包含

  1. 创建app对象 Application.onCreate
  2. 启动main thread
  3. 创建main activity: Activity.init
  4. 填充view: Activity.onCreate
  5. 对屏幕进行布局
  6. 执行初始化绘制

当app进程完成第一次绘制后, 系统进程切换掉正在显示的后台窗口, 替换成main activity, 这时候用户就可以开始使用app了.

创建Application
当应用启动时, 空白启动界面会一直保持到系统完成第一次绘制. 这时候系统会切换到app窗口并允许用户开始与app交互. 如果你重载了Application.onCreate()方法, 系统将调用你的onCreate()方法, 然后生成main thread(即UI thread), 并让其创建main activity. 从这时开始, system- 和 app- 级别的进程将对应地处理app的生命周期.

创建Activity
在app创建activity时, 将处理以下任务:

  1. 初始化values
  2. 调用构造方法(constructors)
  3. 根据当前的生命周期状态调用各个回调方法, 例如Activity.onCreate()

一般情况下onCreate()方法对载入时间影响最大, 因为处理的事情比较多, 载入和填充视图, 填充activity运行需要的对象等.

应用热启动

热启动比冷启动要简单得多, 在热启动时, 系统需要做的就是把应用的activity放到前台. 如果应用的activities都还在内存里, 那么应用就不需要再重复对象初始化, layout inflation和rendering.
但是如果内存已经被trimming事件删除, 例如onTrimMemory(), 那么这些对象需要被重新创建. 热启动和冷启动在显示上是一样的: 系统先显示一个空白界面直到app完成第一次渲染.

应用暖启动

暖启动包含热启动中的一部分工作, 但是要少很多. 有很多状态都可以是暖启动, 例如:
用户离开app, 但是又重新打开了app. 那么app进程会继续运行, 但是app会通过调用onCreate()重新创建activity.
系统从内存中关闭了app, 然后用户又重新打开了app. 那么进程和activity都需要重新启动, 但是之前保存的状态信息可以帮助onCreate()的执行.

AndroidManifest, MainActivity 和 template-styles(Theme), layout

AndroidManifest.xml是整个应用的配置入口, 这里配置应用相关的信息:

  • permission:
  • users-permission:
  • application
    • android

      • name, allowBackup, icon, label, supportsRtl, theme
      • meta-data 多个
    • service  多个
    • receiver 多个
    • activity 多个

其中,
application.andorid:theme 可以通过template-styles.xml自定义, 实际一般使用 @style/Theme.AppCompat.Light.NoActionBar
application.activity: 每个activity都需要在这里注册, 而app启动时打开的activity, 需要增加 intent-filter.action:MAIN, intent-filter.category:DEFAULT和intent-filter.category:LAUNCHER, 因为启动界面的存在, 现在大多数app入口activity使用的是Splash作为MainActivity

MainActivity: 在onCreate时选择layout, layout中会根据对应的fragment对应的类调用其onCreate方法, 然后在MainActivity的onCreate中, 根据id拿到这些fragment, 对fragment里的元素进行操作.

layout: 这个layout是嵌入Theme中的主体部分的布局设计, 可以配置LinearLayout, RelativeLayout等, Layout里面可以再嵌入Layout, Button, TextView, ImageView等元素

界面元素异步刷新

1. 在Activity里声明一个BroadcastReceiver对象实现onReceive方法, 并将这个对象通过registerReceiver注册到系统中, 在onDestroy阶段通过unregisterReceiver解除接收
2. 在Activity或Fragment里集成Listener接口, 实现onXxxx方法, 通过view实例的set方法, 将自己set成view实例的变量, 在view的操作中, 通过调用这个变量的onXxxx方法实现刷新

启动图标及生成

启动图标配置入口在AndroidManifest.xml , 分两部分,一个是ic_launcher, 一个是ic_launcher_round, 分别代表正方形圆角图标和圆形图标

    <application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"

上面这两个配置,对应的配置文件为 /res/mipmap-anydpi-v26/ 目录下的 ic_launcher.xml 和 ic_launcher_round.xml,这两个文件的内容都是一样的。

在GIMP等作图软件上制作图标文件,图标分辨率建议在600以上,然后File->New->Image Asset, 在Source Asset下选择Asset Type为Image, 然后在Path中选择图标文件

在下面的Scaling中选择Trim: Yes, 设置Resize比例让图标完整显示, 然后Background Layer下, Source Asset的Asset Type选择Color, 用提色器选择颜色。

点击Next后,会提示哪些文件将被覆盖。

在安装到测试机上时,因为有缓存,可能图标显示不会更新,需要通过修改手机桌面设置等手段清理缓存查看实际变化。

Service的两种模式

模式1: Where you start and stop. This can be started and stopped only once in an application.

模式2: You Bind and Unbind as required N number of times. But just bind and unbind doesn't do the job. The service first needs to be started then only it can be bound and unbound. So on start of app or whereever appropriate, Start the service. Then Bind when required. When don with it, Unbind it. That Bind-Unbind circle can go on. And Finally when you are sure you don't need it or at the end of the app Stop the Service. So the flow comes as Start -> Bind -> Unbind -> Stop <-

通过bind的方式连接Service

1 定义一个类继承Service
 1.1 在里面创建一个内部类继承Binder, 里面只需要一个方法getInstance(), 用于返回这个service自己
 1.2 在里面创建一个成员变量类型为IBinder, 实例就是上面的内部类
 1.3 覆写onBind(Intent intent)方法, 返回上面这个成员变量
 以上这些步骤, 都是为了在Activity里bindService后, 能拿到这个service的实例并把各种系统资源和配置传过去

2 在manifest.xml文件中声明上面定义的service

3 在Activity里, 初始化一个成员变量serverConnection, 为 ServiceConnection类型的一个实例, 覆写它的两个方法
 3.1 覆写方法 onServiceConnected(ComponentName name, IBinder binder), 在里面从binder拿到service实例, 可以把service赋值到自己的成员变量里, 然后把context(自己), 资源和配置传进去,
 3.2 覆写方法 onServiceDisconnected(ComponentName name), 在里面将service设为null

4 在Activity的onStart()方法里连接service
 4.1 创建一个intent, 传进去的参数一个是this, 另一个是service的类名
 4.2 在调用 bindService()之前, 要用上面的intent 调用一次 startService.
 4.3 调用 bindService(serverIntent, serverConnection, BIND_AUTO_CREATE), 其中第一个参数就是刚才创建的intent, 第二个参数就是上一步初始化的成员变量
 调用完bindService后, 就已经将service创建好并执行其onBind()方法了

5 之后就可以在Activity里调用service里的各个方法

6 不再使用时,调用unbindService(ServiceConnection)方法停止该服务

使用这种bind方式启动的service的生命周期如下:
onCreate() -- > onBind() --> (ServiceConnection的onServiceConnected)-->onUnbind() -- > onDestory()

注意1: 绑定服务不会调用onStart()或者onStartCommand()方法
注意2: 绑定服务由哪个context绑定后,就只能由这个context进行解绑,否则会报java.lang.IllegalArgumentException: Service not registered异常。同理,没被绑定的service,调用解绑同样回报这个异常.
注意3: Service中需要创建一个实现IBinder的内部类(这个内部类不一定在Service中实现,但必须在Service中创建它). 然后在OnBind()的方法中需返回一个IBinder实例,不然onServiceConnected方法不会调用.
注意4: ServiceConnection 的回调方法onServiceDisconnected() 在连接正常关闭的情况下是不会被调用的, 该方法只在Service 被破坏了或者被杀死的时候调用. 例如, 系统资源不足, 要关闭一些Services, 刚好连接绑定的 Service 是被关闭者之一, 这个时候onServiceDisconnected() 就会被调用.

bindService特点:bind的方式开启服务,绑定服务后如果调用者挂了,服务也会跟着挂掉。绑定者可以调用服务里面的方法。

动画Animator

通过声明一个Animator来实现动画效果.

ValueAnimator的使用

在Activity中声明ValueAnimator变量

private ValueAnimator indicatorAnimator;

在onCreate中初始化, 这里的drawable是view里的一个自定义shape, 注意这个ArgbEvaluator, 如果是颜色渐变必须要选这个, 不然按数字渐变的话, 体现到颜色上实际是乱的.

indicatorAnimator = ValueAnimator.ofInt(
ContextCompat.getColor(this, R.color.colorLightGreen),
ContextCompat.getColor(this, R.color.colorGreen));
indicatorAnimator.setDuration(500);
indicatorAnimator.setEvaluator(new ArgbEvaluator());
indicatorAnimator.addUpdateListener((animation)-> {
int value = (int) animation.getAnimatedValue();
GradientDrawable drawable = (GradientDrawable)txtMainH01T03.getBackground();
drawable.setColor(value);
});

然后在对应的按钮动作或界面更新中使用

indicatorAnimator.start();
# or
indicatorAnimator.end();

ObjectAnimator的使用

同样的功能也可以通过ObjectAnimator实现, 在Activity中声明变量

private ObjectAnimator indicatorAnimator;

在onCreate中初始化, 和ValueAnimator不同之处在于, 不需要再设置UpdateListener了

indicatorAnimator = ObjectAnimator.ofInt((GradientDrawable)txtMainH01T03.getBackground(), "Color", Color.RED,Color.BLUE,Color.GRAY,Color.GREEN);
indicatorAnimator.setDuration(500);
indicatorAnimator.setEvaluator(new ArgbEvaluator());

然后在对应的按钮动作或界面更新中使用

indicatorAnimator.start();
# or
indicatorAnimator.end();

Animator的方法

animator对象的方法有

Animator.start() // start the animation from the beginning
Animator.end() // end the animation
Animator.cancel() // cancel the animation
Animator.pause() // added in API 19; pause the animation
Animator.resume() // added in API 19; resume a paused animation

start()会从开始状态启动动画, 如果有startDelay, 那么会在暂停对应时间后启动. 通过cancel() 和 end() 都可以停止动画, 区别在于cancel()会让动画停留在中间状态, 而end() 会让动画直接跳到最终状态.

异步处理Message的Handler

在安卓里不能通过子线程更新UI, 如果从UI线程以外更新, 会报ViewRootImpl$CalledFromWrongThreadException, 可以使用Handler处理.

Handler的形式很灵活, 可以作为Activity的成员变量, 然后赋值给Service及其他实例去调用, 也可以作为Service的成员变量, 由Activity去调用.

使用Activity的Handler更新UI

在MainActivity里创建Handler

# 声明变量
private MainActivityHandler handler;
...
# 在onCreate里初始化
handler = new MainActivityHandler(Looper.getMainLooper());
handler.setWeakReference(this); # 类定义
public static class MainActivityHandler extends Handler {
public static final int UPDATE_TEXT_01 = 0x01;
public static final int START_ANIMATOR = 0x02; private WeakReference<MainActivity> weakReference; public MainActivityHandler(@NonNull Looper looper) {
super(looper);
} public void setWeakReference(MainActivity activity) {
weakReference = new WeakReference<>(activity);
} @Override
public void handleMessage(@NonNull Message message) {
super.handleMessage(message);
MainActivity activity = weakReference.get();
switch (message.what) {
case UPDATE_TEXT_01:
TextView txtMain01 = activity.findViewById(R.id.main_text_01);
TextView txtMainH01T02 = activity.findViewById(R.id.main_h01_text_02);
GradientDrawable drawable = (GradientDrawable)txtMainH01T02.getBackground();
Button btnService = activity.findViewById(R.id.main_button_02);
if (message.arg1 == 0) {
txtMain01.setText("");
drawable.setColor(ContextCompat.getColor(activity, R.color.colorGray));
btnService.setText("Start Service");
} else {
txtMain01.setText(StringUtil.implode(activity.pocketService.getWebServerUrls(), "\n"));
drawable.setColor(ContextCompat.getColor(activity, R.color.colorGreen));
btnService.setText("Stop Service");
}
break;
case START_ANIMATOR: if (activity != null) {
activity.indicatorAnimator.start();
}
break;
default:
}
}
}

在Service里调用

msg.what = MainActivity.MainActivityHandler.UPDATE_TEXT_01;
msg.arg1 = 1;
handler.sendMessage(msg);

Android项目结构和文件间关联的更多相关文章

  1. Android Studio安卓学习笔记(二)Android项目结构

    上一篇代码,我们学习了Android的功能以及如何用Android Studio开发第一个安卓程序.下面就要介绍Android项目结构.为日后学习打基础. 一:Android项目结构 打开MyFris ...

  2. Android之什么是Activity和常用的ADB命令以及Android项目结构的认识

    总结一下之前学习Android的一些内容 一:  Android常用的ADB命令(adb android调试桥)      1.adb devices   查看模拟器设备并重新连接. 2.adb ki ...

  3. Android项目结构 以及体系结构

    学习Android平台的人一般对Android的平台的应该有点认识 其它的就不多讲了 Android项目一般由以下几个部分构成 以上是一个简单的Android项目结构目录图 1. src  主要是 源 ...

  4. 对Android项目中的文件夹进行解释

    对Android项目中的文件夹进行解释: · src:里面存放的是Activity程序,或者是以后的其他组件,在此文件夹之中建立类的时候一定要注意,包名称不能是一级. · gen:此文件夹中的内容是自 ...

  5. Vuejs+elementUI框架开发的项目结构及文件关系

    项目结构|----- build #webpack编译相关文件目录,一般不用动 |----- config #配置目录|         |------ dev.env.js #开发环境变量| |-- ...

  6. 读懂Android项目结构目录

    我们看到下图:当我们创建了第一Android项目的时候有没有被吓到.怎么这么多目录,好头晕啊!没事, 那我们今天就了解一下这些目录是做什么的: src: src 目录是放置我们所有 Java 代码的地 ...

  7. android XMl 解析神奇xstream 一: 解析android项目中 asset 文件夹 下的 aa.xml 文件

    简介 XStream 是一个开源项目,一套简单实用的类库,用于序列化对象与 XML 对象之间的相互转换. 将 XML 文件内容解析为一个对象或将一个对象序列化为 XML 文件. 1.下载工具 xstr ...

  8. eclipse下建立 android 项目,相关文件夹介绍

    今天开始进入ANDROID开发,之前一直做些JAVA的WEBSERVICE之类的文件,第一次从头开始整理ANDROID项目,我会把最近遇到的问题做一一梳理. 现在来说一下建立ANDROID项目后产生的 ...

  9. eclipse Android项目 DDMS db文件 导出 Failed to pull selection null 问题

    我在 eclipse的Android项目中,在 DDMS导出db文件 时,发现报错:Failed to pull selection null 在左侧选中设备,在进行导出 这样就可以正常的进行导出db ...

  10. Eclipse将android项目打包jar文件

    Eclipse+android打包jar文件 蔡建良 2016-3-12 以Android-SlideExpandableListView开源框架为例,将源码Library打包成jar文件并包含R.c ...

随机推荐

  1. JavaScript - input 上传图片 并展示 (食用简单)

    <!DOCTYPE html> <html lang="en">   <head>     <meta charset="UTF ...

  2. [转帖]全表扫描却产生大量db file sequential read一例

    老熊 Oracle性能优化 2012-05-23 开发人员在进行新系统上线前的数据校验测试时,发现一条手工执行的SQL执行了超过1小时还没有返回结果.SQL很简单: SELECT * FROM MOB ...

  3. [转帖]MySQL快速备份表

    https://www.cnblogs.com/JaxYoun/p/14264593.html 1.复制表结构及数据到新表 CREATE TABLE 新表 SELECT * FROM 旧表 这种方法会 ...

  4. [转帖]MYSQL--表分区、查看分区

    https://www.cnblogs.com/pejsidney/p/10074980.html 一.       mysql分区简介 数据库分区 数据库分区是一种物理数据库设计技术.虽然分区技术可 ...

  5. [转帖]【基础】HTTP、TCP/IP 协议的原理及应用

    https://juejin.cn/post/6844903938232156167 前言 本文将持续记录笔者在学习过程中掌握的一些 HTTP .TCP/IP 的原理,以及这些网络通信技术的一些应用场 ...

  6. [转帖]Nginx应用调优案例

    https://bbs.huaweicloud.com/blogs/146367 [摘要] 1 问题背景nginx的应用程序移植到TaiShan服务器上,发现业务吞吐量没有达到硬件预期,需要做相应调优 ...

  7. [转帖]深入内存/主存:解剖DRAM存储器

    https://zhuanlan.zhihu.com/p/561501585 2022/9/9更新:经过和评论区大佬的交流,准备研读一下JEDEC标准,主要是加深自己对banking和访存加速的理解( ...

  8. OpenEuler2203使用rpm方式安装Oracle19c的过程

    OpenEuler2203使用rpm方式安装Oracle19c的过程 安装介质 oracle-database-preinstall-19c-1.0-1.el7.x86_64.rpm oracle-d ...

  9. 飞腾2000+银河麒麟v10安装redis的注意事项

    先说一下结论 无法复用ubuntu上面编译的二进制文件 无法直接使用docker官网下面的arm64的镜像运行 无法直接使用redis6.0.10最新版本编译运行 可以使用redis5.0.4 进行编 ...

  10. Gorm 应用开发时区问题与unique唯一索引字段数据冲突问题

    目录 一.定义表模型时区问题 1.1 time.Time 与int64 1.2 优势 二.unique唯一索引字段数据冲突问题 一.定义表模型时区问题 1.1 time.Time 与int64 一般情 ...