第一行代码 Android (郭霖 著)

https://github.com/guolindev/booksource

 

第1章 开始启程----你的第一行Android代码 (已看)

第2章 先从看得到的入手----探究活动 (已看)

第3章 软件也要拼脸蛋----UI开发的点点滴滴

第4章 手机平板要兼顾----探究碎片

第5章 全局大喇叭----详解广播机制

第6章 数据存储全方案----详解持久化技术

第7章 跨程序共享数据----探究内容提供器

第8章 丰富你的程序----运用手机多媒体

第9章 看看精彩的世界----使用网络技术

第10章 后台默默的劳动者----探究服务

第11章 Android特色开发----基于位置的服务

第12章 最佳的UI体验----Material Design实战

第13章 继续进阶----你还应该掌握的高级技巧

第14章 进入实战----开发酷欧天气

第15章 最后一步----将应用发布到360应用商店

 

第1章 开始启程----你的第一行Android代码

谷歌终于在2008年推出了Android系统的第一个版本

  1.1 了解全貌----Andorid王国简介

    1.1.1 Android系统架构

  1. Linux内核层
  2. 系统运行库层
  3. 应用框架层
  4. 应用层

    1.1.2 Andorid已发布的版本

    1.1.3 Andorid应用开发特色

  1. 四大组件  活动(Activity), 服务(Service), 广播接收器(Broadcast Receiver), 内容提供器(ContentProvidedr)
  2. 丰富的系统控件
  3. SQLite数据库
  4. 强大的多媒体
  5. 地理位置定位

  1.2 手把手带你搭建开发环境

    1.2.1 准备所需要的工具

  • JDK
  • Android SDK
  • Android Studio

    1.2.2 搭建开发环境

https://developer.android.com/studio/index.html

  1.3 创建你的第一个Android项目

    1.3.1 创建Hello World项目

Minimum API Level: API 15:Android 4.0.3(IceCreamSandwich)

    1.3.2 启动模拟器

Nexus 5X API 24 Android 7.0 x86

    1.3.3 运行Hello World

    1.3.4 分析你的第一个Android程序

任何一个新建的项目都会默认使用Andorid模式的项目结构,但这并不是项目真实的目录结构,而是被Android Studio转换过的.

项目真实的目录结构,Project

1. .gradle和.idea

  这两个目录下放置的都是Android Studio自动生成的一些文件, 我们无须关心, 也不要去手动编辑

2. app

  项目中的代码, 资源等内容几乎都是放置在这个目录下的, 我们后面的开发工作也基本都是在这个目录下进行的,待会儿还会对这个目录单独展开进行详解

3. build

  这个目录你也不需要过多关心, 它主要包含了一些在编译时自动生成的文件

4. gradle

  这个目录下包含了gradle wrapper的配置文件,使用gradle wrapper的方式不需要提前将gradle下载好,而是会自动根据本地的缓存情况决定是否需要联网下载gradle.

5. .gitignore

  这个文件是用来将指定的目录或文件排除在版本控制之外的

6. build.gradle

  这是项目全局的gradle构建脚本,通常这个文件的内容是不需要修改的.

7. gradle.properties

  这个文件是全局的gradle配置文件,在这里配置的属性将会影响到项目中所有的gradle编译脚本

8. gradlew和gradlew.bat

  这两个文件是用来在命令行界面中执行gradle命令的,其中gradlew是在Linux或Mac系统中使用的,gradlew.bat是在Windows系统中使用的

9. HelloWorld.iml

  iml文件是所有IntelliJ IDEA项目都会自动生成的一个文件(Android Studio是基于IntelliJ IDEA开发的),用于标识这是一个IntelliJ IDEA项目,我们不需要修改这个文件中的任何内容

10. local.properties

  这个文件用于指定本机中的Android SDK路径, 通常内容都是自动生成的,我们并不需要修改.除非你本机中的Android SDK位置发生了变化, 那么就将这个文件中的路径改成新的位置即可

