高级主题 #
性能优化 #
性能优化概述 #
text
┌─────────────────────────────────────────────────────────────┐
│ 性能优化要点 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ├── 启动性能 │
│ │ - 延迟初始化 │
│ │ - AOT 编译 │
│ │ - 资源优化 │
│ │ │
│ ├── 运行时性能 │
│ │ - UI 渲染优化 │
│ │ - 数据绑定优化 │
│ │ - 内存管理 │
│ │ │
│ ├── 网络性能 │
│ │ - 异步操作 │
│ │ - 缓存策略 │
│ │ - 数据压缩 │
│ │ │
│ └── 应用体积 │
│ - 链接器配置 │
│ - 资源压缩 │
│ - 程序集裁剪 │
│ │
└─────────────────────────────────────────────────────────────┘
启动优化 #
延迟初始化 #
csharp
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new LoadingPage();
}
protected override async void OnStart()
{
await InitializeServicesAsync();
MainPage = new AppShell();
}
private async Task InitializeServicesAsync()
{
var tasks = new List<Task>
{
InitializeDatabaseAsync(),
InitializeCacheAsync(),
LoadUserSettingsAsync()
};
await Task.WhenAll(tasks);
}
}
XAML 编译 #
csharp
using Xamarin.Forms.Xaml;
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace MyApp
{
}
UI 渲染优化 #
使用 Compiled Bindings #
xml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.MainPage"
x:DataType="local:MainViewModel">
<Label Text="{Binding Title}" />
</ContentPage>
避免过度布局 #
xml
<Grid RowDefinitions="Auto, *, Auto">
<Label Grid.Row="0" Text="标题" />
<ScrollView Grid.Row="1">
<StackLayout>
</StackLayout>
</ScrollView>
<Button Grid.Row="2" Text="提交" />
</Grid>
使用 CollectionView 替代 ListView #
xml
<CollectionView ItemsSource="{Binding Items}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="local:Item">
<StackLayout>
<Label Text="{Binding Title}" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
数据绑定优化 #
使用 Compiled Bindings #
csharp
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext = new MainViewModel();
}
}
避免频繁更新 #
csharp
public class MainViewModel : ViewModelBase
{
private CancellationTokenSource _cts;
private string _searchText;
public string SearchText
{
get => _searchText;
set
{
SetProperty(ref _searchText, value);
DebounceSearch(value);
}
}
private void DebounceSearch(string text)
{
_cts?.Cancel();
_cts = new CancellationTokenSource();
Task.Delay(500, _cts.Token)
.ContinueWith(t =>
{
if (!t.IsCanceled)
{
Search(text);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
}
内存管理 #
及时释放资源 #
csharp
public partial class DetailPage : ContentPage
{
private IDisposable _subscription;
public DetailPage()
{
InitializeComponent();
_subscription = Observable.Subscribe(OnNext);
}
protected override void OnDisappearing()
{
base.OnDisappearing();
_subscription?.Dispose();
}
}
使用 WeakReference #
csharp
public class EventSubscriber
{
private readonly WeakReference<Page> _pageRef;
public EventSubscriber(Page page)
{
_pageRef = new WeakReference<Page>(page);
}
public void OnEvent(object sender, EventArgs e)
{
if (_pageRef.TryGetTarget(out var page))
{
}
}
}
链接器配置 #
text
┌─────────────────────────────────────────────────────────────┐
│ 链接器选项 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Don't Link (不链接) │
│ - 不移除任何代码 │
│ - 调试时使用 │
│ - 应用体积最大 │
│ │
│ Link SDK Assemblies Only (仅链接 SDK) │
│ - 仅优化 SDK 程序集 │
│ - 平衡体积和兼容性 │
│ - 推荐用于发布 │
│ │
│ Link All Assemblies (链接所有) │
│ - 优化所有程序集 │
│ - 应用体积最小 │
│ - 需要保留配置 │
│ │
└─────────────────────────────────────────────────────────────┘
xml
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
<iOSLinkMode>SdkOnly</iOSLinkMode>
</PropertyGroup>
csharp
[assembly: Preserve(AllMembers = true)]
namespace MyApp.Services
{
public class DataService
{
}
}
应用生命周期 #
应用生命周期事件 #
text
┌─────────────────────────────────────────────────────────────┐
│ 应用生命周期 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 启动流程: │
│ │
│ App 构造函数 │
│ │ │
│ ▼ │
│ InitializeComponent() │
│ │ │
│ ▼ │
│ OnStart() │
│ │ │
│ ▼ │
│ 应用运行 │
│ │ │
│ ├── OnSleep() ──► 应用进入后台 │
│ │ │ │
│ │ └── OnResume() ──► 应用恢复 │
│ │ │
│ ▼ │
│ OnSleep() │
│ │ │
│ ▼ │
│ 应用终止 │
│ │
└─────────────────────────────────────────────────────────────┘
处理生命周期事件 #
csharp
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new AppShell();
}
protected override void OnStart()
{
Console.WriteLine("应用启动");
}
protected override void OnSleep()
{
Console.WriteLine("应用进入后台");
SaveAppState();
}
protected override void OnResume()
{
Console.WriteLine("应用恢复");
RestoreAppState();
}
private void SaveAppState()
{
var state = new AppState
{
LastPage = MainPage?.GetType().Name,
Timestamp = DateTime.Now
};
Preferences.Set("app_state", JsonConvert.SerializeObject(state));
}
private void RestoreAppState()
{
var stateJson = Preferences.Get("app_state", string.Empty);
if (!string.IsNullOrEmpty(stateJson))
{
var state = JsonConvert.DeserializeObject<AppState>(stateJson);
}
}
}
页面生命周期 #
csharp
public partial class DetailPage : ContentPage
{
public DetailPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
Console.WriteLine("页面即将显示");
}
protected override void OnDisappearing()
{
base.OnDisappearing();
Console.WriteLine("页面即将消失");
}
protected override void OnParentSet()
{
base.OnParentSet();
Console.WriteLine("页面父级设置");
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
Console.WriteLine("绑定上下文改变");
}
protected override bool OnBackButtonPressed()
{
Console.WriteLine("返回按钮按下");
return base.OnBackButtonPressed();
}
}
测试策略 #
单元测试 #
csharp
public class MainViewModelTests
{
[Fact]
public void LoadDataCommand_ShouldLoadItems()
{
var mockDataService = new Mock<IDataService>();
mockDataService.Setup(s => s.GetItemsAsync())
.ReturnsAsync(new List<Item> { new Item { Id = 1, Title = "Test" } });
var viewModel = new MainViewModel(mockDataService.Object);
viewModel.LoadDataCommand.Execute(null);
Assert.Single(viewModel.Items);
Assert.Equal("Test", viewModel.Items[0].Title);
}
[Fact]
public void Title_WhenSet_ShouldRaisePropertyChanged()
{
var viewModel = new MainViewModel();
var raised = false;
viewModel.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(MainViewModel.Title))
{
raised = true;
}
};
viewModel.Title = "New Title";
Assert.True(raised);
}
}
UI 测试 #
csharp
public class MainViewTests
{
[Fact]
public void MainPage_ShouldDisplayTitle()
{
var app = new App();
var mainPage = app.MainPage as MainPage;
var titleLabel = mainPage.FindByName<Label>("TitleLabel");
Assert.NotNull(titleLabel);
Assert.Equal("欢迎使用", titleLabel.Text);
}
}
Xamarin.UITest #
csharp
public class Tests : BaseTest
{
public Tests(Platform platform) : base(platform)
{
}
[Test]
public void AppLaunches()
{
app.Screenshot("First screen.");
}
[Test]
public void LoginTest()
{
app.EnterText("UsernameEntry", "testuser");
app.EnterText("PasswordEntry", "password123");
app.Tap("LoginButton");
app.WaitForElement("WelcomeLabel", "登录成功");
app.Screenshot("登录成功");
}
}
部署发布 #
Android 发布 #
text
┌─────────────────────────────────────────────────────────────┐
│ Android 发布流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 配置应用信息 │
│ - AndroidManifest.xml │
│ - 版本号、权限、图标 │
│ │
│ 2. 创建签名密钥 │
│ - keytool -genkey -v -keystore myapp.keystore │
│ │
│ 3. 配置发布构建 │
│ - Release 模式 │
│ - 链接器设置 │
│ - AOT 编译 │
│ │
│ 4. 生成 APK/AAB │
│ - 归档 (Archive) │
│ - 签名 │
│ │
│ 5. 上传到商店 │
│ - Google Play Console │
│ │
└─────────────────────────────────────────────────────────────┘
AndroidManifest.xml #
xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
package="com.mycompany.myapp">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<application android:label="MyApp"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round">
</application>
</manifest>
发布配置 #
xml
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>false</DebugSymbols>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
<AotAssemblies>true</AotAssemblies>
<EnableLLVM>true</EnableLLVM>
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
</PropertyGroup>
iOS 发布 #
text
┌─────────────────────────────────────────────────────────────┐
│ iOS 发布流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 配置应用信息 │
│ - Info.plist │
│ - 版本号、权限、图标 │
│ │
│ 2. 创建开发者证书 │
│ - Apple Developer 账户 │
│ - 创建 App ID │
│ - 创建证书和描述文件 │
│ │
│ 3. 配置发布构建 │
│ - Release 模式 │
│ - AOT 编译 │
│ - LLVM 优化 │
│ │
│ 4. 生成 IPA │
│ - 归档 (Archive) │
│ - 签名 │
│ │
│ 5. 上传到商店 │
│ - App Store Connect │
│ │
└─────────────────────────────────────────────────────────────┘
Info.plist #
xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>MyApp</string>
<key>CFBundleIdentifier</key>
<string>com.mycompany.myapp</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>NSCameraUsageDescription</key>
<string>需要访问相机来拍照</string>
</dict>
</plist>
迁移到 .NET MAUI #
MAUI 概述 #
text
┌─────────────────────────────────────────────────────────────┐
│ .NET MAUI │
├─────────────────────────────────────────────────────────────┤
│ │
│ .NET MAUI 是 Xamarin.Forms 的继任者: │
│ │
│ 改进: │
│ ├── 统一项目结构 │
│ ├── 更好的性能 │
│ ├── 现代化 API │
│ ├── .NET 6+ 支持 │
│ ├── 更好的热重载 │
│ └── 单一代码库 │
│ │
│ 平台支持: │
│ ├── Android │
│ ├── iOS │
│ ├── macOS │
│ ├── Windows │
│ └── Tizen │
│ │
└─────────────────────────────────────────────────────────────┘
迁移步骤 #
text
┌─────────────────────────────────────────────────────────────┐
│ 迁移流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 评估迁移成本 │
│ - 检查 NuGet 依赖兼容性 │
│ - 检查自定义渲染器 │
│ - 检查 Effects │
│ │
│ 2. 创建 MAUI 项目 │
│ - 使用迁移工具 │
│ - 或手动创建 │
│ │
│ 3. 迁移共享代码 │
│ - Models │
│ - ViewModels │
│ - Services │
│ │
│ 4. 迁移 UI 代码 │
│ - XAML 文件 │
│ - 样式和资源 │
│ │
│ 5. 迁移平台代码 │
│ - 渲染器 → Handlers │
│ - Effects │
│ - 平台服务 │
│ │
│ 6. 测试和调试 │
│ │
└─────────────────────────────────────────────────────────────┘
API 变化 #
csharp
// Xamarin.Forms
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
}
// .NET MAUI
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
}
xml
<!-- Xamarin.Forms -->
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<!-- .NET MAUI -->
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
渲染器迁移到 Handlers #
csharp
// Xamarin.Forms 自定义渲染器
[assembly: ExportRenderer(typeof(CustomButton), typeof(CustomButtonRenderer))]
public class CustomButtonRenderer : ButtonRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
// 自定义逻辑
}
}
// .NET MAUI Handler
public partial class CustomButtonHandler
{
public static IPropertyMapper<CustomButton, CustomButtonHandler> Mapper =
new PropertyMapper<CustomButton, CustomButtonHandler>(ButtonHandler.Mapper)
{
[nameof(CustomButton.CustomProperty)] = MapCustomProperty
};
public CustomButtonHandler() : base(Mapper)
{
}
private static void MapCustomProperty(CustomButtonHandler handler, CustomButton button)
{
// 自定义逻辑
}
}
最佳实践总结 #
代码组织 #
text
MyApp/
├── Models/ # 数据模型
├── ViewModels/ # 视图模型
├── Views/ # 视图
├── Services/ # 服务
├── Converters/ # 值转换器
├── Effects/ # Effects
├── Renderers/ # 自定义渲染器
├── Helpers/ # 辅助类
├── Resources/ # 资源
│ ├── Styles/
│ ├── Images/
│ └── Fonts/
└── Platforms/ # 平台特定代码
├── Android/
├── iOS/
└── UWP/
性能检查清单 #
text
┌─────────────────────────────────────────────────────────────┐
│ 性能检查清单 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ✅ 启用 XAML 编译 │
│ ✅ 使用 Compiled Bindings │
│ ✅ 使用 CollectionView 替代 ListView │
│ ✅ 配置正确的链接器选项 │
│ ✅ 使用异步操作避免 UI 阻塞 │
│ ✅ 及时释放资源和取消订阅 │
│ ✅ 优化图片资源大小 │
│ ✅ 使用缓存减少网络请求 │
│ ✅ 避免过度布局嵌套 │
│ ✅ 延迟加载非必要组件 │
│ │
└─────────────────────────────────────────────────────────────┘
总结 #
恭喜你完成了 Xamarin.Forms 完全指南的学习!你已经掌握了:
- Xamarin 的基础概念和开发环境配置
- XAML 语法和页面布局
- 导航系统和数据绑定
- MVVM 架构模式
- 样式和资源管理
- 平台特性调用
- 性能优化和部署发布
继续实践,探索更多高级功能,并考虑迁移到 .NET MAUI 以获得更好的开发体验!
最后更新:2026-03-29