第一行代码学习笔记

第一行代码学习笔记

第1章

1.1、Android系统架构

image-20220221181535953

​ Linux内核:Android平台的基础是Linux内核,通过Linux内核来执行一些基本操作,如进程管理,进程调度等

​ HAL(硬件抽象层):提供标准界面,向更高层显示设备硬件功能

​ Native Library(系统运行库):通过一些C/C++库来为Android系统提供特性支持,如Webkit库提供浏览器内核

​ Framework(应用框架层):为应用开发提供API,开发者可以使用这些API搭建自己的软件

​ Application(应用层):用户直接接触使用的,所有安装在手机上的应用程序都属于这一层。

1.2、版本信息

​ 常见版本信息:

​ Android 7.0 对应 API 24

​ Android 10 对应 API 29

1.3、开发工具搭建

​ 1.安装JDK,配置java环境变量

​ 2.下载并安装AndroidStudio安装包

1.4、项目结构简介

image-20220221181554122

  1. .gradle和.idea:存放AS自动生成的文件

  2. app:存放项目的资源和代码文件

    1)build:系统自动生成的文件

    2)libs:引用的第三方jar包

    3)androidTest:编写测试用例,自动化测试

    4)java:存放java代码

    5)res:存放资源文件,布局,图片

    6)AndroidManifest.xml:整个Android项目的配置文件

    7)test:编写Unit Test样例,自动化测试

    8).gitignore:app模块版本控制

    9)build.gradle:app模块gradle构造脚本

    10)proguard-rulers.pro:代码混淆规则

  3. gradle:存放gradle配置文件

  4. .gitignore:版本控制

  5. build.gradle:项目全局的gradle构造脚本

  6. gradle.properties:全局的gradle配置文件

  7. gradlew和gradlew.bat:在命令行执行gradle命令,.bat实在win中使用

  8. local.properties:本机中AndroidSDK路径

  9. settings.gradle:指定项目中引用的模块

1.5、build.gradle文件

image-20220221181602550

6、日志工具类Log

Log.v(TAG,"消息");--->打印琐碎消息,级别最低

Log.d(TAG,"消息");--->打印调试消息,

Log.i(TAG,"消息");--->打印比较重要的消息或数据

Log.w(TAG,"消息");--->打印警告信息

Log.e(TAG,"消息");--->打印错误信息

第2章-Activity

2.1、创建和注册

1.右键创建选择Activity,

2.创建class的方式需要在AndroidManifest文件中注册,直接创建activity则不需要

​ 在AndroidManifest文件中注册Activity

​ 只需要中添加字段

image-20220221181612406

2.2、Activity生命周期

image-20220221181622598

1.Activity A打开Activity B 生命周期变化情况

A : onPause()

B : onCretae() -> onStart() -> onResume()

2.3、Intent

  • 显示Intent:
Intent intent = new Intent(this, NextActivity.class);
startActivity(intent);
  • 隐式Intent:通过给Intent指定一系列的参数 ,来让系统分析应该执行什么动作
//启动可以相应”com.example.activity.ACTION_START“ 这个动作的Activity
Intent intent = new Intent("com.example.activity.ACTION_START");
startActivity(intent);

//打开网页
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.baidu.com"));
startActivity(intent);

//打电话
Intent intent1 = new Intent(Intent.ACTION_DIAL);
intent1.setData(Uri.parse("tel:10086"));
startActivity(intent1);



  • 内部路由
//发送方
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("myapplication://app:8080/main?from=11,id=22"));
startActivity(intent);
//接收方 注册
<activity android:name=".MainActivity"
    android:launchMode="singleTop">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <data
            android:scheme="myapplication"
            android:host="app"
            android:port="8080"
            android:path="/main"
            />
    </intent-filter>
</activity>
//接收方处理数据
getIntent().getData().getQueryParameter("from");
getIntent().getData().getQueryParameter("id");
  • Intent 传递数据:
//向下一个Activity传递数据 
//传递方
Intent intent = new Intent(MainActivity.this,ActivityDemo.class);
intent.putExtra("data","传递数据");
startActivity(intent);

//接收方
Intent intent = getIntent();
//从intent中取出对应类型的数据
String data = intent.getStringExtra("data");

2.4、活动启动模式

​ standard:标准模式,默认,每次启动活动 都会创建一个新的压入栈

​ singleTop:如果栈顶已经是当前活动,则直接使用,否则创建新的再压栈

​ singleTask:如果栈中存在当前活动,则让该活动之前的活动全部出栈,如果不存在,则创建新的然后压栈

​ singleInstance:启动一个新的栈来管理这个活动,这类活动通常为共享活动

2.5、程序退出时清除全部活动

创建一个ActivityController类,实现对全部Activity 的控制

public class ActivityController {
    private 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();
            }
        }
        activities.clear();
    }
}

同时为方便管理,给所有活动创建一个父类

public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("BaseActivity", getClass().getSimpleName());
        ActivityController.addActivity(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityController.removeActivity(this);
    }
}

2.6、onNewIntent()

当Activity 的 launchMode= "singleTask" 时,在复用 Activity 时会调用onNewIntent()

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);
    Log.i(TAG, "onNewIntent: ");
}

第3章-UI

3.1、约束布局

<androidx.constraintlayout.widget.Group
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	app:constraint_referenced_ids="am_btn_click,am_tv_showtext,mainbt_douban"/>


3.2、RecycleView

//获取每条Item的 type 
// 可以根据type来显示不同的布局
@Override
public int getItemViewType(int position) {
	return super.getItemViewType(position);
}

3.3、自定义布局

3.4、Niew-Patch 图片

.9 图片可自定义拉伸区域

  • 制作

    选中需要制作的图片,右键菜单中选择 Create 9-Patch File,随后会生成一个与原文件名相似的以 .9.png 结尾的文件

    image-20220222132416909

    打开 .9.png 文件,会呈现如下图的所示的样式,左侧是需要拉伸的图片,右侧为预览图。

    左边和上边表示可拉伸区域;下边和右侧表示内容填充区域

    image-20220222132912854