11. settings.gradle

  这个文件用于指定项目中所有引入的模块. 由于Hello World项目中就只有一个app模块,因此该文件中也就只引入了app这一个模块.通常情况下模块的引入都是自动完成的,需要我们手动去修改这个文件的场景可能比较少

app目录下的内容

1. build

  这个目录和外层的build目录类似, 主要也是包含了一些在编译时自动生成的文件,不过它里面的内容会更多更杂,我们不需要过多关心

2. libs

  如果你的项目中使用到了第三方jar包,就需要把这些jar包都放在libs目录下,放在这个目录下的jar包都会被自动添加到构建路径里去

3. androidTest

  此处是用来编写Android Test测试用例的,可以对项目进行一些自动化测试

4. java

  毫无疑问,java目录是放置我们所有的Java代码的地方, 展开该目录, 你将看到我们刚才创建的HelloWorldActivity文件就在里面

5. res

  这个目录下的内容就有点多了.简单点说, 就是你在项目中使用到的所有图片, 布局, 字符串等资源都要存放在这个目录下, 当然这个目录下还有很多子目录,图片放在drawable目录下,布局放在layout目录下, 字符串放在values目录下,所以你不用担心会把整个res目录弄得乱糟糟的

6. AndroidManifest.xml

  这是你整个Android项目的配置文件,你在程序中定义的所有四大组件都需要的这个文件里注册, 另外还可以在这个文件中给应用程序添加权限声明.由于这个文件以后会经常用到, 我们用到的时候再做详细说明

7. test

  此处是用来编写Unit Test测试用例的,是对项目进行自动化测试的另一种方式

8. .gitignore

  这个文件用于将app模块内的指定目录或文件排除在版本控制之外, 作用和外层的.gitignore文件类似

9. app.iml

  IntelliJ IDEA项目自动生成的文件,我们不需要关心或修改这个文件中的内容

10. build.gradle

  这是app模块的gradle构建脚本,这个文件中会指定很多项目构建相关的配置

11. proguard-rules.rpo

  这个文件用于指定项目代码的混淆规则,当代码开发完成后打成安装包文件,如果不希望代码被别人破解, 通常会将代码进行混淆,从而让破解者难以阅读

 

<activity android:name=".HelloWorldActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
AndoridManifest.xml
public class HelloWorldActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.hello_world_layout);
    }
}
HelloWorldActivity
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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=".HelloWorldActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text = "Hello World!"/>
</android.support.constraint.ConstraintLayout>
hello_world_layout.xml

    1.3.5 详解项目中的资源

所有以drawable开头的文件夹都是用来放图片的,所有以mipmap开头的文件都是用来放应用图标的,所有以values开头的文件夹都是用来放字符串,样式,颜色等配置的,layout文件夹是用来放布局文件的.

之所以有这么多mipmap开头的文件夹,主要是为了让程序能够更好地兼容各种设备. drawable文件夹也是相同的道理

<resources>
    <string name="app_name">HelloWorld</string>
</resources>
res/values/strings.xml
  • 在代码中通过R.string.hello_world可以获得该字符串的引用
  • 在xml中通过@string/hello_world可以获得该字符串的引用

    1.3.6 详解build.gradle文件

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        google()
        jcenter()
        
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.4.0'
        
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
build.gradle
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.voidgame.helloworld"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
app/build.gradle

  1.4 前行必备----掌握日志工具的使用

    1.4.1 使用Android的日志工具Log

  • Log.v().  用于打印那些最为琐碎的,意义最小的日志信息.对应级别verbose,是Android日志里面级别最低的一种
  • Log.d().  用于打印一些调试信息,这些信息对你调试程序和分析问题应该是有帮助的.对应级别debug,比verbose高一级
  • Log.i().  用于打印一些比较重要的数据,这些数据应该是你非常想看到的,可以帮你分析用户行为数据.对应级别info,比debug高一级
  • Log.w().  用于打印一些警告信息, 提示程序在这个地方可能会有潜在的风险,最好去修复一下这些出现警告的地方. 对应级别warn,比info高一级
  • Log.e().  用于打印程序中的错误信息,比如程序进入到了catch语句当中.当有错误信息打印出来的时候,一般都代表你的程序出现严重问题了,必须尽快修复. 对应级别error, 比warn高一级

    1.4.2 为什么使用Log而不使用System.out

  1.5 小结与点评

