0%

官方描述

设置边界

有时,通过移动摄像头来以尽可能最高的缩放级别显示整个受关注区域很有用处。 例如, 如果您要显示用户当前位置方圆五英里内的所有加油站, 可能就需要通过移动摄像头让它们全都显示在屏幕上。 如需实现此目的,请先计算您想在屏幕上显示的 LatLngBounds。 然后使用 CameraUpdateFactory.newLatLngBounds(LatLngBounds bounds, int padding) 获取 CameraUpdate,后者会相应更改摄像头位置,使得给定 LatLngBounds 在计入所指定内边距(单位:像素)后能够完全容纳在地图内。 返回的 CameraUpdate 可确保给定边界与地图边缘之间的间隙(单位:像素)至少与指定的内边距一样大。 请注意,地图的倾斜角度和方位均为 0。

1
2
3
4
5
6
7
8
private GoogleMap mMap;
// Create a LatLngBounds that includes Australia.
private LatLngBounds AUSTRALIA = new LatLngBounds(
new LatLng(-44, 113), new LatLng(-10, 154));

// Set the camera to the greatest possible zoom level that includes the
// bounds
mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(AUSTRALIA, 0));

LatLngBounds

  • public LatLngBounds including (LatLng point) 包含显示的点
  • public LatLng getCenter () 获得中心点

代码的具体实现

1
2
3
4
5
LatLngBounds.Builder latLngBounds=new LatLngBounds.Builder();
for (int i=0;i<latLngs.size();i++){
latLngBounds.include(latLngs.get(i));
}
googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(latLngBounds.build(), 30));

问题

如果直接在获取到地图后调用会报错
解决:在回调里调用

1
2
3
4
5
googleMap.setOnMapLoadedCallback(this); 
@Override
public void onMapLoaded() {
//添加实现的代码
}

全局初始化greenDAO设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class UserGlobalApp extends Application{
private static UserGlobalApp application;
private final static String dbName = "HiJia"; //数据库名字
/** A flag to show how easily you can switch from standard SQLite to the encrypted SQLCipher. */
public static final boolean ENCRYPTED = false; //改为true需要加入包compile 'net.zetetic:android-database-sqlcipher:3.5.1'
private DaoSession daoSession;
@Override
public void onCreate() {
super.onCreate();
application=this;
initDb();
}

/***
* 初始化greenDao
* 数据库
*/
private void initDb(){
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, ENCRYPTED ? dbName+"-encrypted.db" : dbName+".db",null);
Database db = ENCRYPTED ? helper.getEncryptedWritableDb("super-secret") : helper.getWritableDb();
daoSession = new DaoMaster(db).newSession();
}
public DaoSession getDaoSession() {
return daoSession;
}

public static UserGlobalApp getApplication(){
return application;
}
}

使用

添加数据,查询数据

1
2
3
UserGlobalApp.getApplication().getDaoSession().getTrackPointDao().insert(new TrackPoint((long) 10,System.currentTimeMillis(),10.01,10.02,1));
Log.i("sssss",""+UserGlobalApp.getApplication().getDaoSession().getTrackPointDao().loadAll().size());

生成的dao目录配置(非必须)

1
2
3
4
5
6
7
//------------greenDAO数据库配置-----------
greendao {
schemaVersion 1 //数据库版本
daoPackage'com.xuan.bledemo.db.greendao' //dao的存放目录
targetGenDir'src/main/java'
}

问题

数据库加密问题
在全局配置中如果要加密,要设置为true,但是设置为ture会报错

1
public static final boolean ENCRYPTED = false;  //改为true需要加入包compile 

解决:因为没有加密包,需要添加依赖

1
compile 'net.zetetic:android-database-sqlcipher:3.5.1'

数据库路径设置

1
2
3
File path=new File(Environment.getExternalStorageDirectory(),"BleDemo/db/"+dbName);  //设置存储路径
path.getParentFile().mkdirs();
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, ENCRYPTED ? path.getAbsolutePath()+"-encrypted.db" : path.getAbsolutePath()+".db",null);

新建一个xml,放标题内容

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary">
<!--自定义控件-->
<!--<TextView-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:text="标题" />-->
</android.support.v7.widget.Toolbar>