第4章-Fragment

4.1、简介 和生命周期介绍

**Fragment **碎片,可以同时满足手机和平板对界面需求,是一种可以嵌套在Activity中的UI片段,“迷你型的活动”

Fragment 同样拥有自己的生命周期,但是受制于他的宿主Activity的生命周期状态,例如:当 Activity 处于 paused 生命周期时,它所包含的所有 Fragment 也将处于 paused,当 Activity 被销毁时,所有 Fragment 也暂停.

Fragment 可以从startActivityForResult 中接收到返回结果

image-20220222133852284 image-20220222133809998

4.2、向Activity中添加Fragment

要创建 Fragment,您必须创建 Fragment 的子类(或其现有子类),随后重写onCreateView() 方法

public class DetailFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, 
    	@Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_detail, container, false);
        return view;

    }
}

方法一:直接在Activity的布局文件中声明

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/fragment_content"
    tools:context=".activity.FragmentTestActivity">
    <fragment
        android:id="@+id/fragment_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="com.example.myapplication.fragment.ListFragment"
        tools:layout="@layout/fragment_list" />

</FrameLayout>

方法二:在代码中动态添加

FramentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.fragment_content, fragment);//原来的资源id, 要添加的fragment
transaction.commitAllowingStateLoss();

4.3、Fragment适配

  • 1.布局加载

    由于平板和手机的屏幕大小有十分明显的差距,所以同一种布局在手机上很协调,但在平板上被拉长后会很别扭,这就需要我们对应用在平板上的布局进行重写。

    Android 能根据屏幕大小自动对布局进行适配,当屏幕小于某阈值时候使用一种布局,大于时候匹配另一种布局。

    Android提供了限定符(Qualifer),可以根据屏幕宽高dp(Density-independent pixel)大小来适配,也可以根据屏幕的大小(Screen size)来适配。

    常用的适配符如下

屏幕特征 限定符 描述
大小 small 小屏幕
normal 中等屏幕
large 大屏幕(平板至少为large)
xlarge 超大屏幕
分辨率 ldpi 低分辨率(<120dpi)
mdpi 中等分辨率(120dpi-160dpi)
hdpi 高分辨率(160dpi-240dpi)
xhdpi 超高分辨率(240dpi-320dpi)
xxhdpi 超超高分辨率(320dpi-480dpi)
方向 land 横屏
port 竖屏

在res目录下 新建layout-large 字典

将平板的布局写在里面,随后Android 会根据屏幕大小自动装载

第5章-广播

什么是广播,上学时教导处的大喇叭通知全年级某些消息,这就是广播。同样在Android中也存在这样的信息通信机制--广播。

它可以对整个应用内的所有活动进行广播和接收,也可对来自应用外的广播进行处理。

广播分为:标准广播和有序广播。标准广播也称为无序广播,它是一种异步执行的广播,广播发出后,所有接收者可以在同一时间收到这条广播,效率很高,但是这类广播无法被截断。

有序广播:是一种同步执行的广播,同一时刻只有一个接收者能处理这条广播,处理完之后广播才可继续传递,接受顺序要看接收器定义时候的优先级,

5.1、接收系统广播

动态注册:

private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_broadcast);
    //创建过滤器
    intentFilter = new IntentFilter();
    intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
    //注册接收器
    networkChangeReceiver = new NetworkChangeReceiver();
    registerReceiver(networkChangeReceiver, intentFilter);
}

private class NetworkChangeReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //获取系统服务
        ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = connectivityManager.getActiveNetworkInfo();
        if (info != null && info.isAvailable()){
            Toast.makeText(context,"网络可用",Toast.LENGTH_SHORT).show();
        }else{
            Toast.makeText(context,"当前网络不可用",Toast.LENGTH_SHORT).show();
        }	
	}
}

/**
* 动态注册一定要取消注册
*/
@Override
protected void onDestroy() {
    super.onDestroy();
    unregisterReceiver(networkChangeReceiver);
}

静态注册:

新建一个类继承BroadcastReceiver

随后在AndroidManifest文件中生命该接收器,并对过滤规则进行设置

private class NetworkChangeReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //获取系统服务
        ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = connectivityManager.getActiveNetworkInfo();
        if (info != null && info.isAvailable()){
            Toast.makeText(context,"网络可用",Toast.LENGTH_SHORT).show();
        }else{
            Toast.makeText(context,"当前网络不可用",Toast.LENGTH_SHORT).show();
        }	
	}
   
}

<receiver 
    android:name=".activity.DynamicRegisterBroadcast"
    android:enabled="true"
    android:exported="true">
    <intent-filter >
         <action android:name="android.intent.action.BOOT_COMPLETED"/>
    </intent-filter>
</receiver>

5.2、接收自定义广播

步骤:1)发起广播

​ 2)接收广播:

​ 静态注册:创建一个类继承BroadcastReceiver--》在AndroidManifest文件中注册该接收器,并设置过滤规则

​ 动态注册:创建一个类继承BroadcastReceiver--》注册过滤器,注册接收者

//发送端
Intent intent = new Intent("com.example.xxx.xxx");
sendBroadcast(intent);
//接收端
//静态注册
<receiver 
    android:name=".activity.DynamicRegisterBroadcast"
    android:enabled="true"
    android:exported="true">
    <intent-filter >
         <action android:name="com.example.xxx.xxx"/>
    </intent-filter>
</receiver>
//动态注册
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.xxx.xxx");
registerReceiver(mPushBroadcastReceiver, intentFilter);

5.3、本地广播

本地广播只能动态注册接收,无法通过静态注册接收

//本地广播和普通广播的实现方式没有什么区别
//不过一个是直接调用,另一个需要通过LocalBroadcastManager来调用
LocalBroadcastManager loaclBroadcastManager = LocalBroadcastManager.getInstance(this);
Intent intent = new Intent("xxx.xxx.xxx");
localBroadcastManager.sendBroadcast(intent);

//注册接收器时候同样
//创建过滤器
intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
//注册接收器
networkChangeReceiver = new NetworkChangeReceiver();
localBroadcastManager.registerReceiver(networkChangeReceiver, intentFilter);

