本笔记基于B站视频教学以及安卓官方文档。BV号:BV1w4411t7UQ。受益匪浅,再次感谢。
Activity的生命周期
基本控件
MVC(Model-View-Controller)的设计模式。
TextView、Button、SeekBar、ImageView等等(参见开发者手册)。
点击事件:setOn...Listrner(new ...){...}
。
本地化Localization
更改系统语言,应用随之自动适配。
res->values->string.xml->Open Editor->Add Locale(左上角小地球)->Chinese zh
屏幕旋转
横向需要重新设置布局:Create Landscape Variationpubli
直接锁死竖屏:AndroidManifest.xml,<application>
下<activity>
中添加<android:screenOrientation="portrait">
ViewModel
减少不必要的代码冗余,使数据处理与UI分离,利于数据保存。
新建JavaClass:public class MyViewModel extends ViewModel {...}
MainActivity:
public class MainActivity extends AppCompatActivity {
MyViewModel myViewModel;
...;
@override
public void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
myViewModel = new ViewModelProvider(this).get(MyViewModel.class); //创建ViewModel对象
...;
}
}
关于Bundle A mapping from String keys to various Parcelable
values.
常用于Activity之间传递数据,并且数据存储形式key-value。
LiveData
官方解释:在底层数据库更改时通知视图。
*矢量图 New->Vector Asset(自带)。需要根据提示在Gradle里添加语句,否则会报错(与安卓API版本有关)。
新建ViewModel:
public class ViewModelWithLiveData extends ViewModel {
private MutableLiveData<Integer> number;
public MutableLiveData<Integer> getNumber() {
if (Number == null) { //number为对象类型,故要保证其非空
number = new MutableLiveData<>();
number.setvalue(0);
}
return number;
}
public void addNumber(int n) {
number.setValue(number.getValue() + 1);
}
}
MutableLiveData<>:LiveData
which publicly exposes setValue(T)
and postValue(T)
method.
MainActivity:
public class MainActivity extends AppCompatActivity {
ViewModelWithLiveData viewModelWithLiveData;
...;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...; //绑定等操作
viewModelWithLiveData = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(ViewModelWithLiveData.class);
viewModelWithLiveData.getNumber().observe(this, new Observer<Integer>() {//观察数据改变
@Override //this为具有LifeCycle管理功能的对象
public void onChanged(Integer integer) {
textView.setText(String.valueOf(integer));
}
});
...; //按钮点击事件
}
}
DataBinding
官方解释:以声明方式将可观察数据绑定到界面元素。
界面与代码的解耦。
build.gradle:
android {
...
defaultConfig {
...
dataBinding.enabled true
}
}
跳转至layout.xml界面,第一行代码提示,点击Convert to databing layout
<data>
<variable
name="data"
type="com.example.xxx.MyViewModel"/>
</data>
其中调用元素变量(数据回绑):android:text="@{String.valueOf(data.number)}"
,调用函数android:onClick="@{()->data.add()}
"
注意 数据回绑调用需要声明为public
MainActivity:
public class MainActivity extends AppCompatActivity {
MyViewModel myViewModel;
ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//实现数据的绑定与回绑
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
myViewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(MyViewModel.class);
binding.setData(myViewModel);
binding.setLifecycleOwner(this);
}
}
ViewModelProvider() An utility class that provides ViewModels
for a scope.
Default ViewModelProvider
for an Activity
or a Fragment
can be obtained from ViewModelProviders
class.
ViewModelProvider(ViewModelStoreOwner owner, ViewModelProvider.Factory factory)
ViewModelProvider.NewInstanceFactory() Simple factory, which calls empty constructor on the give class.
ViewModelSavedState
状态切换时的简单数据存储,使用SaveStateHandle
和SaveStateViewModelFactory()
SaveSateHandle SavedStateHandle
类是一个键值(key-value)对映射,用于通过 set()
和 get()
方法向已保存的状态写入数据以及从中检索数据。
SaveStateViewModelFactory() ViewModelProvider.Factory
that can create ViewModels accessing and contributing to a saved state via SavedStateHandle
received in a constructor.
SaveStateViewModelFactory(Application application, SaveStateRegistryOwner owner)
MyViewModel:
public class MyViewModel extends ViewModel {
private SavedStateHandle handle;
public MyViewModel(SavedStateHandle handle) {
this.handle = handle;
}
public MutableLiveData<Integer> getNumber() {
if (!handle.contains(MainActivity.KEY_NUMBER)) { //键值对应
handle.set(MainActivity.KEY_NUMBER, 0);
}
return handle.getLiveData(MainActivity.KEY_NUMBER);
}
...;
}
MainActivity:
public class MainActivity extends AppCompatActivity {
MyViewModel myViewModel;
ActivityMainBinding binding;
final static String KEY_NUMBER = "my_number";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
myViewModel = new ViewModelProvider(this, new SavedStateViewModelFactory(getApplication(), this)).get(MyViewModel.class);
binding.setData(myViewModel);
binding.setLifecycleOwner(this);
}
}
SharedPreferences
简单数据的永久存储。
SharedPreferences shp = Context.getSharedPreferences(String, int)
MyData:(Model)
public class MyData {
public int number;
private Context context;
public MyData(Context context) {
this.context = context;
}
public void save() {
String name = context.getResources().getString(R.string.MY_DATA);
SharedPreferences shp = context.getSharedPreferences(name, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = shp.edit();
String key = context.getResources().getString(R.string.MY_KEY);
editor.putInt(key, number);
editor.apply();
}
public int load() {
String name = context.getResources().getString(R.string.MY_DATA);
SharedPreferences shp = context.getSharedPreferences(name, Context.MODE_PRIVATE);
String key = context.getResources().getString(R.string.MY_KEY);
int x = shp.getInt(key, context.getResources().getInteger(R.integer.defValue));
number = x;
return x;
}
}
Context This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.Context是一个访问application环境全局信息的接口,通过它可以访问application的资源和相关的类。
该处用于MyData(其他类)获得MainActivity中的资源。
MainActivity:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyData myData = new MyData(getApplicationContext()); //不能传递this,可能导致内存泄漏
myData.number = 1000;
myData.save();
int y = myData.load();
String TAG = "myLog";
Log.d(TAG, "onCreate" + y);
}
}
AndroidViewModel
为ViewModel的子类,包含可直接访问context的方法。
Application context aware ViewModel
.Subclasses must have a constructor which accepts Application
as the only parameter.
getApplication()
直接访问全局资源。
MyViewModel:
public class MyViewModel extends AndroidViewModel {
private final SavedStateHandle handle;
private final String key = getApplication().getResources().getString(R.string.data_key);
private final String shpName = getApplication().getResources().getString(R.string.shp_name);
public MyViewModel(@NonNull Application application, SavedStateHandle handle) {
super(application); //必须要有
this.handle = handle;
if (!handle.contains(key)) {
load();
}
}
public LiveData<Integer> getNumber() {
return handle.getLiveData(key);
}
void load() {
SharedPreferences shp = getApplication().getSharedPreferences(shpName, Context.MODE_PRIVATE);
int x = shp.getInt(key, 0);
handle.set(key, x);
}
void save() {
SharedPreferences shp = getApplication().getSharedPreferences(shpName, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = shp.edit();
editor.putInt(key, getNumber().getValue());
editor.apply();
}
public void add(int x) {
handle.set(key, getNumber().getValue() + x);
//save(); //消耗时间
}
}
MainActivity:
public class MainActivity extends AppCompatActivity {
MyViewModel myViewModel;
ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
...;
}
@Override
protected void onPause() {
super.onPause();
myViewModel.save(); //每次Activity进入onPause()
}
}
Navigation
NavHost 容器
Fragement 实现屏幕小块内容,依存于Activity。用栈操作。
NavController 导航切换
NavGraph 图形化导航切换设计
页面切换
创建Fragement。例:HostFragement、DetailFragement
为了方便布局设置,可把FrameLayout
改成ConstraintLayout
图形化导航逻辑:New Resource File -> Navigation -> 左上角添加现有Fragement
activity_main.xml添加Containers -> NavHostFragement。
xxxFragement中添加onActivityCreated(@Nullable Bundle saveInstanceState)
,HostFragement:(点击按钮切换)
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Button button = getView().findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NavController controller = Navigation.findNavController(v);
controller.navigate(R.id.action_homeFragment_to_detailFragment);
}
});
}
DetailFragement:(点击按钮切换)
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getView().findViewById(R.id.button).
setOnClickListener(Navigation.createNavigateOnClickListener
(R.id.action_detailFragment_to_homeFragment));
}
MainActivity:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//导航栏名称改变
NavController controller = Navigation.findNavController(this, R.id.fragment);
NavigationUI.setupActionBarWithNavController(this, controller);
}
@Override
public boolean onSupportNavigateUp() { //导航返回键返回
NavController controller = Navigation.findNavController(this, R.id.fragment);
return controller.navigateUp();
//return super.onSupportNavigateUp();
}
}