第2章 先从看得到的入手----探究活动

  2.1 活动是什么

活动(Activity)是最容易吸引用户的地方,它是一种可以包含用户界面的组件,主要用于和用户进行交互.一个应用程序可以包含零个或多个活动,但不包含任何活动的应用程序很少见,谁也不想让自己的应用永远无法被用户看到吧?

  2.2. 活动的基本用法

    2.2.1 手动创建活动

public class FirstActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}
View Code

    2.2.2 创建和加载布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button android:id="@+id/button_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button_1" />
</LinearLayout>


public class FirstActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.setContentView(R.layout.first_layout);
    }
}
View Code

    2.2.3 在AndroidManifest文件中注册

        <activity android:name=".FirstActivity" android:label="This is FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
View Code

    2.2.4 在活动中使用Toast

import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class FirstActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.setContentView(R.layout.first_layout);

        Button button1 = (Button)findViewById(R.id.button_1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(FirstActivity.this, "You clicked Button 1", Toast.LENGTH_SHORT).show();
            }
        });
    }
}
View Code

    2.2.5 在活动中使用Menu

import android.view.Menu;
import android.view.MenuItem;

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.add_item:
                Toast.makeText(this, "You clicked Add", Toast.LENGTH_SHORT).show();
                break;
            case R.id.remove_item:
                Toast.makeText(this, "You clicked Remove", Toast.LENGTH_SHORT).show();
                break;
            default:
                break;
        }
        return true;
    }
View Code

    2.2.6 销毁一个活动

        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
View Code

  2.3 使用Intent在活动之间穿梭

    2.3.1 使用显式Intent

Intent是Android程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据.Intent一般可用于启动活动,启动服务以及发送广播等场景

Intent大致可以分为两种: 显式Intent和隐式Intent

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

使用这种方式来启动活动,Intent的"意图"非常明显,因此我们称之为显示Intent

    2.3.2 使用隐式Intent

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


        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.activitytest.ACTION_START");
                intent.addCategory("com.example.activitytest.MY_CATEGORY");
                startActivity(intent);
            }
        });
View Code

    2.3.3 更多隐式Intent的用法

        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setData(Uri.parse("http://www.baidu.com"));
                startActivity(intent);
            }
        });
View Code
        <activity android:name=".ThirdActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="http" />
            </intent-filter>
        </activity>
View Code

    2.3.4 向下一个活动传递数据

        Button button1 = (Button)findViewById(R.id.button_1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String data = "Hello SecondActivity";
                Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                intent.putExtra("extra_data", data);
                startActivity(intent);
            }
        });


    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second_layout);

        Intent intent = getIntent();
        String data = intent.getStringExtra("extra_data");
        Log.d("SecondActivity", data);
    }
View Code

    2.3.5 返回数据给上一个活动

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

        Button button1 = (Button)findViewById(R.id.button_1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                startActivityForResult(intent, 1);
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case 1:
                if (resultCode == RESULT_OK) {
                    String returnedData = data.getStringExtra("data_return");
                    Log.d("FirstActivity", returnedData);
                }
                break;
            default:
                    break;
        }
    }


        Button button2 = (Button) findViewById(R.id.button_2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.putExtra("data_return", "Hello FirstActivity");
                setResult(RESULT_OK, intent);
                finish();
            }
        });
View Code

  2.4 活动的生命周期

    2.4.1 返回栈

    2.4.2 活动状态