第6章-存储

6.1、File

Android文件的读写流和Java相同,但是不同的是Android使用Context提供的openFileOutput()、openFileInput()打开文件

public FileOutputStream openFileOutput(String name, int mode)
public FileOutputStream openFileOInput(String name, int mode)

第一个参数是文件名(注意文件名不可以包含路径),第二个参数是打开模式:常见模式有两种MODE_PRIVATE(0),MODE_APPEND(32768),MODE_PRIVATE会将文件中原有内容覆盖掉,MODE_APPEND则是在文件末尾追加。

其余对文件的读写操作与Java一致

FileOutputStream fileOutputStream = null;
BufferedWriter bufferedWriter = null;
try {
    fileOutputStream = openFileOutput(fileName, mode);
    Log.d(TAG, "onClick: "+mode);
    bufferedWriter = new BufferedWriter(new OutputStreamWriter(fileOutputStream));
    //获取写入内容
    String fileinput = file_input.getText().toString();
    bufferedWriter.write(fileinput);
    bufferedWriter.flush();
    Toast.makeText(this,"写入成功",Toast.LENGTH_SHORT).show();

} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}finally {
    try {
        if (fileOutputStream != null){
            fileOutputStream.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        if (bufferedWriter != null){
            bufferedWriter.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

常见文件目录结构

($rootDir)
+- /data 			-> Environment.getDataDirectory()
| |
| | ($appDataDir)
| +- data/com.myapp
| 	|
| 	| ($filesDir)
| 	+- files 		 -> Context.getFilesDir() /Context.getFileStreamPath("")
| 	|		|
| 	| 		+- file1 -> Context.getFileStreamPath("file1")
| 	| ($cacheDir)
| 	+- cache 		 -> Context.getCacheDir()
| 	|
| 	+- app_$name 	 -> Context.getDir(String name, int mode)
|
| ($rootDir)
+- /storage/sdcard0  -> Environment.getExternalStorageDirectory()
	| 					/ Environment.getExternalStoragePublicDirectory("")
	|
	+- dir1 		 -> Environment.getExternalStoragePublicDirectory("dir1")
	|
	| ($appDataDir)
	+- Andorid/data/com.myapp
		|
		| ($filesDir)
		+- files 	 -> Context.getExternalFilesDir("")
		| |
		| +- file1   -> Context.getExternalFilesDir("file1")
		| +- Music   -> Context.getExternalFilesDir(Environment.Music);
		| +- Picture -> ... Environment.Picture
		| +- ...
		|
		| ($cacheDir)
		+- cache	 -> Context.getExternalCacheDir()
		|
		+- ???

/data/{packagename} 和外部存储目录 /storage/sdcard0/Android/data/{packagename} 下存储的数据在 apk 卸载后会被系统删除,我们应将应用的数据放于这两个目录中。

6.2、SharedPreferences

  • 1.获取SharedPreferences 对象的方式

    1)Context类的 getSharedPreferences() 方法
    public SharedPreferences getSharedPreferences(String name, int mode)
    name:文件名
    mode:模式目前只有MODE_PRIVATE能用

2)Activity类的getPreferences()方法
public SharedPreferences getPreferences(int mode)
文件名默认为当前活动的类名
3)PreferenceManager类中的getDefaultSharedPreferences()方法
public static SharedPreferences getDefaultSharedPreferences(Context context)
文件名默认文当前应用包名
  • 2.可以从SharedPreferences中获取和存储数据

1)存储数据
//通过调用 SharedPreferences 对象的.edit()方法 获取 SharedPreferences.Editor 对象
//调用 Editor 对象的putString()、putInt()等方法添加数据
//调用 Editor 对象的apply方法将数据提交
SharedPreferences preferernces = getSharedPreferences("config", MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("peizhi1", peizhi1.getText().toString());
editor.putString("peizhi2", peizhi2.getText().toString());
editor.apply();
2)获取数据
SharedPreferences preferernces = getSharedPreferences("config", MODE_PRIVATE);
String peizhi1 = preferences.getString("peizhi1","默认值");

6.3、SQLite

SQLite是Android内置的一款轻量级的关系数据库,它不仅能支持标准SQL语句,还遵循数据库ACID事务,能帮助我们快速的完成对数据的持久化存储。

Android为我们提供了一个专门用于管理SQL数据库的抽象类 SQLiteOpenHelper ,SQLiteOpenHelper 中有两个抽象方法 onCreate()、 onUpgrade(),这两个方法分别用于数据库的创建和升级逻辑。

SQLiteOpenHelper 中还有两个非常重要的 实例方法: getReadableDatabase() 和 getWritableDatabase() 用于打开和创建数据库,并返回一个可以对数据库进行读写的对象。

public SQLiteOpenHelper(@Nullable Context context, @Nullable String name, @Nullable CursorFactory factory, int version)
//Context context 上下文对象
//String name 数据库名称
//CursorFactory factory 查询数据时返回的自定义Cursor对象,一般为null 采用默认Cursor
//int version 版本号
  • 3.1.数据库的创建

    1)定义好建表语句

    2)重写 onCreate 方法,并执行建表语句

//建表语句
private static final String CREATE_TABLE_USER = "create table user(" +
        "id integer primary key autoincrement," +
        "name text not null," +
        "age integer)";
//在重写的onCreate 方法中 执行SQL语句
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
	sqLiteDatabase.execSQL(CREATE_TABLE_USER);
}
//创建对象
DBHelper dbHelper = new DBHelper(getActivity(),"SqliteTest.db", null, 1);
  • 3.2.数据库中添加或删除表

    1)添加新表

//建表语句
private static final String CREATE_TABLE_USER = "create table user(" +
        "id integer primary key autoincrement," +
        "name text not null," +
        "age integer)";
//新的建表语句
private static final String CREATE_TABLE_NEW = "create table new(" +
        "id integer primary key autoincrement," +
        "name text not null," +
        "age integer)";        
