MultiAutoCompleteTextView 和 Firebase
MultiAutoCompleteTextView and Firebase
我有一个存储在 Firebase 中的标签列表。在我的一个片段中,MultiAutoCompleteTextView (MACTV) 允许用户 select 相关标签。
objective,
- 是使用
来自 Firebase 的标签。
- 一旦用户select从 MACTV 使用
OnItemClickListener,selected 标签需要保存到
Firebase.
以下是我尝试实施的方式。
为 MACTV 定义 ArrayAdapter:
ArrayAdapter<String> adapterMultiAutoComplete = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1);
使用 AddValueEventListener 填充 ArrayAdapter
if (fbUser != null) {
dbTags.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Basically, this says "For each DataSnapshot *Data* in dataSnapshot, do what's inside the method.
for (DataSnapshot tagNameSnapshot : dataSnapshot.getChildren()) {
//Get the suggestion by childing the key of the string you want to get.
String ValueTagName = tagNameSnapshot.child("tagName")).getValue(String.class);
//Add ValueTagName to ArrayAdapter
adapterMultiAutoComplete.add(ValueTagName);
}
}
@Override
public void onCancelled(DatabaseError databaseError) {/*Do Nothing*/}
});
}
MACTV 代码
MultiAutoCompleteTextView articleTags = (MultiAutoCompleteTextView) findViewById(R.id.mactv_tags);
articleTags.requestFocus();
articleTags.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
articleTags.setAdapter(adapterMultiAutoComplete);
将 selected 标签保存到 Firebase
List<String> ArticleTags = new ArrayList<>(Arrays.asList(articleTags.getText().toString().split(", ")));
DatabaseReference db = FirebaseDatabase.getInstance().getReference().child("tags").setValue(ArticleTags);
阈值定义为 2。不幸的是,当我开始在 MACTV 中输入时,没有相关标签弹出。
我哪里错了?
顺便说一句,好问题!这个月我看到的最有趣的。
首先,使用此代码将整个 tags
节点加载到设备。想象一下,你有 2M 的标签(SO 有吗?),这段代码还能用吗? ;)
第二件事,onDataChange
中的代码(以及所有 firebase 回调中的代码)在工作线程上调用,但适配器方法应在 UI 线程中调用。
最后,这是我看到的解决方案:
- 您需要使用查询(您可以在 docs 中阅读更多内容)
首先,我们需要按名称对标签进行排序。所以这是基本查询:
DatabaseReference baseRef = FirebaseDatabase.getInstance().getReference().child("tags").orderByChild("tagName");
接下来 - 您必须使用以下代码
将 TextWatcher
附加到您的 MultiAutoCompleteTextView
articleTags.addTextChangedListener(new TextWatcher() {
@Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (charSequence.length <3) return;
String searchTarget = charSequence.toString().toLowerCase();
//Here magic happens)
baseRef.startAt(searchTarget).endAt(searchTarget + "\uf8ff").limitToFirst(20).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Handle executing this code in main thread yourself, answer will be too long with it
adapterMultiAutoComplete.removeAll();
for (DataSnapshot data: dataSnapshot.getChildren()) {
adapterMultiAutoComplete.add(data.getValue(String.class))
}
adapterMultiAutoComplete.notifyDatasetChanged();
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.wtf("What a terrible failure!", databaseError.toException());
}
});
}
@Override public void afterTextChanged(Editable editable) {}
});
P.S.: 代码从未测试过,可能无法运行。但是你明白了 ;)
我有一个存储在 Firebase 中的标签列表。在我的一个片段中,MultiAutoCompleteTextView (MACTV) 允许用户 select 相关标签。
objective,
- 是使用 来自 Firebase 的标签。
- 一旦用户select从 MACTV 使用 OnItemClickListener,selected 标签需要保存到 Firebase.
以下是我尝试实施的方式。
为 MACTV 定义 ArrayAdapter:
ArrayAdapter<String> adapterMultiAutoComplete = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1);
使用 AddValueEventListener 填充 ArrayAdapter
if (fbUser != null) {
dbTags.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Basically, this says "For each DataSnapshot *Data* in dataSnapshot, do what's inside the method.
for (DataSnapshot tagNameSnapshot : dataSnapshot.getChildren()) {
//Get the suggestion by childing the key of the string you want to get.
String ValueTagName = tagNameSnapshot.child("tagName")).getValue(String.class);
//Add ValueTagName to ArrayAdapter
adapterMultiAutoComplete.add(ValueTagName);
}
}
@Override
public void onCancelled(DatabaseError databaseError) {/*Do Nothing*/}
});
}
MACTV 代码
MultiAutoCompleteTextView articleTags = (MultiAutoCompleteTextView) findViewById(R.id.mactv_tags);
articleTags.requestFocus();
articleTags.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
articleTags.setAdapter(adapterMultiAutoComplete);
将 selected 标签保存到 Firebase
List<String> ArticleTags = new ArrayList<>(Arrays.asList(articleTags.getText().toString().split(", ")));
DatabaseReference db = FirebaseDatabase.getInstance().getReference().child("tags").setValue(ArticleTags);
阈值定义为 2。不幸的是,当我开始在 MACTV 中输入时,没有相关标签弹出。
我哪里错了?
顺便说一句,好问题!这个月我看到的最有趣的。
首先,使用此代码将整个 tags
节点加载到设备。想象一下,你有 2M 的标签(SO 有吗?),这段代码还能用吗? ;)
第二件事,onDataChange
中的代码(以及所有 firebase 回调中的代码)在工作线程上调用,但适配器方法应在 UI 线程中调用。
最后,这是我看到的解决方案:
- 您需要使用查询(您可以在 docs 中阅读更多内容)
首先,我们需要按名称对标签进行排序。所以这是基本查询:
DatabaseReference baseRef = FirebaseDatabase.getInstance().getReference().child("tags").orderByChild("tagName");
接下来 - 您必须使用以下代码
将TextWatcher
附加到您的MultiAutoCompleteTextView
articleTags.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {} @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { if (charSequence.length <3) return; String searchTarget = charSequence.toString().toLowerCase(); //Here magic happens) baseRef.startAt(searchTarget).endAt(searchTarget + "\uf8ff").limitToFirst(20).addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { //Handle executing this code in main thread yourself, answer will be too long with it adapterMultiAutoComplete.removeAll(); for (DataSnapshot data: dataSnapshot.getChildren()) { adapterMultiAutoComplete.add(data.getValue(String.class)) } adapterMultiAutoComplete.notifyDatasetChanged(); } @Override public void onCancelled(DatabaseError databaseError) { Log.wtf("What a terrible failure!", databaseError.toException()); } }); } @Override public void afterTextChanged(Editable editable) {} });
P.S.: 代码从未测试过,可能无法运行。但是你明白了 ;)