Die Artikelserie erklärt Schritt für Schritt das Kerngeschäft und den Code des Musikplayers:
- [MAUI Project Combat] Music Player (1): Übersicht und Architektur
- [MAUI Project Combat] Musik-Player (2): Kernel wird abgespielt
- [MAUI Project Combat] Musikplayer (3): Schnittstelleninteraktion
Warum ist Ihnen dieses Projekt in Erinnerung geblieben?
Dies ist ein altes Projekt für Windows Phone 8. 2014 habe ich als Hobby eine App namens "Tomato Player" geschrieben und nebenbei meine Programmierkenntnisse verbessert.
Die Architektur dieses Projekts wurde mehrfach migriert, von WP8 zu UWP zu Xamarin.Forms. Mit der offiziellen Veröffentlichung von MAUI Ende letzten Jahres habe ich versucht, es auf MAUI zu migrieren.
Obwohl es mehrere Migrationen durchlaufen hat, hat sich der Code des Namensraums und des Wiedergabekerns im Grunde nicht wesentlich geändert.Mit dem Upgrade der Lösung setzt das Projekt auf Änderungen in Bibliotheken und API-Aufrufmethoden, die Microsofts Turbulenzen im mobilen Internet miterlebt haben Feld. Ich habe zufällig festgestellt, dass die vor 8 Jahren an den Microsoft Store übermittelte App immer noch die Download-Seite - den Microsoft App Store - öffnen kann , aber da ich kein Windows Phone-Gerät zur Hand habe, kann ich sie in keinem Emulator zum Laufen bringen . Sie können dieses Objekt und diese Zeit nur aus Store-Screenshots und Quellcode nacherleben.
Dieses Projekt hat jetzt keinen kommerziellen Wert, aber ich weiß, was es für mich bedeutet. Die Freude und Freude, die es mir beim Programmieren bereitete, lässt mich wirklich wissen, was „Code 4 Fun“ ist – — Die Freude, die das Programmieren mit sich bringt eine große Hilfe für mich, die damals gerade in die Gesellschaft eingetreten war, mein Selbstvertrauen aufzubauen und auf dem Weg zu bleiben.
Der Gegenstand hatte möglicherweise nie einen Wert. Dann schreiben Sie Blogbeiträge und machen Sie so viel Wert wie möglich auf Open Source.
Derzeit gibt es auf der .Net-Plattform viele Open-Source-Bibliotheken für Audioverpackungen, wie z eine bessere Möglichkeit haben, es zu implementieren, Willkommen, um eine Nachricht unter dem Artikel zu hinterlassen. Da der Code alt ist und in den letzten Jahren nicht umgestaltet wurde, wird es viele Redundanzen in der C#-Sprachversion und beim Schreiben des Codes geben. Ich möchte mich bei allen hier entschuldigen.
die Architektur
Unter Verwendung des Abp-Frameworks habe ich bereits geschrieben, wie man Abp in das .NET-MAUI-Projekt portiert , und dieses Projekt ist gemäß diesem Blogbeitrag ebenfalls abgeschlossen.
Plattformübergreifend
Durch die Verwendung von .NET MAU zur plattformübergreifenden Unterstützung können von Xamarin.Forms portierte Anwendungen reibungslos auf Android- und iOS-Plattformen ausgeführt werden.
Der Wiedergabekern wird von partiellen Klassen bereitgestellt, um plattformübergreifende Unterstützung bereitzustellen.In der Ära von Xamarin.Forms müssen Projekte auf verschiedenen Plattformen verwaltet werden.MAUI ist ein einzelnes Projekt, das mehrere Plattformen unterstützt.
MAUI-Anwendungsprojekte enthalten einen Plattformordner, jeder Unterordner stellt eine Plattform dar, auf die .NET MAUI abzielen kann
Jeder Ordner stellt den spezifischen Code für jede Plattform dar, und standardmäßig kompiliert die Kompilierungsphase nur den aktuell ausgewählten Plattformordnercode.
Dies gehört zur Verwendung von partiellen Klassen und Methoden zum Erstellen von plattformspezifischen Inhalten. Weitere Informationen finden Sie in der offiziellen Dokumentation
Zum Beispiel IMusicControlService
in der partiellen Klassenumsetzung im Projekt:
MatoMusic.Core\Impl\MusicControlService.cs
MatoMusic.Core\Platforms\Android\MusicControlService.cs
MatoMusic.Core\Platforms\iOS\MusicControlService.cs
MatoMusic.Core\Platforms\Windows\MusicControlService.cs
Kernklasse
Beim Entwerfen des Wiedergabekerns haben wir den Track-Manager IMusicInfoManager
und den Wiedergabesteuerungsdienst vom Interaktionspfad des Benutzers abstrahiert IMusicControlService
.
Das Spielerverhalten und das Streckenbetriebsverhalten sind in ihren jeweiligen Bereichen voneinander isoliert und werden durch das Produktions-Verbrauchs-Modell, den Datenfluss und das Blubbern von Nachrichtenbenachrichtigungen koordiniert. Versuchen Sie, den groß angelegten Einsatz von Thread-Sperren und komplexer Thread-Synchronisationslogik zu vermeiden. In der plattformübergreifenden Lösung werden diese Schnittstellen durch partielle Klassen implementiert, und das Klassendiagramm sieht wie folgt aus:
Die auf die Musikwiedergabe bezogene Dienstklasse MusicRelatedService
stellt eine Einkapselungsebene des Wiedergabesteuerungsdienstes dar. Im Hinblick auf die eigentliche Player-Geschäftslogik ist es bequemer, den eingekapselten Code zu verwenden, um die Aufgabe abzuschließen.
Das Projekt folgt dem MVVM-Entwurfsmuster. MusicRelatedViewModel
Als Basisklasse von ViewModel in Bezug auf die Musikwiedergabe enthält es Track-Manager- IMusicInfoManager
und Playback-Control-Service- IMusicControlService
Objekte. Durch bidirektionale Bindung können Entwickler die Musiksteuerung und den Track-Zugriff von der Präsentationsschicht aus einfach durchführen.
ViewModelBase
Es ist eine Basisklasse, die vom AbpServiceBase
Aufruf der gemeinsamen Funktionen des Abp-Frameworks geerbt ist und diese kapselt. Wie Einstellungs-, Lokalisierungs- und UnitOfWork-Funktionen. Und implementiert INotifyPropertyChanged
stellt es Änderungsereignisse für jede Eigenschaft des gebundenen Typs bereit.
Das Kernklassendiagramm sieht wie folgt aus
Definition
- Warteschlange - Song-Warteschlange, eine geordnete Liste der aktuell wiedergegebenen Songs
- Playlist - Playlist, eine Sammlung von spielbaren Inhalten speichern, für Lieblingstitel, zu Favoriten hinzufügen usw.
- PlaylistEntry – Playlist-Eintrag, abspielbarer Inhalt, verbunden mit lokaler Musik oder Online-Musikinformationen
- MyFavourite – Mein Favorit, eine spezielle Wiedergabeliste mit der ID 1, die nicht bearbeitet oder gelöscht werden kann und zum Aufnehmen und Aufleuchten des Songs „Little Red Heart“ verwendet wird
- MusicInfo - Titelinformationen
- AlbumInfo - Albuminformationen
- ArtistInfo - Künstlerinformationen
- BillboardInfo - Charts, Online-Musik-Playlists
Schiene
Zu den Titeln gehören:
- Titel - Musiktitel
- AlbumTitle - Albumtitel
- GroupHeader - die Titelkopfzeile, die verwendet wird, um die Liste entsprechend der Anzeige zu gruppieren
- URL - Adresse der Audiodatei
- Künstler - Künstler
- Genre - Genre
- IsFavourite - Ist es "Favorit"
- IsPlaying - ob es spielt
- AlbumArtPath - Titelbild
- Dauer - die Gesamtdauer des Songs
Wenn Sie mit dem Fuzzy-Suchsteuerelement kooperieren, muss es implementiert werden.Für IClueObject
die Verwendungsmethode lesen Sie bitte das AutoComplete-Steuerelement
public class MusicInfo : ObservableObject, IBasicInfo, IClueObject
{ .. }
public List<string> ClueStrings
{
get
{
var result = new List<string>();
result.Add(Title);
result.Add(Artist);
result.Add(AlbumTitle);
return result;
}
}
Es erbt von ObservableObject
, im Konstruktor Register Property Change Event
IsFavourite
Change, wird aufgerufen MusicInfoManager
, um den aktuellen Track als "Favorit" zu setzen oder zu deaktivieren.
private void MusicInfo_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var MusicInfoManager = IocManager.Instance.Resolve<MusicInfoManager>();
if (e.PropertyName == nameof(IsFavourite))
{
if (IsFavourite)
{
MusicInfoManager.CreatePlaylistEntryToMyFavourite(this);
}
else
{
MusicInfoManager.DeletePlaylistEntryFromMyFavourite(this);
}
}
}
Track-Sammlung
Eine Titelsammlung ist eine Zusammenfassung von Wiedergabelisten, Musikalben oder von Künstlern (Sängern) erstellter Musik, die Folgendes umfasst:
- Titel – Titel, Wiedergabeliste, Musikalbum oder Künstlername
- GroupHeader - die Titelkopfzeile, die verwendet wird, um die Liste entsprechend der Anzeige zu gruppieren
- Musik - Eine Sammlung von Titelinformationen
- AlbumArtPath - Titelbild
- Count - die Anzahl der Titel in der Songsammlung
- Zeit - die Gesamtdauer der Songsammlung
es erbt vonObservableObject
AlbumInfo
, ArtistInfo
, PlaylistInfo
, BillboardInfo
sind alle Unterklassen der Track-Sammlung
Musics
Ist der Inhalt der Track-Sammlung, der Typ ist ObservableCollection<MusicInfo>
, und das Warteschlangenänderungsereignis wird bei der bidirektionalen Bindung bereitgestellt.
Die Anzahl der Titel in der Sammlung und die Gesamtdauer der Sammlung hängen von dieser Variablen ab
public int Count => Musics.Count();
public string Time
{
get
{
var totalSec = Math.Truncate((double)Musics.Sum(c => (long)c.Duration));
var totalTime = TimeSpan.FromSeconds(totalSec);
var time = totalTime.ToString("g");
return time;
}
}
Wenn der Inhalt der Sammlung hinzugefügt oder gelöscht wird, werden die Anzahl der Tracks und die Gesamtdauer der Songsammlung synchron mitgeteilt
private void _musics_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Remove || e.Action == NotifyCollectionChangedAction.Add)
{
RaisePropertyChanged(nameof(Time));
RaisePropertyChanged(nameof(Count));
}
}
GroupHeader
Titelüberschrift, im Allgemeinen erhalten, ist der erste Buchstabe des Titels, wenn der Titel Chinesisch ist, verwenden Sie die Microsoft.International.Converters.PinYinConverter
Pinyin-Initialen des ersten Wortes auf Chinesisch, die plattformübergreifende Implementierungsmethode ist wie folgt:
private partial string GetGroupHeader(string title)
{
string result = string.Empty;
if (!string.IsNullOrEmpty(title))
{
if (Regex.IsMatch(title.Substring(0, 1), @"^[\u4e00-\u9fa5]+$"))
{
try
{
var chinese = new ChineseChar(title.First());
result = chinese.Pinyins[0].Substring(0, 1);
}
catch (Exception ex)
{
return string.Empty;
}
}
else
{
result = title.Substring(0, 1);
}
}
return result;
}
GroupHeader
Der Inhalt, der für die Listengruppenanzeige verwendet wird, wird in nachfolgenden Artikeln ausgearbeitet
Datenbank
Sqlite wird in der Anwendung als Persistenz von Daten wie Wiedergabelisten, Songlisten, Einstellungen usw. verwendet
, und die Sqlite-Datenbankdatei wird mit EF mithilfe von CodeFirst initialisiert:mato.db
Fügen Sie dem MatoMusic.Core-Projekt appsettings.json
eine lokale SQLite-Verbindungszeichenfolge hinzu
"ConnectionStrings": {
"Default": "Data Source=file:{0};"
},
...
Diese Datei ist ein Platzhalter, um den Code-Hardcode an die Konfigurationsdatei zu übergeben
Überschreiben Sie in MatoMusicCoreModule.cs PreInitialize und legen Sie Configuration.DefaultNameOrConnectionString fest:
public override void PreInitialize()
{
LocalizationConfigurer.Configure(Configuration.Localization);
Configuration.Settings.Providers.Add<CommonSettingProvider>();
string documentsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), MatoMusicConsts.LocalizationSourceName);
var configuration = AppConfigurations.Get(documentsPath, development);
var connectionString = configuration.GetConnectionString(MatoMusicConsts.ConnectionStringName);
var dbName = "mato.db";
string dbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), MatoMusicConsts.LocalizationSourceName, dbName);
Configuration.DefaultNameOrConnectionString = String.Format(connectionString, dbPath);
base.PreInitialize();
}
Definieren Sie als Nächstes die Entitätsklasse
Warteschlange spielen
definiert in\MatoMusic.Core\Models\Entities\Queue.cs
public class Queue : FullAuditedEntity<long>
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public override long Id { get; set; }
public long MusicInfoId { get; set; }
public int Rank { get; set; }
public string MusicTitle { get; set; }
}
Lieder Liste
definiert in\MatoMusic.Core\Models\Entities\Playlist.cs
public class Playlist : FullAuditedEntity<long>
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public override long Id { get; set; }
public string Title { get; set; }
public bool IsHidden { get; set; }
public bool IsRemovable { get; set; }
public ICollection<PlaylistItem> PlaylistItems { get; set; }
}
Playlist-Eintrag
definiert in\MatoMusic.Core\Models\Entities\PlaylistItem.cs
public class PlaylistItem : FullAuditedEntity<long>
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public override long Id { get; set; }
public int Rank { get; set; }
public long PlaylistId { get; set; }
[ForeignKey("PlaylistId")]
public Playlist Playlist { get; set; }
public string MusicTitle { get; set; }
public long MusicInfoId { get; set; }
}
Aufbau
Das Datenbankkontextobjekt MatoMusicDbContext
ist wie folgt definiert
public class MatoMusicDbContext : AbpDbContext
{
//Add DbSet properties for your entities...
public DbSet<Queue> Queue { get; set; }
public DbSet<Playlist> Playlist { get; set; }
public DbSet<PlaylistItem> PlaylistItem { get; set; }
...
MatoMusic.EntityFrameworkCore ist ein Wartungs- und Verwaltungsprojekt für Anwendungsdatenbanken, das von Abp.EntityFrameworkCore abhängt.
Verweisen Sie in der csproj-Datei im MatoMusic.EntityFrameworkCore-Projekt auf die folgenden Pakete
<PackageReference Include="Abp.EntityFrameworkCore" Version="7.4.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Design" Version="1.1.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0">
mato.db
Im Projekt MatoMusicEntityFrameworkCoreModule.cs wird das Kontextobjekt registriert, und die Migration wird bei der Programminitialisierung ausgeführt, und die Datei wird auf dem Gerät generiert
public override void PostInitialize()
{
Helper.WithDbContextHelper.WithDbContext<MatoMusicDbContext>(IocManager, RunMigrate);
if (!SkipDbSeed)
{
SeedHelper.SeedHostDb(IocManager);
}
}
public static void RunMigrate(MatoMusicDbContext dbContext)
{
dbContext.Database.Migrate();
}
Projektadresse
Das nächste Kapitel stellt die Kernfunktionen des Players vor: die Wiedergabedienstklasse