Android开发基础(二)
上篇主要描述了Android系统架构,代码是通过Java表示的;
本篇将从介绍Android组件去理解Android开发,代码将对Java和Kotlin进行对比。
Android组件
Android应用程序由一些零散的有联系的组件组成,通过一个工程manifest绑定在一起;
他们基本可以拆分为Activities(活动)、Services(服务)、Content Providers(内容提供者)、Intent(意图)、Broadcast Receiver(广播接收器)、Notification(通知),分别对应不同的作用。
一、Activities
Activity代表一个单独的屏幕,用户可以与之交互;
每个Activity都有预定义的生命周期方法,如onCreate()、onStart()、 onResume()、 onPause()、 onStop() 和 onDestroy(),这些生命周期方法在Activity的不同状态被调用;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
setContentView(R.layout.activity_main);
// 在onCreate方法中初始化Activity
// 例如,可以设置布局、初始化变量等
}
@Override
protected void onStart() {
super.onStart();
// 在onStart方法中准备Activity的显示
// 例如,可以启动后台线程、加载数据等
}
@Override
protected void onResume() {
super.onResume();
// 在onResume方法中执行与用户交互的操作
// 例如,可以更新UI、处理用户输入等
}
@Override
protected void onPause() {
super.onPause();
// 在onPause方法中释放资源或保存数据
// 例如,可以停止后台线程、保存数据等
}
@Override
protected void onStop() {
super.onStop();
// 在onStop方法中执行清理工作
// 例如,可以释放资源、停止服务等
}
@Override
protected void onDestroy() {
super.onDestroy();
// 在onDestroy方法中释放Activity所占用的资源
// 例如,可以取消所有请求、停止所有服务等
}
}
// kotlin中仅对应的继承表示变化
class MainActivity : AppCompatActivity()
在AndroidManifest.xml文件中,可以为Activity指定不同的启动模式,这些模式定义了Activity如何被实例化和在任务堆栈中的位置;
/**
standard:这是默认的启动模式,每次启动Activity时都会创建一个新的Activity实例;
singleTop:如果Activity已经位于任务栈的顶部,系统不会创建新的Activity实例,而是复用现有的实例;
singleTask:这种模式下,系统会确保在一个任务栈中只有一个该Activity的实例;
singleInstance:与singleTask类似,但是系统为这个Activity分配一个单独的任务栈。
*/
<activity android:name=".MyActivity"
android:launchMode="singleTask">
</activity>
Intent用于在应用程序的不同组件之间(如Activity)传递信息,可以使用Intent来启动一个新的Activity或向其他组件传递数据;
当用户与应用程序交互时,一系列的Activity会组成一个任务栈,用户可以后退(通过按返回键)到堆栈中的上一个Activity;
虽然Fragment不是与Activity直接相关的组件,但它们经常与Activity一起使用,Fragment代表Activity中的一个部分,可以重复使用和组织UI代码;
在AndroidManifest.xml文件中,可以为Activity指定Intent Filters,以便应用程序能够响应系统或其他应用程序发出的特定Intent;
/**
Intent.FLAG_ACTIVITY_NEW_TASK:这个标志用于创建一个新的任务栈来启动Activity;
Intent.FLAG_ACTIVITY_SINGLE_TOP:这个标志与singleTop启动模式类似;
Intent.FLAG_ACTIVITY_CLEAR_TOP:这个标志与singleTask启动模式类似;
Intent.FLAG_ACTIVITY_REORDER_TO_FRONT:这个标志将使Activity重新排序到任务栈的前面,但不会改变其启动模式。
*/
Intent intent = new Intent(this, MyActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
// 使用Intent.FLAG_ACTIVITY_NEW_TASK启动Activity
val newTaskIntent = Intent(this, OtherActivity::class.java)
newTaskIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(newTaskIntent)
一个Android应用通常包含多个Activity,每个Activity负责一个特定的功能或任务;
在创建和启动Intent时,可以使用不同的Flags来控制如何启动新的Activity或处理已经存在的Activity实例;
在一个Activity结束时,可以返回一个结果给启动它的Activity,这是通过使用setResult()方法实现的。
二、Services
与Activity不同,Service不会提供用户界面,但可以在后台执行一些操作,如播放音乐、同步数据等;
在AndroidManifest.xml文件中,通过 标签定义Service;
<service android:name=".MyService" android:exported="false">
<intent-filter>
<action android:name="com.example.myapp.MyServiceAction" />
</intent-filter>
</service>
它有一个单一的onStartCommand()方法,当Service被启动时调用,可以通过两种方式启动Service:通过Context.startService()方法或通过一个Intent;
Service也可以被其他组件绑定并与之通信,通过定义一个或多个Binder接口;
import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.util.Log
class MyService : Service() {
private static final String TAG = "MyService"
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(TAG, "Service started with startId: $startId")
// 在这里执行你的业务逻辑
return START_STICKY // 返回值表示如果系统需要重新创建这个 Service,它将保持其已启动的状态
}
override fun onBind(intent: Intent): IBinder? {
// 返回一个自定义的 IBinder 对象来绑定服务
return MyBinder()
}
private class MyBinder : Binder() {
// 提供了一个公开的方法来访问服务中的公共方法或数据
fun doSomething() {
// 在这里执行你想要的操作
Log.d(TAG, "Binder method called")
}
}
}
serviceConnection = object : ServiceConnection {
override fun onServiceConnected(componentName: ComponentName?, b: IBinder?) {
// 绑定成功后,通过 IBinder 对象调用服务中的方法
val binder = b as MyService.MyBinder
myService = MyService() // 创建服务实例(如果之前没有创建)
binder.doSomething() // 调用服务中的方法
}
override fun onServiceDisconnected(componentName: ComponentName?) {
// 服务意外断开连接时调用此方法,可以在这里处理相关逻辑。
}
}
val intent = Intent(this, MyService::class.java) // 创建 Intent 对象来启动服务
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) // 绑定服务并传入 Intent、ServiceConnection 和标志位(这里是自动创建)
}
Service可以在后台执行耗时的任务,而不会阻塞用户界面;
Service可以发送和接收广播,这是Android的一种通知机制。
三、Content Providers
Content Providers是一种数据共享机制,允许应用程序将数据提供给其他应用程序使用;
public class MyProvider extends ContentProvider {
@Override
public boolean onCreate() {
return false;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
// 实现必要的方法
}
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.example.myapp.myprovider/my_path");
Cursor cursor = resolver.query(uri, projection, selection, selectionArgs, sortOrder);
四、Intent
Intent通常起着媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。
五、Broadcast Receiver
用于接收来自系统或其他应用程序发送的广播,可以用于监听各种不同的事件,如系统设置更改、网络状态变化或新消息到达等。
package com.example.myapplication;
import android.content.Intent;
import androidx.core.app.JobIntentService;
import androidx.core.content.ContextCompat;
public class MyService extends JobIntentService {
private static final String MY_ACTION = "com.example.myapplication.MY_ACTION";
private static final String MY_EXTRA = "com.example.myapplication.MY_EXTRA";
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, MyService.class, 1, work);
}
@Override
protected void onHandleWork(Intent intent) {
if (intent != null && MY_ACTION.equals(intent.getAction())) {
String extraData = intent.getStringExtra(MY_EXTRA);
// 处理接收到的广播数据
}
}
}
<service android:name=".MyService" android:exported="false">
<intent-filter>
<action android:name="com.example.myapplication.MY_ACTION"/>
</intent-filter>
</service>
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import androidx.core.app.JobIntentService;
import androidx.core.content.ContextCompat;
import androidx.core.content.IntentUtils;
import static androidx.core.content.IntentUtilsKt.*;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 启动MyService来注册Broadcast Receiver
Intent work = new Intent(this, MyService.class);
work.setAction(MyService.MY_ACTION);
work.putExtra(MyService.MY_EXTRA, "额外的数据"); // 可选,根据需要传递数据给MyService处理。
enqueueWork(this, work); // 使用JobIntentService的enqueueWork()方法启动服务。这将在后台线程上异步执行服务。
}
}
六、Notification
用于在状态栏上显示通知给用户,这些通知可以包含文本、图标、声音、振动和其他类型的视觉和听觉反馈,以向用户提供关于应用程序或其他事件的即时信息。
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.Build
import androidx.core.app.NotificationCompat
public class MyNotification {
private Context context;
private NotificationManager notificationManager;
public MyNotification(Context context) {
this.context = context;
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}
public void createNotificationChannel(String channelId, String channelName) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
}
public void showNotification() {
String channelId = "my_channel_id";
String channelName = "My Notification Channel";
createNotificationChannel(channelId, channelName);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, channelId)
.setContentTitle("Notification Title")
.setContentText("This is the notification content")
.setSmallIcon(R.drawable.ic_launcher);
notificationManager.notify(1, notificationBuilder.build());
}
}
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.Build
import androidx.core.app.NotificationCompat
class MyNotification(context: Context) {
private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
fun createNotificationChannel(channelId: String, channelName: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT)
notificationManager.createNotificationChannel(channel)
}
}
fun showNotification() {
val channelId = "my_channel_id"
val channelName = "My Notification Channel"
createNotificationChannel(channelId, channelName)
val notification = NotificationCompat.Builder(context, channelId)
.setContentTitle("Notification Title")
.setContentText("This is the notification content")
.setSmallIcon(R.drawable.ic_launcher)
.build()
notificationManager.notify(1, notification)
}
}
总结:Java与Kotlin
异:
Java 和 Kotlin 的语法存在显著差异,Kotlin 的语法更加简洁,减少了样板代码的数量,使得代码更加清晰易读;
Kotlin 对于空值的安全性处理比 Java 更强大,Kotlin 中的非空类型可以自动处理空值问题,减少了空指针异常的可能性;
Kotlin 支持扩展函数,可以在不修改原有类的基础上为其添加新的方法,而 Java 则不支持这一特性;
Kotlin 支持 Lambda 表达式和匿名函数,使得编写简洁、功能强大的代码更加容易,而 Java 8 之后也开始支持 Lambda 表达式,但相对 Kotlin 的语法更加繁琐;
List<String> names = Arrays.asList("Peter", "Anna", "Mike", "Xenia");
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello from another thread!");
}
}).start();
val names = listOf("Peter", "Anna", "Mike", "Xenia")
names.sorted { a, b -> b.compareTo(a) } // 使用lambda表达式排序
fun main() {
val printMessage = { message: String -> println(message) } // 定义匿名函数
printMessage("Hello from Kotlin!") // 调用匿名函数
}
Kotlin 在内存安全方面更加严格,减少了内存泄漏的风险,而 Java 需要开发者更加关注内存管理问题;
同:
两者都是静态类型语言,支持面向对象编程;
两者都可以编写 Android 应用,并且编译成字节码;
两者都支持 Android API,可以调用 Android 提供的各种组件和服务。