//在重写的onCreate 方法中 执行SQL语句 并将创建新表的语句一起执行
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
	sqLiteDatabase.execSQL(CREATE_TABLE_USER);
	sqLiteDatabase.execSQL(CREATE_TABLE_NEW);
}
//重写 onUpgrade 方法中删除已存在的表并且重新执行 onCreate() 方法
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
	sqLiteDatabase.execSQL("drop table if exists user");
	sqLiteDatabase.execSQL("drop table if exists new");
	onCreate(sqLiteDatabase);
}
//在新建对象时候 将版本号加1
DBHelper dbHelper = new DBHelper(getActivity(),"SqliteTest.db", null, 2);
2)删除表
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
	sqLiteDatabase.execSQL("drop table if exists user");
	sqLiteDatabase.execSQL("drop table if exists new");
}
DBHelper dbHelper = new DBHelper(getActivity(),"SqliteTest.db", null, 3);
  • 3.3.增删改查

//增
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", name);
values.put("age", age);
db.insert("user",null ,values);
//删
db.delete("user", null, null);
//改
ContentValues values = new ContentValues();
values.put("name","小明");
db.execSQL("update user set name = ? where name like ?",new String[]{"小明","xiaoming_"});
//查
Cursor cursor = db.query("user", null, null, null, null, null, null);
StringBuilder builder = new StringBuilder();
if (cursor.moveToFirst()){
    do {
       //对查询到元素进行操作
    }while (cursor.moveToNext());
}
cursor.close();
  • 3.4.使用SQLite执行SQL语句

DBHelper dbHelper = new DBHelper(getActivity(),"SqliteTest.db", null, 3);
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.execSQL("SQL语句")

6.4、常用SQL语法

  • CREATE DATABASE

CREATE DATABASE 用来创建一个新的数据库,它的用法如下:

CREATE DATABASE database_name;
  • INSERT INTO

INSERT INTO 命令向数据库中插入新的数据,它的用法如下:

INSERT INTO table_name( column1, column2....columnN)
VALUES ( value1, value2....valueN);
  • SELECT

用于从数据库中查询(选取)数据,它的用法如下:

SELECT column1, column2....columnN
FROM  table_name;
  • UPDATE

用于更新数据库中的数据,它的用法如下:

UPDATE table_name
SET column1 = value1, column2 = value2....columnN=valueN
[ WHERE CONDITION ];
  • DELETE

用于从数据库中删除数据,它的用法如下:

DELETE FROM table_name
WHERE {CONDITION};
  • CREATE TABLE

用于创建一个新的数据表,它的用法如下:

CREATE TABLE table_name(
column1 datatype,
column2 datatype,
column3 datatype,
.....
columnN datatype,
PRIMARY KEY( one or more columns )
);
  • ALTER TABLE

用于修改数据表。ALTER TABLE 可以用来修改数据表的字段,例如:

ALTER TABLE table_name {ADD|DROP|MODIFY} column_name {data_ype};

也可以用来修改数据表的名称,例如:

ALTER TABLE table_name RENAME TO new_table_name;
  • DROP TABLE

DROP TABLE 命令用来删除数据表,它的用法如下:

DROP TABLE table_name;
  • SQL索引

用于提高数据表的查询速度。一个表可以创建多个索引,一个索引可以包含一个或者多个字段

使用索引时应该遵循以下几条原则:

  • 仅在被频繁检索的字段上创建索引。
  • 针对大数据量的表创建索引,而不是针对只有少量数据的表创建索引。
  • 通常来说,经常查询的记录数目少于表中总记录数据的 15% 时,可以创建索引。这个比例并不绝对,它与全表扫描速度成反比。
  • 尽量不要在有大量重复值得字段上建立索引,比如性别字段、季度字段等。
//创建索引
CREATE INDEX index_name
ON table_name ( column1, column2.....);
//删除索引
ALTER TABLE table_name
DROP INDEX index_name;
  • SQL事务

事务具有四个标准属性,分别是原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability),简称 ACID

  • 原子性

一个事务中的所有 SQL 语句,要么全部执行成功,要么全部执行失败,不会结束在中间的某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

  • 一致性

在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的数据必须完全符合所有的预设规则,其中包含数据的精确度、串联性以及后续数据库可以自发性地完成预定的工作。

  • 隔离性

数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。

  • 持久性

事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

第8章-通知

8.1、通知

Notification :
	创建: 
		1.先通过 getSystemService(NOTIFICATION_SERVICE) 获取 NotificationManager 对象
			NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
		2.创建 Notification 对象, 
			Notification notification = new NotificationCompact.Builder(Context, "优先级")
				.setContentTitle()//设置标题
				.setContentText()//设置内容
				.setSmallIcon()//设置小图标
				.setLargeIon()//设置大图标
				.setWhen()//设置显示时间
				.setAutoCancle()//点击后自动关闭
				.setContentIntent()//点击跳转事件
				.setSound()//设置音频 uri
				.setVibrate()//设置震动时长 长整型数组new Long[]{0, 1000, 1000, 1000} || 静止0秒,震动1s,静止1s,震动1s
				.setLights(Color.GREEN, 1000, 1000)//设置提示灯的颜色闪烁间隔 || 绿光 亮起1s 熄灭1s
				.setDefault(NotificationCompact.DEFAULT_ALL)//以上设置全部使用Notification的默认设置
				.build();
			manager.notify(id, notification);
		3.关闭
			manager.cancle(id);
	特色:
		Notification notification = new NotificationCompact.Builder(Context, "优先级")
			.setStyle()
			/*
				设置大段文字
				.setStyle(new NotificationCompact.BigTextStyle().bigText("这是一个很长的句子"))
				设置图片
				.setStyle(new NotificationCompact.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(getResources(), 图片id)))
				
			*/
			.setPriority()//设置通知重要程度
			/*
				NotificationCompact.PRIORITY_MAX  //最重要
				NotificationCompact.PRIORITY_HIGH  //较高
				NotificationCompact.PRIORITY_LOW  //较低
				NotificationCompact.PRIORITY_MIN  //最不重要
				NotificationCompact.PRIORITY_DEFAULLT  //默认和不设置一样
			*/