每个活动在其生命周期中最多可能有4种状态

  1. 运行状态

当一个活动位于返回栈的栈顶时,这时活动就处于运行状态.系统最不愿意回收的就是处于运行状态的活动,因为这会带来非常差的用户体验

  2. 暂停状态

当一个活动不再处于栈顶状态,但仍然可见时,这时活动就进入了暂停状态.你可能会觉得既然活动已经不在栈顶了,还怎么会可见呢?这是因为并不是每一个活动都会占满整个屏幕的,比如对话框形式的活动只会占用屏幕中间的部分区域.处于暂停状态的活动仍然是完全存活着的,系统也不愿意去回收这种活动(因为它还是可见的,回收可见的东西都会在用户体验方面有不好的影响),只有在内存极低的情况下,系统才会考虑回收这种活动

  3. 停止状态

当一个活动不再处于栈顶位置,并且完全不可见的时候,就进入了停止状态.系统仍然会为这种活动保存相应的状态和成员变量,但是这并不是完全可靠的,当其他地方需要内存时,处于停止状态的活动有可能会被系统回收

  4. 销毁状态

当一个活动从返回栈中移除后就变成了销毁状态.系统会最倾向于回收处于这种状态的活动,从而保证手机的内存充足

    2.4.3 活动的生存期

 

 

    2.4.4 体验活动的生命周期

public class MainActivity extends AppCompatActivity {

    public static final String TAG = "MainActivity";

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

        Button startNormalActivity = (Button)findViewById(R.id.start_normal_activity);
        final Button startDialogActivity = (Button)findViewById(R.id.start_dialog_activity);

        startNormalActivity.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, NormalActivity.class);
                startActivity(intent);
            }
        });

        startDialogActivity.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, DialogActivity.class
                );
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "onStart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d(TAG, "onRestart");
    }
}
View Code

    2.4.5 活动被回收了怎么办

 

  2.5 活动的启动模式

 

    2.5.1 standard

 

    2.5.2 singleTop

 

    2.5.3 singleTask

 

    2.5.4 singleInstance

 

  2.6 活动的最佳实践

    2.6.1 知晓当前是在哪一个活动

Log.d("BaseActivity", getClass().getSimpleName());
View Code

    2.6.2 随时随地退出程序

public class ActivityCollector {
    public static List<Activity> activities = new ArrayList<>();

    public static void addActivity(Activity activity) {
        activities.add(activity);
    }

    public static void removeActivity(Activity activity) {
        activities.remove(activity);
    }

    public static void finishAll() {
        for (Activity activity: activities) {
            if (!activity.isFinishing()) {
                activity.finish();
            }
        }
    }
}

android.os.Process.killProcess(android.os.Process.myPid());
View Code

    2.6.3 启动活动的最佳写法

 

  2.7 小结与点评

 

第3章 软件也要拼脸蛋----UI开发的点点滴滴

  3.1 如何编写程序界面

  3.2 常用控件的使用方法

    3.2.1 TextView

    3.2.2 Button

    3.2.3 EditText

    3.2.4 ImageView

    3.2.5 ProgressBar

    3.2.6 AlertDialog

    3.2.7 ProgressDialog

  3.3 详解4中基本布局

    3.3.1 线性布局

    3.3.2 相对布局

    3.3.3 帧布局

    3.3.4 百分比布局

  3.4 系统控件不够用?创建自定义控件

    3.4.1 引入布局

    3.4.2 创建自定义控件

  3.5 最常用和最难用的控件----List View

    3.5.1 ListView的简单用法

    3.5.2 定制ListView的界面

    3.5.3 提升ListView的运行效率

    3.5.4 ListView的点击事件

  3.6 更强大的滚动控件----Recycler View

    3.6.1 RecyclerView的基本用法

    3.6.2 实现横向滚动和瀑布流布局

    3.6.3 RecyclerView的点击事件

  3.7 编写界面的最佳实践

    3.7.1 制作Nine-Patch图片

    3.7.2 编写精美的聊天界面

  3.8 小结与点评

