TinderLiker 开发总结

概览:

1. 采用ORM数据库LitePal

2. ToolBar的使用

3. 最新兼容库的下拉刷新

4. 工具类


1. 采用ORM数据库LitePal

(1)官方介绍

LitePal is an Open Source Android library that allows developers to use SQLite database extremely easy. You can finish most of the database operations without writing even a SQL statement, including create or upgrade tables, crud operations, aggregate functions, etc. The setup of LitePal is quite simple as well, you can integrate it into your project in less than 5 minutes.

官方地址GitHub

系列博客地址(中文的)

(2)欣赏一下增删改查(配置超级简单,见官网)

1
2
3
4
Album album = new Album();
album.setName("album");
album.setPrice(10.99f);
album.save();

1
2
3
DataSupport.delete(Song.class, id);
DataSupport.deleteAll(Song.class, "duration > ?" , "350");

1
2
3
4
5
6
7
Album albumToUpdate = new Album();
albumToUpdate.setPrice(20.99f); // raise the price
albumToUpdate.update(id);
Album albumToUpdate = new Album();
albumToUpdate.setPrice(20.99f); // raise the price
albumToUpdate.updateAll("name = ?", "album");

1
2
3
4
5
Song song = DataSupport.find(Song.class, id);
List<Song> allSongs = DataSupport.findAll(Song.class);
List<Song> songs = DataSupport.where("name like ?", "song%").order("duration").find(Song.class);

(3)踩过的坑

a. 定义model时,加上id,方便以后更新数据

如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Address extends DataSupport {
private long id;
private String name;
private float lat;
private float lng;
private Date date;
private boolean checked;
private boolean my_location;
private String owner_id;
public Address() {
}
...
}

更新时就可以

1
2
3
4
Tinder savedTinder = savedTinders.get(0);
savedTinder.setChanged_date(t.getChanged_date());
savedTinder.setRelation(t.getRelation());
savedTinder.update(savedTinder.getId());
b. 更新到默认值的方法有点特别

源码如下:

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
/**
* Updates the corresponding record by id. Use setXxx to decide which
* columns to update.
*
* <pre>
* Person person = new Person();
* person.setName("Jim");
* person.update(1);
* </pre>
*
* This means that the name of record 1 will be updated into Jim.<br>
*
* <b>Note: </b> 1. If you set a default value to a field, the corresponding
* column won't be updated. Use {@link #setToDefault(String)} to update
* columns into default value. 2. This method couldn't update foreign key in
* database. So do not use setXxx to set associations between models.
*
* @param id
* Which record to update.
* @return The number of rows affected.
*/
public synchronized int update(long id) {
try {
UpdateHandler updateHandler = new UpdateHandler(Connector.getDatabase());
int rowsAffected = updateHandler.onUpdate(this, id);
getFieldsToSetToDefault().clear();
return rowsAffected;
} catch (Exception e) {
throw new DataSupportException(e.getMessage());
}
}

所以更新到默认值的时候需要这么做:

1
2
3
4
5
6
7
8
9
long id = address.getId();
if (id > 0) {
if (!address.isChecked()) {
address.setToDefault("checked");
}
address.update(id);
} else {
address.save();
}
c. 别忘了Proguard

-keep class org.litepal.* { ; }

2. ToolBar的使用

(1)依赖

1
2
3
4
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:21.0.2'
}

(2)Theme配制

style.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="AppTheme.Base">
<!-- Customize your theme here. -->
</style>
<style name="AppTheme.Base" parent="Theme.AppCompat">
<item name="windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<!-- Actionbar color -->
<item name="colorPrimary">@color/red</item>
<!--Status bar color-->
<item name="colorPrimaryDark">@color/red</item>
<!--Window color-->
<item name="android:windowBackground">@android:color/white</item>
</style>
</resources>

v21/style.xml

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="AppTheme.Base">
<!--Navigation bar color-->
<item name="android:navigationBarColor">@color/red</item>
</style>
</resources>

(3)单独定义toolBar的布局文件toolbar.xml

1
2
3
4
5
6
7
8
9
<?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_height="wrap_content"
android:background="?attr/colorPrimary"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize">
</android.support.v7.widget.Toolbar>

(4)其他布局文件中引入toolBar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
layout="@layout/toolbar"
android:id="@+id/toolbar" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
...
</ScrollView>
</LinearLayout>

(5)让toolBar支持actionBar

1
2
3
4
5
6
7
8
9
10
11
12
13
private void initToolBar() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setTitle(mTinder.getName());
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}

3. 最新兼容库的下拉刷新

(1)依赖

1
2
3
4
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:21.0.2'
}

(2)布局和其他的下拉刷新一样

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
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/frag_liker_refresh_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/frag_liker_bottom_layout">
<GridView
android:id="@+id/frag_liker_gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp"
android:gravity="fill"
android:horizontalSpacing="8dp"
android:numColumns="3"
android:stretchMode="columnWidth"
android:verticalSpacing="8dp" />
</android.support.v4.widget.SwipeRefreshLayout>
<TextView
android:id="@+id/empty_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:layout_marginTop="150dp"
android:layout_centerHorizontal="true"
android:textColor="#ababab"
android:visibility="gone"
android:gravity="center"
android:lineSpacingExtra="6dp"
android:drawableTop="@drawable/ic_mainlikepass_smile"
android:text="@string/frag_tinder_liker_empty" />
</RelativeLayout>

注意这里展示空列表的方式

(3)刚进入页面显示刷新图标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 定义Runnable
private Runnable mProgressRunnable = new Runnable() {
@Override
public void run() {
mSwipeRefreshLayout.setRefreshing(true);
}
};
// 第一次显示刷新
mHandler.postDelayed(mProgressRunnable, 100);
// 停止刷新
mHandler.removeCallbacks(mProgressRunnable);
mSwipeRefreshLayout.setRefreshing(false);

如果只是在初始化是设置mSwipeRefreshLayout.setRefreshing(true);,刷新图标不会显示。

4. 工具类

(1)把形如1988-08-17T00:00:00.000Z的时间转换为毫秒数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static int getAge(String formattedBirthday) {
// birth_date : 1988-08-17T00:00:00.000Z
String format = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.US);
int age = 0;
Calendar cal = Calendar.getInstance();
int nowYear = cal.get(Calendar.YEAR);
try {
Date date = sdf.parse(formattedBirthday);
cal.setTime(date);
int birthYear = cal.get(Calendar.YEAR);
age = nowYear - birthYear;
if (age < 0) age = 0;
} catch (ParseException e) {
e.printStackTrace();
}
return age;
}

(2)利用Android的工具方法得到相对时间,如一天前,一周前等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static CharSequence getActiveTime(String formattedTime) {
String format = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.US);
CharSequence activeTime = "";
Calendar cal = Calendar.getInstance();
try {
Date date = sdf.parse(formattedTime);
cal.setTime(date);
activeTime = DateUtils.getRelativeTimeSpanString(cal.getTimeInMillis());
} catch (ParseException e) {
e.printStackTrace();
}
return activeTime;
}