一,初识jeptack
jetpack是一个又多个库组成的套件,可以帮助开发者遵循最佳做法,减少样板代码的编写,可以在各种Android版本和设备中一致运行的代码,让开发者精力集中编写重要的代码。
jetpack与AndroidX
AndroidX命名空间中包含Android Jetpack库
AndroidX替代了Android Support Library
AAC(Android Architecture Component)中的组件并入了AndroidX
二,相关组件知识
1,LifeCycle
LifeCycle的诞生是为了解决解耦页面和组件的问题。
使用Lifecycle的好处是:帮助开发者建立感知生命周期的组件。组件在其内部管理自己的生命周期,从而降低耦合度。降低内存泄漏发生的可能性。Activity,Fragment,Service,Application均有lifecycle的支持
- 使用Lifecycle解耦页面和组件
自定义控件实现LifecycleObserver,
public class MyChronometer extends Chronometer implements LifecycleObserver {
private long elapsedTime;
public MyChronometer(Context context, AttributeSet attrs) {
super(context, attrs);
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
private void startMeter(){
setBase(SystemClock.elapsedRealtime() - elapsedTime);
start();
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
private void stopMeter(){
elapsedTime = SystemClock.elapsedRealtime() - getBase();
stop();
}
}
public class Step2Activity extends AppCompatActivity {
private MyChronometer chronometer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
chronometer = findViewById(R.id.chronometer);
// 在页面中添加监听
getLifecycle().addObserver(chronometer);
}
}
- 使用LifecycleService解耦Service与组件
举例如下:获取位置监听,首先创建一个MyLocationObserver,实现LifecycleObserver
public class MyLocationObserver implements LifecycleObserver {
private Context context;
private LocationManager locationManager;
private MyLocationListener locationListener;
public MyLocationObserver(Context context) {
this.context = context;
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
private void startGetLocation() {
Log.d("ning","startGetLocation");
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
locationListener = new MyLocationListener();
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 3000, 1, locationListener);
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
private void stopGetLocation() {
Log.d("ning","stopGetLocation");
locationManager.removeUpdates(locationListener);
}
static class MyLocationListener implements LocationListener{
@Override
public void onLocationChanged(Location location) {
Log.d("ning","location changed:"+location.toString());
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
}
}
然后在定义Service实现LifecycleService
public class MyLocationService extends LifecycleService {
public MyLocationService() {
Log.d("ning","MyLocationService");
MyLocationObserver observer = new MyLocationObserver(this);
getLifecycle().addObserver(observer);
}
}
最后正常开启服务
public void startGps(View view) {
startService(new Intent(this,MyLocationService.class));
}
public void stopGps(View view) {
stopService(new Intent(this,MyLocationService.class));
}
- 使用ProcessLifecycleOwner监听应用程序生命周期
针对整个应用程序的监听,与Activity数量无关。
Lifecycle.Event.ON_CREATE只会被调用一次,Lifecycle.Event.ON_DESTROY永远不会被调用
代码如下,首先创建ApplicationObserver,实现LifecycleObserver
public class ApplicationObserver implements LifecycleObserver {
private String TAG = "ning";
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onCreate() {
Log.d(TAG, "Lifecycle.Event.ON_CREATE");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart() {
Log.d(TAG, "Lifecycle.Event.ON_START");
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
Log.d(TAG, "Lifecycle.Event.ON_RESUME");
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
Log.d(TAG, "Lifecycle.Event.ON_PAUSE");
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onStop() {
Log.d(TAG, "Lifecycle.Event.ON_STOP");
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroy() {
Log.d(TAG, "Lifecycle.Event.ON_DESTROY");
}
}
然后在MyAppliaction的调用代码如下
public class MyApplication extends Application{
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle()
.addObserver(new ApplicationObserver());
}
}
2,ViewModel
ViewModel能够解决常见的三个问题
1),瞬态数据丢失
2),异步调用的内存泄漏
3),类膨胀提高维护难度和测试难度。
ViewModel是介于视图View和数据模型Model之间的桥梁,能够使视图和数据分离也能够保持通信
viewmodel的生命周期特性独立于配置变化。
使用注意点,不要向viewmodel中传入Context,会到导致内存泄漏。如果要使用Context,要使用AndroidViewModel的Application。
VM使用代码如下,自定义一个ViewModel继承ViewModel
public class MyViewModel extends AndroidViewModel {
public int number;
public MyViewModel(@NonNull Application application) {
super(application);
}
}
public class MainActivity extends AppCompatActivity {
private TextView textView;
private MyViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(MyViewModel.class);
textView.setText(String.valueOf(viewModel.number));
}
public void plusNumber(View view) {
textView.setText(String.valueOf(++viewModel.number));
}
}
3,LiveData
LiveData和ViewModel的关系是在ViewModel中的数据发生变化时通知页面。
LiveData的优势有以下几点
1)确保界面数据合理状态
2)不会发生内存泄漏
3)不会因Activity停止而导致崩溃
4)不再需要手动处理生命周期
5)数据始终保持最新状态
6)适当的配置更改
7)共享资源
····
代码如下,创建一个ViewModel
public class MyViewModel extends ViewModel {
private MutableLiveData currentSecond;
public MutableLiveData getCurrentSecond() {
if(currentSecond == null){
currentSecond = new MutableLiveData<>();
currentSecond.setValue(0);
}
return currentSecond;
}
}
下面是Activity中的代码
public class MainActivity extends AppCompatActivity {
private MyViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = findViewById(R.id.textView);
viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(MyViewModel.class);
textView.setText(String.valueOf(viewModel.getCurrentSecond().getValue()));
viewModel.getCurrentSecond().observe(this, new Observer() {
@Override
public void onChanged(Integer i) {
textView.setText(String.valueOf(i));
}
});
startTimer();
}
private void startTimer() {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
//非UI线程 postValue
//UI线程 setValue
viewModel.getCurrentSecond().postValue(viewModel.getCurrentSecond().getValue()+1);
}
},1000,1000);
}
}
4,DataBinding
- 让布局文件承担了部分原本属于页面的工作,使页面与布局耦合度进一步降低
自定义BindingAdapter
加载网络图片。
方法重载,加载本地图片。
多参数重载。
布局文件中的代码如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);
Idol idol = new Idol("斯嘉丽.约翰逊",4);
activityMainBinding.setIdol(idol);
activityMainBinding.setEventHandle(new EventHandleListener(this));
}
public class EventHandleListener {
private Context context;
public EventHandleListener(Context context) {
this.context = context;
}
public void buttonOnClick(View view){
Toast.makeText(context,"喜欢",Toast.LENGTH_SHORT).show();
}
}
当布局文件用到include引用布局的时候怎样传递数据类。
首先是activity_main.xml
sub.xml文件代码入下
自定义BindAdapter代码如下
public class ImageViewBindingAdapter {
//加载网络图片
@BindingAdapter("image")
public static void setImage(ImageView imageView, String url){
if(!TextUtils.isEmpty(url)){
Picasso.get()
.load(url)
.placeholder(R.drawable.ic_launcher_background)
.into(imageView);
}else{
imageView.setBackgroundColor(Color.GRAY);
}
}
//加载本地图片
@BindingAdapter("image")
public static void setImage(ImageView imageView, int resId){
imageView.setImageResource(resId);
}
//参数可选,网络图片为空时,加载本地图片
@BindingAdapter(value = {"image", "defaultImageResource"}, requireAll = false)
public static void setImage(ImageView imageView, String url, int resId){
if(!TextUtils.isEmpty(url)){
Picasso.get()
.load(url)
.placeholder(R.drawable.ic_launcher_background)
.into(imageView);
}else{
imageView.setImageResource(resId);
}
}
}
- 双向绑定
BaseObservable与ObservableFiled
BaseObservable示例代码如下
public class UserViewModel extends BaseObservable {
private User user;
public UserViewModel(){
this.user = new User("Jack");
}
@Bindable
public String getUserName(){
return user.userName;
}
public void setUserName(String userName){
if(userName != null && !userName.equals(user.userName)){
user.userName = userName;
Log.d("ning","set username:"+userName);
notifyPropertyChanged(BR.userName);
}
}
}
ObservableFiled的示例代码
public class UserViewModel {
private ObservableField userObservableField;
public UserViewModel(){
User user = new User("Jack");
userObservableField = new ObservableField<>();
userObservableField.set(user);
}
public String getUserName(){
return userObservableField.get().userName;
}
public void setUserName(String userName){
Log.d("ning","userObservableField:"+userName);
userObservableField.get().userName = userName;
}
}
- RecyclerView的绑定
Adapter适配器中的代码如下:
public class RecyclerViewAdapter extends RecyclerView.Adapter {
List idols;
public RecyclerViewAdapter(List idols) {
this.idols = idols;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemBinding itemBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
R.layout.item,
parent,
false);
return new MyViewHolder(itemBinding);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Idol idol = idols.get(position);
holder.itemBinding.setIdol(idol);
}
@Override
public int getItemCount() {
return idols.size();
}
static class MyViewHolder extends RecyclerView.ViewHolder{
private ItemBinding itemBinding;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
}
public MyViewHolder(ItemBinding itemBinding) {
super(itemBinding.getRoot());
this.itemBinding = itemBinding;
}
}
}
- DataBinding的优势
不需要findViewById,项目更加简洁,可读性更高
布局文件可以包含简单的业务逻辑