文章目录
Android基础
学习 Android 开发可以类比成盖房子。想要盖一座漂亮的房子,需要掌握以下知识点:
- Java 基础知识:Java 就像是建筑工人的工具,工人需要熟练使用这些工具才能盖出好的房子。
- Android 开发基础:Android 里的布局和 UI 控件就像是在房子里安装地板、门窗、灯具等装饰物,让房子更美观舒适。
- 数据存储:SQLite 数据库就像是仓库,里面可以保存各种零散的材料,需要时可以去取出来使用。
- 网络编程:网络编程就像是房子里的管道和电线,让不同的房子之间可以互相连接和通信。Web 服务、HTTP 请求、JSON 解析、XML 解析、Restful API 设计等如同建筑工人需要了解建筑规范、图纸等信息。
- 多媒体应用:多媒体应用就像是在房子里加入音响、电视等设备,让住宅变得更加智能化。
- 高级主题:服务(Service)、广播接收器(Broadcast Receiver)、内容提供者(Content Provider)、通知(Notification)、定位(Location)等,就是房子里各种高级功能的添加,让房子变得更加实用和舒适。
在学习过程中需要注意一下几点:
- 布局:Android 中有多种布局方式,类比成在地上摆设家具,不同的房间需要选用合适的家具。
- 生命周期:Activity 有生命周期,就像是人的生命周期一样,需要依据不同的生命周期来进行合理的处理。
- 异步编程:异步编程就像是在房子后面修建一个工作坊一样,让一些耗时的操作在工作坊里面进行,不影响正常居住。
- 内存管理:内存管理就像是在房子里管理垃圾一样,要及时清理一些无用的东西,避免占用过多的空间。
综上所述,学习 Android 开发就像是在盖一座漂亮的房子,需要认真学习每一个知识点,并且不断实践和积累经验。
在学习过程中容易混淆的地方有:
- 布局:Android 中有多种布局方式,如线性布局、相对布局、网格布局等,每种布局方式都有其适用的地方。
- 生命周期:Activity 有生命周期,如创建、启动、暂停、恢复、停止和销毁等状态,开发人员需要掌握每个生命周期的具体作用。
- 异步编程:Android 中的 UI 操作必须在主线程中完成,因此对于一些耗时的操作,应该使用异步处理方式(AsyncTask),而不是直接在主线程中进行。
- 内存管理:Android 应用程序运行在移动设备上,内存资源有限,因此需要合理管理内存资源,避免应用程序出现内存泄漏等问题。
总之,学习 Android 开发需要掌握 Java 编程语言的基础知识,并深入学习 Android 平台的特点和开发技术。需要认真学习每一个知识点,多做实践和项目练习,不断积累经验。
Android 是一个开放源代码的移动操作系统,它包含许多不同的知识点,下面是一些通俗易懂的比喻来描述它们:
- Android 系统架构:Android 系统就像是一个大楼,它由不同的层构成,每层都有不同的功能和职责。
- Android 应用程序组成:Android 应用程序就像是楼里的小房间,每个房间有不同的用途和功能。
- Android 布局:Android 布局就像是在房间里摆放家具,不同的家具摆放可以影响整个房间的风格和使用感受。
- Android UI 控件:Android UI 控件就像是房间里的各种装饰物,如门窗、墙纸、地毯等,不同的控件可以让应用程序的界面更加美观和易用。
- Android 活动(Activity):Android 活动就像是在不同的房间之间切换,当用户从一个房间移动到另一个房间时,需要进行一些特定的操作。
- Android 意图(Intent):Android 意图就像是在不同的房间中传递信息,通过意图可以启动不同的活动,并将数据传递给其他的应用程序。
- Android 数据存储:Android 数据存储就像是在房间里放置和管理文件或者书籍,可以将数据存储到本地或者云端,并进行读写操作。
- Android 网络编程:Android 网络编程就像是在房子里安装网络设备,可以连接到互联网并获取或上传数据。
- Android 多媒体应用:Android 多媒体应用就像是在房子里使用各种音响、电视等设备,可以处理音频、视频和图片等多媒体资源。
- Android 高级主题:Android 高级主题就像是在楼里添加一些高级功能,如电梯、警报系统等,可以增强底层功能和用户体验。
总之,Android 包含许多不同的知识点,但是通过通俗易懂的比喻,我们可以更加生动形象地描述它们。
Fragment 和 Activity
Fragment 和 Activity 都是 Android 开发中常用的组件,它们有以下不同点:
- 管理方式:Activity 是整个应用程序的窗口,负责管理和显示应用程序的界面和交互逻辑;而 Fragment 则是在一个 Activity 中的部分窗口区域,可以单独管理自己的界面和逻辑。
- 重用性:Fragment 可以被多个 Activity 共享使用,而 Activity 则只能在整个应用程序中单独使用。
- 生命周期:Activity 和 Fragment 都有自己的生命周期,但是生命周期的触发时机和顺序不同。
- 界面布局:Activity 可以单独设置自己的布局文件,而 Fragment 的布局则需要使用在 Activity 中声明的容器进行显示。
推荐使用哪个组件取决于具体的应用场景。一般来说,当我们需要管理大量的界面和交互逻辑时,应该使用 Activity;当我们需要在一个活动中处理多个可独立操作的界面时,应该使用 Fragment。
例如,在一个购物应用中,Activity 可以用来管理主界面、搜索界面、购物车界面等等;而在购物车界面中,由于可能存在大量订单数据以及多种付款方式,我们可以使用 Fragment 来管理下单界面、选择付款方式界面等子界面,并且这些子界面也可以被其他 Activity 共享使用。
总之,Android 开发中 Fragment 和 Activity 都是非常重要的组件,我们需要根据具体的应用场景进行选择和使用。
onCreate() | 这是第一个回调,在活动第一次创建时调用 |
---|---|
onStart() | 这个回调在活动为用户可见时被调用 |
onResume() | 这个回调在应用程序与用户开始可交互的时候调用 |
onPause() | 被暂停的活动无法接受用户输入,不能执行任何代码。当前活动将要被暂停,上一个活动将要被恢复时调用 |
onStop() | 当活动不在可见时调用 |
onDestroy() | 当活动被系统销毁之前调用 |
onRestart() | 当活动被停止以后重新打开时调用 |
gradle是什么、需要注意什么
Gradle是一款基于Groovy语言的构建工具,它既可以用来构建Java项目,也可以用来构建其他类型的项目。Gradle最初是为了解决构建复杂大型软件项目的问题而设计的,它可以自动化执行各种编译、测试和打包等任务,使得软件开发人员可以更加高效地管理和构建项目。
使用Maven时,只要确保依赖项版本相同,即使使用不同版本的Maven,也可以正常构建项目。这是因为Maven本身的主要职责是管理和协调各种依赖项,并在构建过程中将它们集成到最终的构建结果中,而Maven默认会下载相应的依赖项并将其放到一个本地仓库中,供项目使用。因此,只要依赖项版本匹配,Maven就可以正确地找到和使用相应的库。
但是与Maven不同的是,Gradle是基于Groovy语言的DSL(领域特定语言)构建工具,Gradle使用Groovy脚本来进行构建任务和依赖管理。由于Gradle版本之间存在一些API和功能上的差异,如果使用不同版本的Gradle,可能会导致构建失败或者其他问题。因此,为了避免这种情况的发生,我们建议在使用Gradle进行构建的时候,也应该尽量使用同一个版本的Gradle。
ActivityResultLauncher替代startActivityForResult
startActivityForResult() 和 ActivityResultLauncher 都是用于启动一个 Activity
并等待其返回结果的 API。startActivityForResult() 方法允许你启动另一个 Activity,并希望在那个 Activity
执行完毕后返回一些数据。一旦启动了另一个 Activity 并且设置了 setResult() 方法,新的 Activity
就会被关闭,并将结果返回到调用方 Activity 中的 onActivityResult() 方法中。而 ActivityResultLauncher 是一个基于回调函数的新 API,它是 startActivityForResult()
方法的现代替代品。相比之下,ActivityResultLauncher 更加强大、更加安全、更容易使用。它不仅可以启动其他的
Activity,还可以启动其他的 Intent-based Use Case,如请求权限、选择文件、选择图片等等。通过注册一个监听器来接收结果,我们可以清晰地理解该 Use Case,而且代码的可读性更好。
使用 startActivityForResult(),当调用其他应用程序的 Activity 时,应用程序会等待该 Activity
执行完毕后再返回到自己的 Activity。在此期间,整个应用程序都被暂停,这可能会导致用户体验不佳。另外, startActivityForResult() 还需要进行参数传递和结果接收等操作,代码实现起来也相对复杂。而且,在
Android 11 及以上版本中, startActivityForResult() 还受到了更大限制,不再允许在一些情况下使用。为了解决这些问题,Google 推出了一个新的 API:ActivityResultLauncher。该 API
显式地将批准权限的范围限制在特定的 Activity 请求中,并提高了代码的可读性和易用性。而且,与
startActivityForResult() 不同的是,ActivityResultLauncher
是非阻塞式的,不会导致应用程序被暂停。因此,开发者们应该尽量使用新的 API 以提高安全性和用户体验。
// 结束触发
mScanBarcodeLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK && result.getData() != null) {
String barcode = result.getData().getStringExtra("barcode");
Toast.makeText(this, barcode, Toast.LENGTH_SHORT).show();
}
}
);
// 启动新活动窗体
Intent intent = new Intent(MainActivity.this, BarActivity.class);
mScanBarcodeLauncher.launch(intent);
// 结束
Intent intent = new Intent();
intent.putExtra("barcode", barcode.getRawValue());
setResult(RESULT_OK, intent);
finish();
三种回调方法
- 使用接口回调:这是最常见和简单的回调机制。定义一个接口,在需要回调的地方实现该接口,并在合适的时候调用接口方法触发回调。这种方式适用于简单的回调需求。
//当使用接口回调时的一个示例是一个简单的计时器应用。假设你希望在计时结束后触发某个操作,可以通过接口回调来实现。
//首先,定义一个接口 `TimerCallback` 用于回调计时结束事件:
```java
public interface TimerCallback {
void onTimerFinished();
}
然后,在计时器类中添加一个方法 startTimer()
来启动计时器,并在计时结束时触发回调:
public class Timer {
private TimerCallback callback;
public void setTimerCallback(TimerCallback callback) {
this.callback = callback;
}
public void startTimer(int duration) {
// 启动计时器逻辑
new CountDownTimer(duration, 1000) {
public void onTick(long millisUntilFinished) {
// 每秒执行的逻辑
}
public void onFinish() {
// 计时结束后触发回调
if (callback != null) {
callback.onTimerFinished();
}
}
}.start();
}
}
接下来,在需要使用计时器的地方实现 TimerCallback
接口,并在回调方法 onTimerFinished()
中处理计时结束事件:
public class MainActivity implements TimerCallback {
private Timer timer;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
timer = new Timer();
timer.setTimerCallback(this);
// 启动计时器
timer.startTimer(5000);
}
// 重写实现 TimerCallback 接口的方法
public void onTimerFinished() {
// 计时结束后的逻辑
runOnUiThread(() -> {
// 在UI线程更新UI或执行其他操作
Toast.makeText(MainActivity.this, "计时结束", Toast.LENGTH_SHORT).show();
});
}
}
在这个示例中,通过接口回调的方式,当计时器结束时,onTimerFinished()
方法会被调用,并在回调方法中执行相应的逻辑,这里是显示一个Toast提示计时结束。
需要注意的是,在使用接口回调时,请确保在正确的时机设置回调对象,并在合适的地方调用回调方法,以确保回调逻辑能够正确触发。同时,根据具体需求,可以在回调方法中在UI线程上执行相关操作。
- 匿名内部类/Lambda表达式回调:
// 创建 BarcodeActivity 实例
barcodeActivity = new BarcodeActivity();
// 设置扫码结果回调,匿名内部类
barcodeActivity.setOnScanResultListener(new BarcodeActivity.OnScanResultListener() {
@Override
public void onScanResult(String result) {
// 处理扫码结果
Log.d("MainActivity", "扫码结果: " + result);
Toast.makeText(MainActivity.this, "扫码结果: " + result, Toast.LENGTH_SHORT).show();
}
});
// 设置扫码结果回调,Lambda表达式
// barcodeActivity.setOnScanResultListener(result -> {
// 处理扫码结果
// Log.d("MainActivity", "扫码结果: " + result);
// Toast.makeText(MainActivity.this, "扫码结果: " + result, Toast.LENGTH_SHORT).show();
// });
// 启动扫码
barcodeActivity.startScan();
// 使用回调接口(Callback Interface)来实现回调
public class BarcodeActivity {
private OnScanResultListener listener;
public interface OnScanResultListener {
void onScanResult(String result);
}
public void setOnScanResultListener(OnScanResultListener listener) {
this.listener = listener;
}
public void startScan() {
// 模拟扫描得到结果
String result = "123456";
// 触发回调
if (listener != null) {
listener.onScanResult(result);
}
}
}
// 使用Java提供的函数式接口(如Consumer、BiConsumer等)来定义回调函数接口
class BarcodeActivity {
private Consumer<String> listener;
public void setOnScanResultListener(Consumer<String> listener) {
this.listener = listener;
}
public void startScan() {
// 模拟扫描得到结果
String result = "123456";
// 触发回调
if (listener != null) {
listener.accept(result);
}
}
}
- 观察者模式实现回调:观察者模式是一种设计模式,可以用于实现回调机制。在观察者模式中,有两个角色:观察者和被观察者。当被观察者的状态发生变化时,它会通知所有注册的观察者,并且观察者会根据被观察者的通知执行相应的操作。
import java.util.ArrayList;
import java.util.List;
// 被观察者接口
interface Observable {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers(String data);
}
// 观察者接口
interface Observer {
void update(String data);
}
// 被观察者类
class BarcodeScanner implements Observable {
private List<Observer> observers = new ArrayList<>();
@Override
public void addObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers(String data) {
for (Observer observer : observers) {
observer.update(data);
}
}
public void startScanning() {
// 模拟扫码得到结果
String result = "123456";
// 通知观察者
notifyObservers(result);
}
}
// 观察者类
class User implements Observer {
private String name;
public User(String name) {
this.name = name;
}
@Override
public void update(String data) {
System.out.println(name + "收到扫码结果: " + data);
}
}
// 示例代码
public class Example {
public static void main(String[] args) {
// 创建被观察者对象
BarcodeScanner scanner = new BarcodeScanner();
// 创建观察者对象
User user1 = new User("用户1");
User user2 = new User("用户2");
// 注册观察者
scanner.addObserver(user1);
scanner.addObserver(user2);
// 启动扫描
scanner.startScanning();
// 取消注册观察者
scanner.removeObserver(user2);
// 再次启动扫描
scanner.startScanning();
}
}