背景
MVVM是目前谷歌推荐的Android开发层次框架,如果跟JetPacket相互结合 可以更好的进行相关的开发。
使用到的JetPacket组件
LiveData 、Room 、ViewModel、DataBinding
代码分层分包
比如我们需要开发一个用户信息模块 根据mvvm的设计理念我们可以这个分包
|-- api
|-- room
|-- userInfo
| |-- model
| |-- repository
| |-- view
| |-- viewmodel
- api 是结合retrofit的请求库 作为全局的网络请求url封装
- room 作为全局数据库的一个封装包,提供各种持久化数据库的入口
- model 作为一个小功能的数据层
- repository 是当这个功能的获取数据比较复杂的时候可以多加一层
- view是作为数据的显示层
- viewmodel 作为viewmodel层主要是进行逻辑处理
代码编写
1.别忘了添加权限
<uses-permission android:name="android.permission.INTERNET" />
2.dataBinding 需要打开
dataBinding {
enabled = true
}
- 添加环境依赖
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'com.squareup.retrofit2:retrofit:2.6.2'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'androidx.room:room-runtime:2.2.2'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
implementation 'de.hdodenhof:circleimageview:3.0.1'
annotationProcessor 'androidx.room:room-compiler:2.2.2'
- 定义model层
@Entity(tableName = "user")
public class User {
@PrimaryKey()
@ColumnInfo(name = "id", typeAffinity = ColumnInfo.INTEGER)
public int id;
@ColumnInfo(name = "name", typeAffinity = ColumnInfo.TEXT)
public String name;
@ColumnInfo(name = "avatar", typeAffinity = ColumnInfo.TEXT)
@SerializedName("avatar_url")
public String avatar;
@ColumnInfo(name = "followers", typeAffinity = ColumnInfo.INTEGER)
public int followers;
@ColumnInfo(name = "following", typeAffinity = ColumnInfo.INTEGER)
public int following;
@ColumnInfo(name = "blog", typeAffinity = ColumnInfo.TEXT)
public String blog;
@ColumnInfo(name = "company", typeAffinity = ColumnInfo.TEXT)
public String company;
@ColumnInfo(name = "bio", typeAffinity = ColumnInfo.TEXT)
public String bio;
@ColumnInfo(name = "location", typeAffinity = ColumnInfo.TEXT)
public String location;
@ColumnInfo(name = "html_url", typeAffinity = ColumnInfo.TEXT)
@SerializedName("html_url")
public String htmlUrl;
public User(
int id, String name, String avatar, int followers, int following, String blog, String company, String bio, String location, String htmlUrl) {
this.id = id;
this.name = name;
this.avatar = avatar;
this.followers = followers;
this.following = following;
this.blog = blog;
this.company = company;
this.bio = bio;
this.location = location;
this.htmlUrl = htmlUrl;
}
}
- 创建数据库
@Database(entities = User.class, version = 1, exportSchema = false)
public abstract class UserDatebase extends RoomDatabase {
private static final String DATABASE_NAME = "user_db";
private static UserDatebase databaseInstance;
public static synchronized UserDatebase getInstance(Context context) {
if (databaseInstance == null) {
databaseInstance = Room.databaseBuilder(context.getApplicationContext(), UserDatebase.class, DATABASE_NAME).build();
}
return databaseInstance;
}
public abstract UserDao getUserDao();
}
@Dao
public interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertUser(User user);
@Delete
void deleteStudent(User user);
@Query("SELECT * FROM user WHERE name= :name")
LiveData<User> getUserByName(String name);
}
6.定义网络请求
public interface API {
@GET("users/{userId}")
Call<User> getUser(@Path("userId") String userId);
}
public class RetrofitClient {
private static final String BASE_URL = "http://www.baidu.com";
private static RetrofitClient retrofitClient;
private Retrofit retrofit;
private RetrofitClient() {
retrofit = new Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build();
}
public static synchronized RetrofitClient getInstance() {
if (retrofitClient == null) {
retrofitClient = new RetrofitClient();
}
return retrofitClient;
}
public API getApi() {
return retrofit.create(API.class);
}
}
7.将数据库和网络库的获取方式放在application方便获取
public class MyApplication extends android.app.Application {
private static UserDatebase userDatebase;
private static API api;
@Override
public void onCreate() {
super.onCreate();
userDatebase = UserDatebase.getInstance(this);
api = RetrofitClient.getInstance().getApi();
}
public static API getApi() {
return api;
}
public static UserDatebase getUserDatebase() {
return userDatebase;
}
}
8.假设我们要获取的数据非常复杂,我们可以多搞一个repository层(当然这一层也是可以没有的)
public class UserRepository {
private String TAG = this.getClass().getName();
private UserDao userDao;
private API api;
public UserRepository(UserDao userDao, API api) {
this.api = api;
this.userDao = userDao;
}
public LiveData<User> getUser(final String name) {
refresh(name);
return userDao.getUserByName(name);
}
public void refresh(String name) {
api.getUser(name).enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.body() != null) {
insterUer(response.body());
}
}
@Override
public void onFailure(Call<User> call, Throwable t) {
Log.i(TAG, "onFailure: ", t);
}
});
}
private void insterUer(final User user) {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
userDao.insertUser(user);
}
});
}
}
9.将viewmodel层给实现
public class UserViewModel extends AndroidViewModel {
private LiveData<User> user;
private UserRepository userRepository;
private String userName = "whd";
public UserViewModel(@NonNull Application application) {
super(application);
UserDatebase userDatebase = MyApplication.getUserDatebase();
UserDao userDao = userDatebase.getUserDao();
userRepository = new UserRepository(userDao, MyApplication.getApi());
user = userRepository.getUser(userName);
}
public LiveData<User> getUser(){
return user;
}
public void refresh(){
userRepository.refresh(userName);
}
}
10.我们再看下view层 包括Activity和xml
class Main2Activity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
var binding =
DataBindingUtil.setContentView<ActivityMain2Binding>(this, R.layout.activity_main2)
val userViewModel = ViewModelProvider(this).get(UserViewModel::class.java)
userViewModel.user.observe(this,
Observer<User> {
binding.user = it
})
val swipeRefresh = binding.swipeRefresh
swipeRefresh.setOnRefreshListener {
userViewModel.refresh()
swipeRefresh.isRefreshing = false
}
}
}
xml包括了一些数据的显示
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="user"
type="com.example.mvvm_jetpack.userInfo.model.User" />
</data>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitStart"></ImageView>
<view
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="128dp"
android:layout_marginTop="128dp"
android:layout_marginRight="128dp"></view>
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="80dp"
android:gravity="center_horizontal"
android:orientation="vertical">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/profile_image"
android:layout_width="96dp"
android:layout_height="96dp"
app:civ_border_color="#CCCCCC"
app:civ_border_width="2dp"
app:image="@{user.avatar}"
></de.hdodenhof.circleimageview.CircleImageView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@{user.name}"
android:textSize="22sp"
android:textStyle="bold"
></TextView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@{user.bio}"
android:textSize="16sp"></TextView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@{user.company}"
android:textSize="16sp"></TextView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@{user.location}"
android:textSize="16sp"></TextView>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.followers}"
android:textSize="16sp"></TextView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:text="@{user.following}"
android:textSize="16dp"
></TextView>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@{user.htmlUrl}"
android:textSize="16dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@{user.blog}"
android:textSize="16dp" />
</LinearLayout>
</RelativeLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</layout>
我们还将圆形头像的加载给到Picasa来加载
public class ImageViewBindAdapter {
@BindingAdapter(value = {"image", "defaultImageResource"}, requireAll = false)
public static void setImage(ImageView imageView, String imageUrl, int imageSource) {
if (!TextUtils.isEmpty(imageUrl)) {
Picasso.get().load(imageUrl).placeholder(R.drawable.ic_launcher_background).error(R.drawable.ic_launcher_background).into(imageView);
}
}
}
总结
以上就是Mvvm结合Jetpack的使用,希望在平时项目中多运用,写出更高效和优质的代码。