第4章 手机平板要兼顾----探究碎片

  4.1 碎片是什么

  4.2 碎片的使用方式

    4.2.1 碎片的简单用法

    4.2.2 动态添加碎片

    4.2.3 在碎片中模拟返回栈

    4.2.4 碎片和活动之间进行通信

  4.3 碎片的生命周期

    4.3.1 碎片的状态和回调

    4.3.2 体验碎片的生命周期

  4.4 动态加载布局的技巧

    4.4.1 使用限定符

    4.4.2 使用最小宽度限定符

  4.5 碎片的最佳实践----一个简易版的新闻应用

  4.6 小结与点评

第5章 全局大喇叭----详解广播机制

  5.1 广播机制简介

  5.2 接收系统广播

    5.2.1 动态注册监听网络变化

    5.2.2 静态注册实现开机启动

  5.3 发送自定义广播

    5.3.1 发送标准广播

    5.3.2 发送有序广播

  5.4 使用系统广播

  5.5 广播的最佳实践----实现强制下线功能

  5.6 Git时间----初识版本控制工具

    5.6.1 安装Git

    5.6.2 创建代码仓库

    5.6.3 提交本地代码

  5.7 小结与点评

第6章 数据存储全方案----详解持久化技术

  6.1 持久化技术简介

  6.2 文件存储

    6.2.1 将数据存储到文件中

    6.2.2 从文件中读取数据

  6.3 SharedPreferences存储

    6.3.1 将数据存储到SharedPreferences中

    6.3.2 从SharedPreferences中读取数据

    6.3.3 实现记住密码功能

  6.4 SQLite数据库存储

    6.4.1 创建数据库

    6.4.2 升级数据库

    6.4.3 添加数据

    6.4.4 更新数据

    6.4.5 删除数据

    6.4.6 删除数据

    6.4.7 查询数据

  6.5 使用LitePal操作数据库

    6.5.1 LitePal简介

    6.5.2 配置LitePal

    6.5.3 创建和升级数据库

    6.5.4 使用LitePal添加数据

    6.5.5 使用LitePal更新数据

    6.5.6 使用LitePal删除数据

    6.5.7 使用LitePal查询数据

  6.6 小结与点评

第7章 跨程序共享数据----探究内容提供器

  7.1 内容提供器简介

  7.2 运行时权限

    7.2.1 Android权限机制详解

    7.2.2 在程序运行时申请权限

  7.3 访问其他程序中的数据

    7.3.1 ContentResolver的基本用法

    7.3.2 读取系统联系人

  7.4 创建自己的内容提供器

    7.4.1 创建内容提供器的步骤

    7.4.2 实现跨程序数据共享

  7.5 Git时间----版本控制工具进阶

    7.5.1 忽略文件

    7.5.2 查看修改内容

    7.5.3 撤销未提交的修改

    7.5.4 查看提交记录

  7.6 小结与点评

第8章 丰富你的程序----运用手机多媒体

  8.1 将程序运行到手机上

  8.2 使用通知

    8.2.1 通知的基本用法

    8.2.2 通知的进阶技巧

    8.2.3 通知的高级功能

  8.3 调用摄像头和相册

    8.3.1 调用摄像头拍照

    8.3.2 从相册中选择照片

  8.4 播放多媒体文件

    8.4.1 播放音频

    8.4.2 播放视频

  8.5 小结与点评

第9章 看看精彩的世界----使用网络技术

  9.1 WebView的用法

  9.2 使用HTTP协议访问网络

    9.2.1 使用HttpURLConnection

    9.2.2 使用OkHttp

  9.3 解析XML格式数据

    9.3.1 Pull解析方式

    9.3.2 SAX解析方式

  9.4 解析JSON格式数据

    9.4.1 使用JSONObject

    9.4.2 使用GSON

  9.5 网络编程的最佳实践

  9.6 小结与点评

