Android
考试复习
简答题
五层架构
官网:https://developer.android.google.cn/guide/platform?hl=zh-cn
从上往下:
- 应用层(System Apps):系统应用层,系统内置的应用程序以及非系统级的应用程序,如相机,日历,支付宝,微信
- 应用架构层(Java API Framework):为开发人员提供了开发应用程序所需要的API,这一层是由Java代码编写的,可以称为Java Framework,如Activity Manager,Resource Manager
- 系统运行库:Native C/C++ Libraries:C/C++程序库,Android Runtime:Android运行时库。许多核心 Android 系统组件和服务(例如 ART 和 HAL)构建自原生代码,需要以 C 和 C++ 编写的原生库。Android 平台提供 Java 框架 API 以向应用显示其中部分原生库的功能。Android Runtime:运行时库 , Dalvik虚拟机是Google等厂商合作开发的Android移动设备平台的核心组成部分之一
- Hardware Abstraction Layer:硬件抽象层(HAL):提供标准界面,向更高级别的 Java API 框架显示设备硬件功能。
- Linux Kernel:Linux内核层。Android 的核心系统服务基于Linux 内核,在此基础上添加了部分Android专用的驱动。系统的安全性、内存管理、进程管理、网络协议栈和驱动模型等都依赖于该内核。
进程与线程
官网:https://developer.android.google.cn/guide/components/processes-and-threads?hl=zh-cn
当应用组件启动且该应用未运行任何其他组件时,Android 系统会使用单个执行线程为应用启动新的 Linux 进程。默认情况下,同一应用的所有组件会在相同的进程和线程(称为“主”线程)中运行。
启动应用时,系统会为该应用创建一个称为“main”(主线程)的 执行线程。此线程非常重要,因为其负责将事件分派给相应的界面微件,其中包括绘图事件。此外,应用与 Android 界面工具包组件(来自 android.widget
和 android.view
软件包的组件)也几乎都在该线程中进行交互。因此,主线程有时也称为界面线程。但在一些特殊情况下,应用的主线程可能并非其界面线程
系统不会为每个组件实例创建单独的线程。在同一进程中运行的所有组件均在界面线程中进行实例化,并且对每个组件的系统调用均由该线程进行分派。因此,响应系统回调的方法(例如,报告用户操作的 onKeyDown()
或生命周期回调方法)始终在进程的界面线程中运行。例如,当用户轻触屏幕上的按钮时,应用的界面线程会将轻触事件分派给微件,而微件转而会设置其按下状态,并将失效请求发布到事件队列中。界面线程从队列中取消该请求,并通知该微件对其自身进行重绘。
当应用执行繁重的任务以响应用户交互时,除非您正确实现应用,否则这种单线程模式可能会导致性能低下。具体地讲,如果界面线程需要处理所有任务,则执行耗时较长的操作(例如,网络访问或数据库查询)将会阻塞整个界面线程。一旦被阻塞,线程将无法分派任何事件,包括绘图事件。从用户的角度来看,应用会显示为挂起状态。更糟糕的是,如果界面线程被阻塞超过几秒钟时间(目前大约是 5 秒钟),用户便会看到令人厌烦的“应用无响应”(ANR) 对话框。如果引起用户不满,他们可能就会决定退出并卸载此应用。
此外,Android 界面工具包并非线程安全工具包。所以您不得通过工作线程操纵界面,而只能通过界面线程操纵界面。因此,Android 的单线程模式必须遵守两条规则:
- 不要阻塞 UI 线程
- 不要在 UI 线程之外访问 Android UI 工具包
考试要考这两点
使用 AsyncTask
AsyncTask
允许对界面执行异步操作。它会先阻塞工作线程中的操作,然后在界面线程中发布结果,而无需您亲自处理线程和/或处理程序。
如要使用该类,您必须创建 AsyncTask
的子类并实现 doInBackground()
回调方法,该方法会在后台线程池中运行。如要更新界面,您应实现 onPostExecute()
(该方法会传递 doInBackground()
返回的结果并在界面线程中运行),以便安全更新界面。然后,您可以通过从界面线程调用 execute()
来运行任务。
public class MainActivity extends AppCompatActivity {
private ProgressBar bar = null;
private String filename;
private DownloadTask downloadtask = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置布局文件
setContentView(R.layout.activity_main);
// 初始化进度条
bar = (ProgressBar) findViewById(R.id.progressBar);
}
// 点击下载按钮触发的方法
public void onDownload(View v) {
// 设置要下载的文件名
filename = "test.bmp";
// 创建并执行下载任务
downloadtask = new DownloadTask();
downloadtask.execute(filename);
}
// 点击取消按钮触发的方法
public void onCancel(View v) {
// 取消当前下载任务
downloadtask.cancel(false);
}
// 自定义的异步任务类,继承自AsyncTask
class DownloadTask extends AsyncTask<String, Integer, Boolean> {
// 后台线程执行文件下载操作
@Override
protected Boolean doInBackground(String... params) {
// 输出日志,表示开始下载文件
Log.i("MyTest", "开始下载文件:" + params[0]);
// 模拟文件下载过程,循环执行100次
for (int i = 1; i <= 100; i++) {
// 检查任务是否被取消
if (isCancelled()) {
return false;
}
// 输出日志,表示下载进度
Log.i("MyTest", "下载进度:" + i);
try {
// 模拟文件下载过程中的延迟
Thread.sleep(20);
} catch (InterruptedException e) {
// 异常处理
e.printStackTrace();
}
// 以当前的i模拟已经下载的文件大小,通知UI更新下载进度
publishProgress(i);
}
// 下载完成,返回true
return true;
}
// 执行任务前的准备工作
@Override
protected void onPreExecute() {
super.onPreExecute();
}
// 任务执行完成后的处理
@Override
protected void onPostExecute(Boolean result) {
// 根据下载结果显示相应的提示信息
if (result) {
Toast.makeText(getApplicationContext(), "文件下载成功", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(), "文件下载失败", Toast.LENGTH_LONG).show();
}
super.onPostExecute(result);
}
// 更新下载进度时调用,用于更新UI上的ProgressBar
@Override
protected void onProgressUpdate(Integer... values) {
bar.setProgress(values[0]);
super.onProgressUpdate(values);
}
// 任务被取消时的处理
@Override
protected void onCancelled(Boolean result) {
// 显示取消下载的提示信息
Toast.makeText(getApplicationContext(), "文件下载取消", Toast.LENGTH_SHORT).show();
// 将ProgressBar重置为0
bar.setProgress(0);
super.onCancelled(result);
}
}
}
线程安全:
博客:连接
public class MainActivity2 extends AppCompatActivity {
private TextView cxk;
private int count =1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
cxk = findViewById(R.id.text);
new Timer().schedule(new TimerTask() {
@Override
public void run() {
myHandler.sendEmptyMessage(1);
}
}, 0,200);
}
final Handler myHandler = new Handler() {
@Override
//重写handleMessage方法,根据msg中what的值判断是否执行后续操作
public void handleMessage(Message msg) {
if (msg.what == 1) {
//更新UI
String res=String.valueOf(count++);
cxk.setText(res);
}
}
};
}
JVM
官网:https://source.android.google.cn/docs/core/runtime/jit-compiler?hl=zh-cn
华为的:https://developer.harmonyos.com/cn/develop/arkCompiler/
相关内容:https://zhuanlan.zhihu.com/p/53723652
在编译打包生成APK文件时,会有这样一个流程:
- Java编译器将Java文件编译为class文件
- dx工具将编译输出的类文件转换为dex文件(Android虚拟机不支持class文件)
而Android虚拟机有两种:Dalvik和ART,JIT与AOT是虚拟机为了提高运行效率等采用的不同的编译策略。
JIT意思是Just In Time Compiler,就是即时编译技术,与Dalvik虚拟机相关。
Dalvik虚拟机可以看做是一个Java虚拟机。在 Android系统初期,每次运行程序的时候,Dalvik负责将dex翻译为机器码交由系统调用。这样有一个缺陷:每次执行代码,都需要Dalvik将操作码代码翻译为机器对应的微处理器指令,然后交给底层系统处理,运行效率很低。
为了提升效率Android在2.2版本中添加了JIT编译器,当App运行时,每当遇到一个新类,JIT编译器就会对这个类进行即时编译,经过编译后的代码,会被优化成相当精简的原生型指令码(即native code),这样在下次执行到相同逻辑的时候,速度就会更快。JIT 编译器可以对执行次数频繁的 dex/odex 代码进行编译与优化,将 dex/odex 中的 Dalvik Code(Smali 指令集)翻译成相当精简的 Native Code 去执行,JIT 的引入使得 Dalvik 的性能提升了 3~6 倍。
AOT是指"Ahead Of Time",与"Just In Time"不同,从字面来看是说提前编译。
JIT是运行时编译,是动态编译,可以对执行次数频繁的dex代码进行编译和优化,减少以后使用时的翻译时间,虽然可以加快Dalvik运行速度,但是有一个很大的问题:将dex翻译为本地机器码也要占用时间。 所以Google在4.4推出了全新的虚拟机运行环境ART(Android RunTime),用来替换Dalvik(4.4上ART和Dalvik共存,用户可以手动选择,5.0 后Dalvik被替换)。
AOT 是静态编译,应用在安装的时候会启动 dex2oat 过程把 dex预编译成 ELF 文件,每次运行程序的时候不用重新编译。 ART 对 Garbage Collection(GC)过程的也进行了改进:
- 只有一次 GC 暂停(Dalvik 需要两次)
- 在 GC 保持暂停状态期间并行处理
- 在清理最近分配的短时对象这种特殊情况中,回收器的总 GC 时间更短
- 优化了垃圾回收的工效,能够更加及时 地进行并行垃圾回收,这使得 GC_FOR_ALLOC 事件在典型用例中极为罕见
- 压缩 GC 以减少后台内存使用和碎片
Fragment
生命周期:
切换横竖屏之后生命周期变化: 博客:https://blog.csdn.net/jaynm/article/details/104560439
默认生命周期:onCreate -->onStart–>onResumeo -->onPause -->onStop -->onDestroy
调试快捷键
博客:https://blog.csdn.net/ljc1026774829/article/details/80493699
快捷键 | 介绍 |
---|---|
F7 | 进入函数 |
Shift + F7 | 进入函数,如果断点所在行上有多个方法调用,会弹出进入哪个方法 |
F8 | 进入下一步,如果当前行断点是一个方法,则不进入当前方法体内 |
F9 | 恢复程序运行,但是如果该断点下面代码还有断点则停在下一个断点上 |
F10 | 执行到光标处 |
Alt + F8 | 选中对象,弹出可输入计算表达式调试框,查看该输入内容 的调试结果 |
Shift + F8 | 跳出当前函数 |
Intent意图
博客:https://blog.csdn.net/JMW1407/article/details/114932159
程序设计题
考实验 五、六
实验五
MainActivity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragment_list);
if (fragment == null) {
fragment = new StudentListFragment();
fm.beginTransaction()
.add(R.id.fragment_list, fragment)
.commit();
}
}
}
Student
public class Student {
private String id;
private String name;
private String phone;
private Integer imageId;
//of构造方法
public static Student of(String id, String name, String phone, Integer imageId) {
return new Student(id, name, phone, imageId);
}
public Student(String id, String name, String phone, Integer imageId) {
this.id = id;
this.name = name;
this.phone = phone;
this.imageId = imageId;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Integer getImageId() {
return imageId;
}
public void setImageId(Integer imageId) {
this.imageId = imageId;
}
}
StudentListFragment
public class StudentListFragment extends Fragment {
private EditText inputId;
private EditText inputName;
private EditText inputPhone;
private ImageView inputImage;
private Button inputAdd;
private StudentAdapter studentAdapter;
private List<Student> students;
private RecyclerView recyclerView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_student_list, container, false);
init(view);
updateUI();
return view;
}
private void updateUI() {
students = new ArrayList<>();
Student student = Student.of("21200107230", "蔡徐坤", "12345678901", R.drawable.cxk2);
students.add(student);
studentAdapter = new StudentAdapter();
recyclerView.setAdapter(studentAdapter);
}
@Override
public void onResume() {
super.onResume();
updateUI();
}
private void init(View view) {
recyclerView = view.findViewById(R.id.student_list_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
inputId = view.findViewById(R.id.input_id);
inputName = view.findViewById(R.id.input_name);
inputPhone = view.findViewById(R.id.input_phone);
inputImage = view.findViewById(R.id.input_image);
inputAdd = view.findViewById(R.id.btn_add);
inputAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String id = inputId.getText().toString();
String name = inputName.getText().toString();
String phone = inputPhone.getText().toString();
Integer image = R.drawable.cxk;
Student student = Student.of(id, name, phone, image);
students.add(student);
studentAdapter.notifyDataSetChanged();
clearInput();
}
});
}
private void clearInput() {
inputId.setText("");
inputName.setText("");
inputPhone.setText("");
}
private class StudentAdapter extends RecyclerView.Adapter<StudentHolder> {
@NonNull
@Override
public StudentHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = View.inflate(getContext(), R.layout.item_student, null);
return new StudentHolder(view);
}
@Override
public void onBindViewHolder(@NonNull StudentHolder holder, @SuppressLint("RecyclerView") int position) {
holder.showId.setText(students.get(position).getId());
holder.showName.setText(students.get(position).getName());
holder.showPhone.setText(students.get(position).getPhone());
holder.showImage.setImageResource(students.get(position).getImageId());
//删除按钮
holder.btnDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
students.remove(position);
studentAdapter.notifyDataSetChanged();
}
});
//拨打电话按钮
holder.btnPhone.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//跳转到拨号界面
String phone = students.get(position).getPhone();
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phone));
startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return students.size();
}
}
public class StudentHolder extends RecyclerView.ViewHolder {
private TextView showId;
private TextView showName;
private TextView showPhone;
private ImageView showImage;
private Button btnDelete;
private Button btnPhone;
public StudentHolder(@NonNull View itemView) {
super(itemView);
showId = itemView.findViewById(R.id.show_id);
showName = itemView.findViewById(R.id.show_name);
showPhone = itemView.findViewById(R.id.show_phone);
showImage = itemView.findViewById(R.id.show_image);
btnDelete = itemView.findViewById(R.id.btn_del);
btnPhone = itemView.findViewById(R.id.btn_phone);
}
}
}
布局
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fragment_list"
tools:context=".MainActivity">
</androidx.constraintlayout.widget.ConstraintLayout>
fragment_student_list
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/fragment_container"
tools:context=".StudentListFragment">
<TextView
android:text="电话:"
android:layout_width="46dp"
android:layout_height="34dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="148dp"
android:layout_marginStart="16dp"
android:id="@+id/textView17"
android:textSize="16sp"/>
<TextView
android:text="学号:"
android:layout_width="46dp"
android:layout_height="34dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="16dp"
android:layout_marginStart="16dp"
android:id="@+id/textView16"
android:textSize="16sp"/>
<ImageView
android:src="@drawable/cxk"
android:layout_width="107dp"
android:layout_height="104dp"
tools:src="@tools:sample/avatars"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
android:id="@+id/input_image"/>
<Button
android:text="添加学生"
android:layout_width="104dp"
android:layout_height="51dp"
android:id="@+id/btn_add"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="16dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="128dp"/>
<TextView
android:text="姓名:"
android:layout_width="46dp"
android:layout_height="34dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="84dp"
android:layout_marginStart="16dp"
android:id="@+id/textView14"
android:textSize="16sp"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:ems="10"
android:id="@+id/input_id"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="4dp"
android:layout_marginStart="76dp"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:ems="10"
android:id="@+id/input_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="72dp"
android:layout_marginStart="76dp"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:ems="10"
android:id="@+id/input_phone"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="76dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="136dp"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/student_list_recycler_view"
android:layout_width="404dp"
android:layout_height="461dp"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="4dp"
app:layout_constraintTop_toBottomOf="@+id/input_phone"
android:layout_marginTop="44dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
item_student.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="89dp"
android:layout_height="98dp"
tools:srcCompat="@tools:sample/avatars"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:id="@+id/show_image"
android:layout_marginTop="12dp"
android:layout_marginStart="4dp"/>
<TextView
android:text="TextView"
android:layout_width="181dp"
android:layout_height="25dp"
app:layout_constraintTop_toTopOf="parent"
android:id="@+id/show_id"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="12dp"
android:layout_marginStart="100dp"/>
<TextView
android:text="TextView"
android:layout_width="181dp"
android:layout_height="27dp"
android:id="@+id/show_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="44dp"
android:layout_marginStart="100dp"/>
<TextView
android:text="TextView"
android:layout_width="180dp"
android:layout_height="30dp"
app:layout_constraintStart_toStartOf="parent"
android:id="@+id/show_phone"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="80dp"
android:layout_marginStart="100dp"/>
<Button
android:text="删除学生"
android:layout_width="97dp"
android:layout_height="43dp"
app:layout_constraintTop_toTopOf="parent"
android:id="@+id/btn_del"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="12dp"
android:layout_marginEnd="28dp"
app:layout_constraintStart_toEndOf="@+id/show_id"
app:layout_constraintHorizontal_bias="1.0"/>
<Button
android:text="拨打电话"
android:layout_width="98dp"
android:layout_height="47dp"
android:id="@+id/btn_phone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="60dp"
android:layout_marginEnd="28dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
实验六