在需要的页面调用

1
2
3
4
<include
android:layout_width="match_parent"
android:layout_height="wrap_content"
layout="@layout/activity_tool_bar" />

去掉自带标题

在配置文件找到

1
android:theme="@style/AppTheme"

点击进去把parent修改为NoActionBar

1
2
3
4
5
6
7
8
9
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<!--最顶层的颜色消息时间栏-->
<item name="colorPrimary">@color/colorPrimary</item>
<!--标题栏颜色-->
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<!--应用内系统控件的颜色,例如系统的滑动条等-->
<item name="colorAccent">@color/colorAccent</item>
</style>

在activity里获取标题控件,设置基本属性

1
2
3
4
5
6
7
8
9
10
toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle("标题");
toolbar.setSubtitle("副标题");
toolbar.setTitleTextColor(Color.WHITE); //颜色
toolbar.setSubtitleTextColor(Color.WHITE);
toolbar.setLogo(R.mipmap.debug); //图标

//设置导航图标要在setSupportActionBar方法之后
setSupportActionBar(toolbar);
toolbar.setNavigationIcon(R.mipmap.ic_launcher);

在activity添加标题栏返回箭头

使能返回button

1
2
3
4
5
6
7
toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle("标题");
toolbar.setSubtitle(副标题);
//设置导航图标要在setSupportActionBar方法之后
setSupportActionBar(toolbar);
if(getSupportActionBar() != null)
getSupportActionBar().setDisplayHomeAsUpEnabled(true); // Enable the Up button

添加返回button事件

1
2
3
4
5
6
7
8
9
 @Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case android.R.id.home: //返回键
//添加处理代码
break;
}
return super.onOptionsItemSelected(item);
}

扫描模式

ScanSettings的属性与方法

1
2
3
4
5
6
7
8
9
10
11
12
ScanSettings settings = new ScanSettings.Builder()
//设置扫描模式(SCAN_MODE_LOW_LATENCY扫描优先,SCAN_MODE_LOW_POWER省电优先,SCAN_MODE_BALANCED平衡模式,SCAN_MODE_OPPORTUNISTIC安卓6.0里面才用的模式)
.setScanMode(ScanSettings.SCAN_MODE_OPPORTUNISTIC)
//设置扫描的时间,设置了这一项,将扫描5秒,然后在onBatchScanResults里面回调
.setReportDelay(5000)
//android 6.0可用
.setMatchMode(1)
//android 6.0可用
.setCallbackType(1)
//android 6.0可用
.setNumOfMatches(1)
.build();

主流的ORM框架

greenDAO

介绍

greenDAO是一种Android数据库ORM(object/relational mapping)框架,与OrmLite、ActiveOrm、LitePal等数据库相比,单位时间内可以插入、更新和查询更多的数据,而且提供了大量的灵活通用接口。
源码github
官网

GreenDao 3.0改动:

使用过GreenDao的同学都知道,3.0之前需要通过新建GreenDaoGenerator工程生成Java数据对象(实体)和DAO对象,非常的繁琐而且也加大了使用成本。

GreenDao 3.0最大的变化就是采用注解的方式通过编译方式生成Java数据对象和DAO对象。

类注解

  • @Entity 标记了一个Java类作为一个greenDAO实体
1
2
3
4
@Entity
public class Test {
...
}

基本属性注解

  • @Id 必须是long类型,在数据库作为主键,参数autoincrement是否自增
1
2
@Id(autoincrement = true)
private Long id;
  • @Property 指定改字段的列名,如果不指定将使用默认值(eg:customName对应数据库列名为CUSTOM_NAME)
1
2
@Property(nameInDb = "USER_NAME")
private String customName;
  • @Transient 这个属性将不会作为数据表中的一个字段
1
2
@Transient
private int tempUsageCount;
  • @NotNull 该字段不能为null(作用于long, int, short, byte类型)
1
2
@NotNull
private int repos;
  • @Index 索引(unique唯一)
1
2
@Index(unique = true)
private String name;
  • @Unique 添加唯一键(隐含为其创建了一个索引)
1
@Unique private String name;

问题

