[英]How to use Firebase with the Android universal music player?
Here is the Google sample app. 这是Google示例应用。 It's set up to pull metadata from a URL with a JSON.
它设置为使用JSON从URL中提取元数据。 I would like to know how to have Firebase be my source.
我想知道如何让Firebase成为我的来源。
Here is my attempt in changing the RemoteJSONSource class: 这是我尝试更改RemoteJSONSource类:
package com.mm.android.uamp.model;
import android.support.v4.media.MediaMetadataCompat;
import android.util.Log;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import com.mm.android.uamp.utils.LogHelper;
import java.util.ArrayList;
import java.util.Iterator;
public class RemoteJSONSource implements MusicProviderSource {
private static final String TAG = LogHelper.makeLogTag(RemoteJSONSource.class);
DatabaseReference mRootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference mMusic = mRootRef.child("music");
ArrayList<MediaMetadataCompat> tracksFromFB = new ArrayList<>();
public void buildFromFirebase(){
mMusic.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot music : dataSnapshot.getChildren()){
String title = music.child("title").getValue(String.class);
String album = music.child("album").getValue(String.class);
String artist = music.child("artist").getValue(String.class);
String genre = music.child("genre").getValue(String.class);
String source = music.child("source").getValue(String.class);
String id = String.valueOf(source.hashCode());
String iconUrl = music.child("image").getValue(String.class);
int trackNumber = music.child("trackNumber").getValue(Integer.class);
int totalTrackCount = music.child("totalTrackCount").getValue(Integer.class);
int duration = music.child("duration").getValue(Integer.class);
MediaMetadataCompat theMetadataFB = new MediaMetadataCompat.Builder()
.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, id)
.putString(MusicProviderSource.CUSTOM_METADATA_TRACK_SOURCE, source)
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, album)
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist)
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration)
.putString(MediaMetadataCompat.METADATA_KEY_GENRE, genre)
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, iconUrl)
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, title)
.putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, trackNumber)
.putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, totalTrackCount)
.build();
tracksFromFB.add(theMetadataFB);
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
}
});
}
@Override
public Iterator<MediaMetadataCompat> iterator() {
buildFromFirebase();
ArrayList<MediaMetadataCompat> tracksFB = tracksFromFB;
return tracksFB.iterator();
}
}
The firebase onDataChange is asynchronous so I think it hasn't finished pulling the data yet before the iterator method returns tracksFB.iterator cause tracksFB array is null. firebase onDataChange是异步的,所以我认为它还没有在iterator方法返回tracksFB.iterator之前完成提取数据,因为tracksFB数组为null。 Weird thing is when I run in debug mode with a line break on
奇怪的是当我在调试模式下运行换行符时
ArrayList tracksFB = tracksFromFB; ArrayList tracksFB = tracksFromFB;
It works. 有用。 From my research I think I need a callback or some type of pausing task, but I just cant figure it out.
根据我的研究,我认为我需要一个回调或某种类型的暂停任务,但我无法弄明白。
Possible relevant code connected to the iterator method 可能的相关代码连接到迭代器方法
public interface MusicProviderSource {
String CUSTOM_METADATA_TRACK_SOURCE = "__SOURCE__";
Iterator<MediaMetadataCompat> iterator();
}
next 下一个
public class MusicProvider {
private static final String TAG = LogHelper.makeLogTag(MusicProvider.class);
private MusicProviderSource mSource;
private ConcurrentMap<String, List<MediaMetadataCompat>> mMusicListByGenre;
private final ConcurrentMap<String, MutableMediaMetadata> mMusicListById;
private final Set<String> mFavoriteTracks;
enum State {
NON_INITIALIZED, INITIALIZING, INITIALIZED
}
private volatile State mCurrentState = State.NON_INITIALIZED;
public interface Callback {
void onMusicCatalogReady(boolean success);
}
public MusicProvider() {
this(new RemoteJSONSource());
}
public MusicProvider(MusicProviderSource source) {
mSource = source;
mMusicListByGenre = new ConcurrentHashMap<>();
mMusicListById = new ConcurrentHashMap<>();
mFavoriteTracks = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
}
public Iterable<String> getGenres() {
if (mCurrentState != State.INITIALIZED) {
return Collections.emptyList();
}
return mMusicListByGenre.keySet();
}
/**
* Get an iterator over a shuffled collection of all songs
*/
public Iterable<MediaMetadataCompat> getShuffledMusic() {
if (mCurrentState != State.INITIALIZED) {
return Collections.emptyList();
}
List<MediaMetadataCompat> shuffled = new ArrayList<>(mMusicListById.size());
for (MutableMediaMetadata mutableMetadata: mMusicListById.values()) {
shuffled.add(mutableMetadata.metadata);
}
Collections.shuffle(shuffled);
return shuffled;
}
/**
* Get music tracks of the given genre
*
*/
public Iterable<MediaMetadataCompat> getMusicsByGenre(String genre) {
if (mCurrentState != State.INITIALIZED || !mMusicListByGenre.containsKey(genre)) {
return Collections.emptyList();
}
return mMusicListByGenre.get(genre);
}
}
Also the musicService.java in the link above might be relevant. 此外,上面链接中的musicService.java可能是相关的。 PLEASE help!
请帮忙!
There are two ways I can think to do this, but I'm not familiar enough with Firebase to provide working code. 我有两种方法可以做到这一点,但我对Firebase不够熟悉,无法提供有效的代码。
The sample executes iterator()
in an AsyncTask
, expecting it to block until it can provide a response. 该示例在
AsyncTask
执行iterator()
,期望它阻塞直到它可以提供响应。 So the first, and probably easiest, way to fix it would be to cause iterator()
to wait on the data being loaded, or it failing to load. 因此,修复它的第一种也许是最简单的方法是使
iterator()
等待正在加载的数据,或者无法加载。 This could be a spinlock or something like wait/notify. 这可能是一个自旋锁或类似wait / notify的东西。
if (!dataloaded) {
try {
wait();
} catch (InterruptedException e) {}
}
ArrayList<MediaMetadataCompat> tracksFB = tracksFromFB;
return tracksFB.iterator();
I'd call buildFromFirebase();
我打电话给
buildFromFirebase();
in the constructor though, rather than waiting. 但是在构造函数中,而不是等待。
The second option would be to refactor UAMP to have it load the catalog asynchronously. 第二种选择是重构UAMP以使其异步加载目录。 This would be a lot more work, but it may result in a better design in the long run.
这将是一项更多的工作,但从长远来看,它可能会带来更好的设计。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.