8.2、拍照及获取相册中图片

调用相机拍照:
	1.首先我们需要一个地方来暂存拍到的图片
		File imagefile = new File(getExternalCacheDir(),"文件名.类型");
		//判断下该文件是否已经存在
		if(imagefile.exists()){
			//存在就删除
			imagefile.delete();
		}
		//不存在就新建一个
		imagefile.createNewFile();
	2.将文件路径转换为对应的URI
		//如果当前系统版本在Android 7.0以上 则需要通过内容提供器来找到文件位置 并将其转换为URI
		if(Build.VERSION.SDK_INT >= 24){
			imageUri = FileProvider.getUriForFile(上下文对象, fileprovider注册名, 文件路径imagefile);
		}else{
		//7.0 以下可以直接转换
			imageUri = Uri.fromFile(imagefile);
		}
		(1)注册fileprovider 
			在Manifes 文件中 添加一个<provider> 标签
			 <provider
				android:name="androidx.core.content.FileProvider"
				android:authorities="com.example.myapplication.fileprovider"
				android:grantUriPermissions="true"
				android:exported="false">
				<meta-data 
					android:name="android.support.FILE_PROVIDER_PATHS"
					android:resource="@xml/filepaths"
					/>
			</provider>
		(2)创建res/xml/filepaths.xml 文件
			<paths xmlns:android="http://schemas.android.com/apk/res/android">
			<external-path name="my_image" path="" />
			</paths>
	3.打开相机
		Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
		intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
		startActivityForResult(intent, 标识);
	4.处理返回数据 在 onActivityResult() 对返回的数据进行处理
		//转化为 Bitmap 类型
		Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openFileStream(imageUri));

从相册中选择图片:
	1.申请获取临时读写的权限
		//先检查以前有没有授权
		ContextCompat.checkSelfPermission(上下文 , Manifest.permission.WRITE_EXTERNAL_STORAGE)
		//没有就去申请权限
		ActivityCompat.requestPermissions(上下文 , new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 标识);
		//有过就直接打开相册
	2.打开相册
		Intent intent = new Intent("android.intent.action.GET_CONTENT");
		//选择的是图片
		intent.setType("image/*");
		startActivityForResult(intent, 标识);
	3.处理返回数据 在 onActivityResult() 对返回的数据进行处理
		Uri uri = data.getData();
		String imagePath = null;
        Cursor query = getContentResolver().query(uri, null, selection, null, null);
        if (query != null) {
            while (query.moveToNext()) {
				//文件路径
                imagePath = query.getString(query.getColumnIndex(MediaStore.Images.Media.DATA));
            }
            query.close();
        }
		

		

8.3、播放音视频

播放音视频文件:
	1.申请获取临时读写的权限 (同上)
	2.初始化MediaPlayer
		MediaPlayer media = new MediaPlayer();
		File file = new File(文件路径, 文件名);
		media.setDataSource(file.getPath());
		media.prepare();
	3.改变播放状态
		start() //开始播放
		pause() //暂停
		reset() //重置
		seekTo() //从指定位置开始播放
		stop() //停止 此后不可播放
		release() //释放
		isPlaying() //正在播放?
		getDuration() //获取音频总的时长
	4.播放视频文件 和播放音频文件类似 Videoview
		就是初始化部分有所不同
		视频直接 videoview.setVideoPath(file.getPath());
	5.不管是播放视频还是音频都需要在最后退出的时候释放资源
		重写onDestory(){
			if (mediaPlayer != null){
				mediaPlayer.stop();
				mediaPlayer.release();
			}
			if (videoView != null){
				videoView.suspend();
			}
		}

第9章-网络

9.1、Http与OkHttp

通过HTTP协议访问网络
	1.通过HttpURLConnection:
		new Thread(new Runnable(){
			@Override
            public void run() {
				URL url = new URL("http://www.baidu.com");
				HttpURLConnection connection = (HttpURLConnection)url.openConnection();
				connection.setRequestMethod("GET");//GET POST
				connection.setConnectiTimeOut(ms);//设置连接超时时间 单位ms
				connection.setReadTimeOut(ms);//设置读取超时时间 单位ms
				//获取输入流
				InputStream stream = connection.getInputStream();
				BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
				//读取数据
				reader.readLine();
			}
		}).start();
		//运行在UI 线程 可以这里面对 UI 界面进行修改
		runOnUiThread(new Runnable(){
			@Override
            public void run() {
				TextView.setText("xxxxx");
			}
		});
		
	2.通过 OkHttp:
		new Thread(new Runnable(){
			@Override
	        public void run() {
				OkHttpClient client = new OkHttpClient();
				//GET 
				Request request = new Request.Builder()
					.url()
					.build();
				/*
					//POST
					RequestBody requestBody = new FromBody.Builder()
						.add("键", "值")
						.add("键", "值")
						.build();
					Request request = new Request.Builder()
						.url()
						.post(requestBody)
						.build();
				*/
				Response response = client.newCall(request).execute();
				response.body().toString();
			}
		}).start();

9.2、解析xml

解析XML文件:
	1.Pull方式
		XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
		XmlPullParser xmlPullParser = factory.newPullParser();
		xmlPullParser.setInput(new StringReader("xml字符串"));
		int eventType = xmlPullParser.getEventType();
		//开始解析
		while(eventType != XmlPullParser.END_DOCUMENT){
			//获取节点名
			String nodeName = xmlPullParser.getName();
			case XmlPullParser.START_TAG:
				//根据不同的节点名做相应动作
					//获取当前节点内的数据
					xmlPullParser.nextText();
				break;
			case XmlPullParser.END_TAG:
				break;
			eventType = xmlPullParser.next();
		}
	2.SAX方式
		(1)新建一个类 继承 DefaultHandler 重写他的 startDocument、 startElement、 characters、 endElement、 endDocument 方法
			class XMLContentHandler extends DefaultHandler{
			
			}
		(2)
			SAXParserFactory factory = SAXParserFactory.newInstance();
			XMLReader xmlReader = factory.newSAXParser().getXMLReader();
			//配置
			xmlReader.setContentHandler(new XMLContentHandler());
			xmlReader.parser(new InputSource(new StringReader("xml字符串")));