知识点:int 是基本类型,直接存数值,而integer是对象,用一个引用指向这个对象
问题描述:在实体类用int等基本类型,默认不标记注解,在建数据库也会全部设置NOT NULL
解决:因此需要在实体类里写对象类型。
2016-11-29 16:18:24 发现使用中文字段名默认生成为ANSI,出现乱码,尽量使用因为的字段别名

主流的ORM框架

greenDAO3.1 安装

配置build.gradle

在model的build.gradle文件添加如下配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.greenrobot:greendao-gradle-plugin:3.1.0'
}
}

apply plugin: 'org.greenrobot.greendao'

dependencies {
compile 'org.greenrobot:greendao:3.1.0'
}

数据库的设置(可选项)

在model的build.gradle文件添加如下配置

1
2
3
4
5
6
7
8
android {
...
}

greendao {
schemaVersion 2
...
}

参数解释

  • schemaVersion: 数据库schema版本,也可以理解为数据库版本号(默认1)
  • daoPackage:设置DaoMaster 、DaoSession、Dao包名(默认为你实体的名字)
  • targetGenDir:设置DaoMaster 、DaoSession、Dao目录(默认build/generated/source/greendao)
  • testsGenSrcDir:设置生成单元测试目录(默认src/androidTest/java)
  • generateTests:设置自动生成单元测试用例

新建实体

添加注解@

1
2
3
4
5
6
7
8
9
10
11
12
13
@Entity
public class test {
@Id(autoincrement = true)
private long tes;

public long getTes() {
return tes;
}

public void setTes(long tes) {
this.tes = tes;
}
}

编译运行

  • targetGenDir目录(默认build/generated/source/greendao)下自动生成自动生成DaoMaster.java 、DaoSession.java、Dao.java
  • 实体test.java自动新增如下代码
1
2
3
4
5
6
7
8
@Generated(hash = 838475940)
public test(long tes) {
this.tes = tes;
}

@Generated(hash = 1102163179)
public test() {
}

简单的使用

新建DBManager.java管理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public class DBManager {
private final static String dbName = "test_db";
private static DBManager mInstance;
private DaoMaster.DevOpenHelper openHelper;
private Context context;

public DBManager(Context context) {
this.context = context;
openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
}
/**
* 获取单例引用
*
* @param context
* @return
*/
public static DBManager getInstance(Context context) {
if (mInstance == null) {
synchronized (DBManager.class) {
if (mInstance == null) {
mInstance = new DBManager(context);
}
}
}
return mInstance;
}

/**
* 获取可读数据库
*/
private SQLiteDatabase getReadableDatabase() {
if (openHelper == null) {
openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
}
SQLiteDatabase db = openHelper.getReadableDatabase();
return db;
}
/**
* 获取可写数据库
*/
private SQLiteDatabase getWritableDatabase() {
if (openHelper == null) {
openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
}
SQLiteDatabase db = openHelper.getWritableDatabase();
return db;
}
/**
* 插入一条记录
*
* @param test
*/
public void insertUser(test test) {
DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
DaoSession daoSession = daoMaster.newSession();
testDao userDao = daoSession.getTestDao();
userDao.insert(test);
}
/**
* 查询用户列表
*/
public List<test> queryUserList() {
DaoMaster daoMaster = new DaoMaster(getReadableDatabase());
DaoSession daoSession = daoMaster.newSession();
testDao userDao = daoSession.getTestDao();
QueryBuilder<test> qb = userDao.queryBuilder();
List<test> list = qb.list();
return list;
}
}

测试代码

1
2
3
4
5
private void daotest(){
DBManager dbManager=DBManager.getInstance(this);
dbManager.insertUser(new test(10));
Log.i("sssss","ddddd"+dbManager.queryUserList().get(0).getTes());
}

参考

Android数据存储之GreenDao 3.0 详解
官方教程

创建拦截器(Interceptor)

可以分开写两个拦截器一个有网的一个离线的,这里只写了一个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//创建拦截器(Interceptor)
Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
okhttp3.Response originalResponse = chain.proceed(chain.request());
if (com.xuan.bledemo.util.Utils.isNetworkAvailable(MainActivity.this)) { //判断是否有网络判断
int maxAge = 60; //在线缓存在一分钟内读取
Log.i("缓存测试", "在线");
return originalResponse.newBuilder()
.removeHeader("Pragma") //作用未知
.header("Cache-Control", "public,max-age=" + maxAge)
.build();
} else {
int maxStale = 60 * 60 * 24 * 28; //离线时缓存保存4周
Log.i("缓存测试", "离线");
return originalResponse.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.build();
}
}
};