第10章 后台默默的劳动者----探究服务

  10.1 服务是什么

  10.2 Android多线程编程

    10.2.1 线程的基本用法

    10.2.2 在子线程中更新UI

    10.2.3 解析异步消息处理机制

    10.2.4 使用AsyncTask

  10.3 服务的基本用法

    10.3.1 定义一个服务

    10.3.2 启动和停止服务

    10.3.3 活动和服务进行通信

  10.4 服务的生命周期

  10.5 服务的更多技巧

    10.5.1 使用前台服务

    10.5.2 使用IntentService

  10.6 服务的最佳实践----完整版的下载示例

  10.7 小结与点评

第11章 Android特色开发----基于位置的服务

  11.1 基于位置的服务简介

  11.2 申请API Key

  11.3 使用百度定位

    11.3.1 准备LBK SDK

    11.3.2 确定自己位置的经纬度

    11.3.3 选择定位模式

    11.3.4 看得懂的位置信息

  11.4 使用百度地图

    11.4.1 让地图显示出来

    11.4.2 移动到我的位置

    11.4.3 让"我"显示在地图上

  11.5 Git时间----版本控制工具的高级用法

    11.5.1 分支的用法

    11.5.2 与远程版本库协作

  11.6 小结与点评

第12章 最佳的UI体验----Material Design实战

  12.1 什么是Material Desgin

  12.2 Toolbar

  12.3 滑动菜单

    12.3.1 DrawerLayout

    12.3.2 NavigationView

  12.4 悬浮按钮和可交互提示

    12.4.1 FloatingActionButton

    12.4.3 Snackbar

    12.4.4 CoordinatorLayout

  12.5 卡片式布局

    12.5.1 CardView

    12.5.2 AppBarLayout

  12.6 下拉刷新

  12.7 可折叠式标题栏

    12.7.1 CollapsingToolbarLayout

    12.7.2 充分利用系统状态栏空间

  12.8 小结与点评

第13章 继续进阶----你还应该掌握的高级技巧

  13.1 全局获取Context的技巧

  13.2 使用Intent传递对象

    13.2.1 Serializable方式

    13.2.2 Parcelable方式

  13.3 定制自己的日志工具

  13.4 调试Android程序

  13.5 创建定时人物

    13.5.1 Alarm机制

    13.5.2 Doze模式

  13.6 多窗口模式编程

    13.6.1 进入多窗口模式

    13.6.2 多窗口模式下的生命周期

    13.6.3 禁用多窗口模式

  13.7 Lambda表达式

  13.8 总结

第14章 进入实战----开发酷欧天气

  14.1 功能需求及技术可行性分析

  14.2 Git时间----将代码托管到GitHub上

  14.3 创建数据库和表

  14.4 遍历全国省市县数据

  14.5 显示天气信息

    14.5.1 定义GSON实体类

    14.5.2 编写天气界面

    14.5.3 将天气显示到界面上

    14.5.4 获取必应每日一图

  14.6 手动更新天气和切换城市

    14.6.1 手动更新天气

    14.6.2 切换城市

  14.7 后台自动更新天气

  14.8 修改图标和名称

  14.9 你还可以做的事情

第15章 最后一步----将应用发布到360应用商店

  15.1 生成正式签名的APK文件

    15.1.1 使用Android Studio生成

    15.1.2 使用Gradle生成

    15.1.3 生成多渠道APK文件

  15.2 申请360开发者账号

  15.3 发布应程序

  15.4 嵌入广告进行盈利

    15.4.1 注册腾讯广告联盟账号

    15.4.2 新建媒体和广告位

    15.4.3 接入广告SDK

    15.4.4 重新发布应用程序

  15.5 结束语

转载于:https://www.cnblogs.com/revoid/p/10929061.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值