9.3、解析Json

解析JSON串:
	解析JSON 串 就像剥洋葱 得一层一层来 (某位不知名的王某寄语)
	样例JSON 串:
		{
		  "employees": [
			{
			  "firstName": "Bill",
			  "lastName": "Gates"
			},
			{
			  "firstName": "George",
			  "lastName": "Bush"
			},
			{
			  "firstName": "Thomas",
			  "lastName": "Carter"
			}
		  ]
		}
	1.使用JSONObject 解析
		//首先我们看到这个json串外部是一个JSONObject对象
			//所以需要先获取到这个对象
		JSONObject jsonObject = new JSONObject("json字符串");
		//随后这个JSON 就变成了这样
			"employees": [
				{
				  "firstName": "Bill",
				  "lastName": "Gates"
				},
				{
				  "firstName": "George",
				  "lastName": "Bush"
				},
				{
				  "firstName": "Thomas",
				  "lastName": "Carter"
				}
			  ]
		//然后我们看到这个一个名为 "employees" 的JSON 数组
		//获取这个数组
		JSONArray jsonArray = jsonObject.getJSONArray("employees");
				{
				  "firstName": "Bill",
				  "lastName": "Gates"
				},
				{
				  "firstName": "George",
				  "lastName": "Bush"
				},
				{
				  "firstName": "Thomas",
				  "lastName": "Carter"
				}
		
		//我们看到这个数组中有好多好多小项组成 每个小项都是 JSONObject 类型的
		//从数组中逐个取出这些小项
		for(int i = 0; i < jsonArray.length(); i++){
			JSONObject object = jsonArray.getJSONObject(i);
			//拿到小项后
			/*
				  "firstName": "Bill",
				  "lastName": "Gates"
			*/
			//我们就可以根据键值来取出对应数据
			String firstName = object.getString("firstName");
			String lastName = object.getString("lastName");
			
		}
		
	2.使用Gson 解析
		还是采用上面的 JSON 样例
		//首先我们需要先给项目添加 Gson 依赖
		implementation 'com.google.code.gson:gson:2.8.8'
		
		//随后我们可以选择安装一个 GsonFormat 插件帮助我们快速将JSON 串转化为实体类
		
		//插件安装完成后 新建一个类 JsonContent 根据JSON 串创建实体
		//随后在主函数中调用
		
		//调用
		Gson gson = new Gson();
		JsonContent jsonContent = gson.fromJson("json字符串", new TypeToken<JsonContent>(){}.getType());
		List<JsonContent.EmployeesDTO> employees = jsonContent.getEmployees();
		for (JsonContent.EmployeesDTO exployeesDTO : employees){
			String firstName = exployeesDTO.getFirstName();
			String lastName = exployeesDTO.getLastName();
		}

第10章-Service

10.1、异步消息处理机制之:Handler

  • 1.组成

它总共由四部分组成,分别是 Message、Handler、Looper、MessageQueue

Message:是消息的载体,它可以在内部携带少量的信息,譬如 what 字段可以用来做标识,arg1 和 arg2字段 可以携带一些整形数据,此外可以使用 obj 字段来携带对象

Handler:用于发送和处理消息,发送消息一般使用 handler 的 sendMessge ,处理消息需要重写 Handler 的 handleMessage 方法 根据 Message 的what 字段来区分到底是哪条消息

MessageQueue:消息队列,用于存放 handler 发送的消息,每个线程中只会存在一个 MessageQueue

Looper:MessageQueue 的管家,调用 Looper.loop() 后会建立一个死循环, 不断地从 MessageQueue 中取出消息

  • 2.消息处理流程

首先需要在主线程中创建一个 Handler 对象, 并重写他的 handleMessage 方法

随后如果在子线程中需要进行 UI 等操作,就创建一个 Message 对象,并通过 handler 将其发送出去

之后这条消息会被添加到 MessageQueue 中,等待被处理

而Looper 一直尝试在 MessageQueue 中取消息,分发给 handler 的 handleMessage 方法

handleMessage 对消息进行处理

img

10.2、AsyncTask

  • 1.简介

AsyncTask也是基于异步消息处理机制的,只不过Android 对其进行了很好的封装

由于AsyncTask 是一个抽象类,所有如果我们想使用它就必须新建一个类来继承他,并且重写他的方法

在继承 AsyncTask 时候 我们可以指定三个参数,AsyncTask<Params, Progress, Result>

params:在AsyncTask 执行时候需要的参数 即 doInBackground() 的参数

progress:如果需要在前台进行进度显示时,进度的单位 由 progress 参数确定

result:当任务执行完毕,需要一个返回值,返回值的类型由 result 确定

  • 2.常用方法

onPreExecute():在后台任务开始执行之前调用,——主线程

doInBackground():在这里进行耗时的后台任务 在子线程 如果需要反馈任务进度 可以通过publishProgress() 方式来完成——子线程

onProgressUpdate():调用 publishProgress 方法后 就会调用该方法,可以对 UI 进行更新——主线程

onPostExecute():当后台任务执行完毕时候,就会调用本方法,doInBackground 的返回值 作为参数传递进来——主线程

10.3、Service

  • 1.简介

新服务的创建:创建一个类继承 Service 类,重写他的 onBind 方法,并在 AndroidManifest.xml 文件中注册 即可新建一个服务

onCreate() 只在服务第一次创建的时候调用

onStartCommand() 在服务每次启动时候调用

onDestory() 在服务销毁的时候调用

  • 2.活动和服务之间通信

创建一个类 继承 Binder

通过 onBind 方法绑定这个类

然后还需要在服务调用处 进行绑定

//在服务中进行绑定
public class MyService extends Service{
    private MyBinder mbind = new MyBinder();
	class MyBinder extends Binder{}