设置缓存文件

问题?关于缓存文件在手机上的地方,目前未找到

1
2
3
4
//设置缓存文件
File cacheFile=new File(this.getCacheDir(),"xuanCache");
Log.i("缓存测试","缓存目录"+this.getCacheDir().getPath());
Cache cache=new Cache(cacheFile,1024*1024*100); //100mb

创建httpclient

1
2
3
4
5
6
7
8
//创建httpclient
OkHttpClient okHttpClient=new OkHttpClient.Builder()
.cache(cache)
.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR) //添加有网过滤器
.addInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR) //添加无网络过滤器,可以分别定义
.retryOnConnectionFailure(true) //出现错误时重新连接
.connectTimeout(5, TimeUnit.SECONDS) //设置超时时间
.build();

将httpclient添加到retrofit

1
2
3
4
5
6
//将http client添加到retrofit
Retrofit retrofit=new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create()) //添加gson包
.client(okHttpClient) //添加自定义的httpclient
.baseUrl("http://api.zdoz.net/") //添加网址头,注意‘/’结尾
.build();

请求数据

第一次必须有网络,后面无网络就是请求缓存

  • enqueue 异步
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Itest itest=retrofit.create(Itest.class); //接口
Call<Test> getCall= itest.getTest(108.2345); //传接口参数
//异步网络请求json数据
getCall.enqueue(new Callback<Test>() {
@Override
public void onResponse(Call<Test> call, Response<Test> response) {
Log.e("缓存测试","请求成功"+response.body().getD());
}
@Override
public void onFailure(Call<Test> call, Throwable t) {
Log.e("缓存测试","请求失败"+t.toString());

}
});

问题,未验证

  • 相当与数据库的 POST(创建)、PUT(更新)、GET(查看)、DELETE(删除)
  • 缓存根据查找的资料,好像只有GET可以缓存

总结

  • 上述缓存,是同一缓存的配置,如果要单个请求配置,可以设置接口的head,在里面传参数,然后在统一的缓存配置中用参数动态变化没次的不同缓存策略及时间。

认识

当前的网络开源库有许多,如volley,okhttp,retrofit等,这三个库当前是比较火的,其中,okhttp和retrofit由square团队开发。

  • okhttp是高性能的http库,等同于httpclient,6.0将替换httpclient
  • 简化了网络请求流程,同时自己内部对OkHtttp客户端做了封装
  • gson库是为了将返回数据转化为实体类

搭建环境

Retrofit

1
compile 'com.squareup.retrofit2:retrofit:2.1.0'

gson

1
2
//将请求结果转换成json的json转换包,如果导入了这个依赖,就不用再导入Gson包,因为这个已经包含了Gson包
compile 'com.squareup.retrofit2:converter-gson:2.1.0'

网络权限

1
2
<!-- 用于访问网络,网络定位需要上网 -->
<uses-permission android:name="android.permission.INTERNET" />

创建json对应得实体类

测试网址:http://api.zdoz.net/DDD2DMS.aspx?gps=108.2345

  • 新建一个实体类Test.java,把json数据通过gsonFormat插件生成对应得属性方法

创建接口

  • 新建一个接口类Itest.java
1
2
3
4
public interface Itest {
@GET("DDD2DMS.aspx")
Call<Test> getTest(@Query("gps") double gps);
}

请求json数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Retrofit retrofit=new Retrofit.Builder()
//如果是json数据必须加这句
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://api.zdoz.net/")
.build();
Itest itest=retrofit.create(Itest.class);
Call<Test> testCall= itest.getTest(108.2345);
testCall.enqueue(new Callback<Test>() {
@Override
public void onResponse(Call<Test> call, Response<Test> response) {
Log.e("得到得json数据",""+response.body().getD());
}
@Override
public void onFailure(Call<Test> call, Throwable t) {

}
});

参数详解

  • enqueue 异步请求
  • execute 同步请求
  • baseUrl参数以’/‘结束