    public IBinder onBind(Intent intent) {
        return mbind;
    }
}
//服务调用处进行调用
private MyService.MyBinder mbind;
private ServiceConnection connection = new ServiceConnection(){
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            mbind = (MyService.MyBinder) iBinder;
        }
        public void onServiceDisconnected(ComponentName componentName) {
        }
}
Intent intent = new Intent(this, MyService.class);
startService(intent);
bindService(intent, connection, BIND_AUTO_CREATE);

protected void onDestroy() {
    super.onDestroy();
    unbindService(connection);
}

注:虽然每次调用 startService() 都会调用 onStartCommand 方法,但实际上只存在一个服务实例,所以不管调用多少次 startService() 最后退出前调用一次 unbindService() 就可退出服务

  • 3.前台服务

利用Notification 来避免因内存空间不足而回收后台正在运行的服务

//在 Service 的 onCreate 方法中 定义如下操作
public void onCreate(){
    Intent intent = new Intent(this, 目的Activity);
    PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
    Notification notification = Notification.Builder()
        .setContentTitle("title")
        .setContentText("content")
        .setWhen(System.currentTimeMillis)
        .setContentIntent(pi)
        .build();
    startForeground(标识, notification);
    
    
}
  • 4.IntentService

因为服务在主线程运行 所以如果直接在服务中 处理一些耗时操作 会导致 ANR 直接卡死

所以面对这些耗时操作,我们需要在服务中另起线程来处理这些耗时操作

//在Service 的 onStartCommand方法中 做如下定义
public void onStartCommand(Intent intent, int flags, int startId){
    new Thread(new Runnable(){
        public void run(){
            //处理耗时操作
        }
    }
    ).start();
}

对于这种服务 启动后会一直运行,必须调用 stopService 或是 stopself() 才可以使它停下来

但是这样会很麻烦,经常会忘记关闭线程

因此Android提供了一个 IntentService 帮助我们很好的解决了创建一个异步和自动停止的服务问题

//样例
public class MyIntentService extends IntentService{
    public MyIntentService(){
        super("MyIntentService");//调用父类的构造方法
    }
    //在子线程中运行
    protected void onHandleIntent(Intent intent){
        //处理耗时操作
    }
}

10.4、MaterialDesign

  • 1.主题的几个主要颜色区

  • 2.Toolbar标题栏

  • 3.DrawerLayout滑动侧边栏

  • 4.FloatActionButton悬浮按钮

  • 5.Snackbar提示栏

  • 6.CoordinatorLayout

第11章-高德地图使用

高德地图使用指南

一、申请高德地图KEY

二、开发前的准备

1 资源包的下载

相关下载-Android 地图SDK|高德地图API (amap.com)中根据自己的需要下载相应的包

我推荐选择开发包定制下载,他会帮你集成你需要的功能,这样就不需要咱们自己一个个去找包,然后再导入了,而且也大大缩小了资源包的体积

2 配置项目

解压下前面下载的项目资源包,将其放在工程的 libs 目录下,

然后在资源包右键添加作为library

随后还需要在 build.gradle 中添加一段话

android{
	...
	 sourceSets{
        main{
            jniLibs.srcDirs = ['libs']
        }
    }
	...

}

点击Syn Now 就配置装载好了

3 声明权限

随后我们需要在 AndroidManifest.xml 中做一些权限配置和声明

<!--允许访问网络,必选权限-->
    <uses-permission android:name="android.permission.INTERNET" />

    <!--允许获取精确位置,精准定位必选-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <!--允许获取粗略位置,粗略定位必选-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

    <!--允许获取设备和运营商信息,用于问题排查和网络定位(无gps情况下的定位),若需网络定位功能则必选-->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

    <!--允许获取网络状态,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <!--允许获取wifi网络信息,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

    <!--允许获取wifi状态改变,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

    <!--后台获取位置信息,若需后台定位则必选-->
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

    <!--用于申请调用A-GPS模块,卫星定位加速-->
    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />

    <!--允许写入扩展存储,用于写入缓存定位数据-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <!--允许读设备等信息,用于问题排查-->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

在 application 标签下添加如下内容

<application>
	...
	<meta-data android:name="com.amap.api.v2.apikey" android:value="你刚刚申请的key"/>
	...
</application>

三、显示地图

在页面布局中加入 MapView

<com.amap.api.maps.MapView
	android:id="@+id/mapdemo_mv"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
/>	

然后在 Activity 中获取该布局的实例,注意需要对 Activity 的各个状态对MapView 进行创建或销毁,因为地图的声明周期十分重要

 private MapView mapView;
 private AMap aMap;
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main);
    //获取地图控件引用
    mapView = (MapView) findViewById(R.id.mapdemo_mv);
    //在activity执行onCreate时执行mMapView.onCreate(savedInstanceState),创建地图
    mapView.onCreate(savedInstanceState);
    if (aMap == null){
        //这样就可以简单显示地图了
        aMap = mapView.getMap();
    }
     
  }
  @Override
  protected void onDestroy() {
    super.onDestroy();
    //在activity执行onDestroy时执行mMapView.onDestroy(),销毁地图
    mapView.onDestroy();
  }
 @Override
 protected void onResume() {
    super.onResume();
    //在activity执行onResume时执行mMapView.onResume (),重新绘制加载地图
    mapView.onResume();
    }
 @Override
 protected void onPause() {
    super.onPause();
    //在activity执行onPause时执行mMapView.onPause (),暂停地图的绘制
    mapView.onPause();
    }
 @Override
 protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    //在activity执行onSaveInstanceState时执行mMapView.onSaveInstanceState (outState),保存地图当前的状态
    mapView.onSaveInstanceState(outState);
  } 

四、显示定位蓝点

MyLocationStyle myLocationStyle = new MyLocationStyle();
//设置连续定位模式下的 时间间隔
myLocationStyle.interval(2000);

//设置定位蓝点展示模式
//LOCATION_TYPE_SHOW 只定位一次
//LOCATION_TYPE_LOCATE 只定位一次、且视图移动到屏幕中央
//LOCATION_TYPE_FOLLOW 连续定位、且视图移动到屏幕中央、定位蓝点随着设备移动 (1秒1次)
//LOCATION_TYPE_MAP_ROTATE 连续定位、且视图移动到屏幕中央、定位蓝点随着设备移动、地图依照设备方向旋转 (1秒1次)
//LOCATION_TYPE_LOCATION_ROTATE 连续定位、且视图移动到屏幕中央、定位蓝点随着设备移动、定位点依照设备方向旋转 (1秒1次)
//以下三种模式从5.1.0版本开始提供
//MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER 连续定位、且蓝点不会移动到视图中心点、定位点依照设备方向旋转、并且蓝点会随设备移动
//MyLocationStyle.LOCATION_TYPE_FOLLOW_NO_CENTER 连续定位、且蓝点不会移动到视图中心点、并且蓝点会随设备移动
//MyLocationStyle.LOCATION_TYPE_MAP_ROTATE_NO_CENTER 连续定位、蓝点不会移动到地图中心点、地图依照设备方向旋转、并且蓝点会跟随设备移动。
myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE);

//设置是否显示定位小蓝点
myLocationStyle.showMyLocation(true);
//自定义定位小兰点图标
myLocationStyle.myLocationIcon(BitmapDescriptor xx);
//设置定位蓝点样式
aMap.setMyLocationStytle(myLocationStyle);
//设置定位按钮 是否显示 可以定位到当前位置、且视图移动到视图中心
aMap.getUiSettings().setMyLocationButtonEnabled(true);
//设置是否启动定位蓝点
aMap.setMyLocationEnabled(true);


//获取当前位置信息 经纬度
aMap.setOnMyLocationChangeListener(new AMap.OnMyLocationChangeListener() {
    @Override
    public void onMyLocationChange(Location location) {
        //在这里可以对定位进行操作
        Log.e(TAG, "onMyLocationChange: "+location.getLatitude() + location.getLongitude() );
    }
});

五、控件交互

基本控件的操作都需要通过 UiSettings 这个类来实现

private UiSettings uiSettings;
uiSettings = aMap.getUiSettings();

//缩放按钮
uiSettings.setZoomControls(true);
//缩放按钮位置
//AMapOptions.ZOOM_POSITION_RIGHT_BUTTOM 右侧靠下
//AMapOptions.ZOOM_POSITION_RIGHT_CENTER 右侧居中
uiSettings.setZoomPosition(AMapOptions.ZOOM_POSITION_RIGHT_CENTER);

//指南针
uiSettings.setCompassEnable(true);

//定位按钮
//设置数据监听源
aMap.setLocationSource(this);
//显示默认定位按钮
uiSettings.setMyLocationButtonEnable(true);
//可触发定位并显示当前位置
aMap.setMyLocationEnable(true);

//比例尺
uiSettings.setScaleControlsEnable(true);

//高德地图logo
//AMapOptions.LOGO_POSITION_BOTTOM_LEFT  LOGO边缘MARGIN(左边)
//AMapOptions.LOGO_MARGIN_BOTTOM  LOGO边缘MARGIN(底部
//AMapOptions.LOGO_MARGIN_RIGHT  LOGO边缘MARGIN(右边)
//AMapOptions.LOGO_POSITION_BOTTOM_CENTER  Logo位置(地图底部居中)
//AMapOptions.LOGO_POSITION_BOTTOM_LEFT  Logo位置(地图左下角)
//AMapOptions.LOGO_POSITION_BOTTOM_RIGHT  Logo位置(地图右下角)
uiSettings.setLogoPosition(AMapOptions.LOGO_POSITION_BOTTOM_LEFT);

六、手势交互

1 缩放手势

缩放手势可改变地图的缩放级别,地图响应的手势如下:

  • 双击地图可以使缩放级别增加1 (放大)
  • 两个手指捏/拉伸

也可以禁用或启用缩放手势。禁用缩放手势不会影响用户使用地图上的缩放控制按钮

UiSettings.setZoomGesturesEnabled(boolean);
2 滑动手势

您可以用手指拖动地图四处滚动(平移)或用手指滑动地图(动画效果),也可以禁用或开启平移(滑动)手势。

UiSettings.setScrollGesturesEnabled(boolean);
3 旋转手势

您可以用两个手指在地图上转动,可以旋转3D矢量地图,也可以禁用旋转手势。

UiSettings.setRotateGesturesEnabled(boolean);
4 倾斜手势

用户可以在地图上放置两个手指,移动它们一起向下或向上去增加或减小倾斜角,也可以禁用倾斜手势。

UiSettings.setTiltGesturesEnabled(boolean);

七、地址编码

1.根据关键词获取该位置经纬度
GeocodeQuery query = new GeocodeQuery("关键词", "搜索范围,null为国内搜索");
GeocodeSearch search = new GeocodeSearch(Context context);
//继承接口 重写方法
search.setOnGeocodeSearchListener(this);
search.getFromLocationNameAsyn(query);

@Override
public void onGeocodeSearched(GeocodeResult geocodeResult, int i) {
    if (i == AMapException.CODE_AMAP_SUCCESS){
        if (geocodeResult != null && geocodeResult.getGeocodeAddressList() != null && geocodeResult.getGeocodeAddressList().size() > 0){
           //只使用第一个值
            GeocodeAddress address = geocodeResult.getGeocodeAddressList().get(0);
            if (address != null){
                //获取经纬度 生成LatLng对象
                LatLng latLng = new LatLng(address.getLatitude(), address.getLongtitude());;
            }
        }
    }
}
2.根据经纬度获取该地信息

八、进行导航

高德给我们提供了一个现成的API供我们使用

//传入起始位置和终点位置的POI
POI start = new POI("地点名", LatLang latlang,"");//地点名  地点经纬度  
//起始点,null,终点,模式
AmapNaviParams params = new AmapNaviParams(start, null, end, AmapNaviType.DRIVER);
params.setUseInnerVoice(true);
AmapNaviPage.getInstance().showRouteActivity(getApplicationContext(), params, MainActivity.this);
posted @ 2022-02-22 16:08  Alen.Wang  阅读(129)  评论(0编辑  收藏  举报