Android 我需要将一个对象数组转换为一个字符串数组,但它总是返回一个空指针
所以我试图从Firebase数据库收集数据,将其存储在ArrayList中,将ArrayList转换为对象数组,然后将其转换为字符串数组 在我尝试将ArrayList转换为对象数组之前,我的代码基本正常,然后我得到了一个空指针Android 我需要将一个对象数组转换为一个字符串数组,但它总是返回一个空指针,android,arrays,arraylist,firebase,firebase-realtime-database,Android,Arrays,Arraylist,Firebase,Firebase Realtime Database,所以我试图从Firebase数据库收集数据,将其存储在ArrayList中,将ArrayList转换为对象数组,然后将其转换为字符串数组 在我尝试将ArrayList转换为对象数组之前,我的代码基本正常,然后我得到了一个空指针 public class PostSkillsActivity extends AppCompatActivity { ArrayList<String> skills_array; Object[] mySkills; public
public class PostSkillsActivity extends AppCompatActivity {
ArrayList<String> skills_array;
Object[] mySkills;
public String[] skills;
private AutoCompleteTextView jobInputSkills;
private Button finishBtn;
private ImageButton addSkillsBtn;
private GridView gridView;
private DatabaseReference mDatabaseSkills;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_post_skills);
mDatabaseSkills = FirebaseDatabase.getInstance().getReference().child("Skills");
mDatabaseSkills.keepSynced(true);
mDatabaseSkills.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
collectSkills((Map<String,Object>) dataSnapshot.getValue());
}
@Override
public void onCancelled(DatabaseError databaseError) {}
});
jobInputSkills = (AutoCompleteTextView) findViewById(R.id.input_job_skills);
finishBtn = (Button) findViewById(R.id.skills_finish_btn);
addSkillsBtn = (ImageButton) findViewById(R.id.add_skills_btn);
addSkillsBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
didTapButton(v);
addSkill();
}
});
/**
* Populate Skills Auto Text View
*/
mySkills = skills_array.toArray();
skills = Arrays.copyOf(mySkills, mySkills.length, String[].class);;
ArrayAdapter<String> adapter = new ArrayAdapter<String>
(this, android.R.layout.simple_list_item_1, skills);
jobInputSkills.setAdapter(adapter);
/**
* GridView Functionality
*/
gridView = (GridView) findViewById(R.id.gridview);
gridView.setAdapter(new SkillsAdapter(this, skills));
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(
getApplicationContext(),
((TextView) view.findViewById(R.id.label))
.getText(), Toast.LENGTH_SHORT).show();
}
});
}
private void collectSkills(Map<String,Object> skills) {
skills_array = new ArrayList<>();
Iterator myVeryOwnIterator = skills.keySet().iterator();
while(myVeryOwnIterator.hasNext()) {
String key=(String)myVeryOwnIterator.next();
String value=(String)skills.get(key);
skills_array.add(value);
}
}
private void addSkill() {
String[] words = jobInputSkills.getText().toString().split(" ");
StringBuilder sb = new StringBuilder();
if (words[0].length() > 0) {
sb.append(Character.toUpperCase(words[0].charAt(0)) + words[0].subSequence(1, words[0].length()).toString().toLowerCase());
for (int i = 1; i < words.length; i++) {
sb.append(" ");
sb.append(Character.toUpperCase(words[i].charAt(0)) + words[i].subSequence(1, words[i].length()).toString().toLowerCase());
}
}
final String skill_name = sb.toString();
if(!TextUtils.isEmpty(skill_name)){
final DatabaseReference newSkill = mDatabaseSkills.child(skill_name);
newSkill.child(skill_name).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
}
else {
newSkill.setValue(skill_name);
}
}
@Override
public void onCancelled(DatabaseError databaseError) {}
});
}
}
public void didTapButton(View view) {
ImageButton button = (ImageButton)findViewById(R.id.add_skills_btn);
final Animation myAnim = AnimationUtils.loadAnimation(this, R.anim.bounce);
// Use bounce interpolator with amplitude 0.2 and frequency 20
MyBounceInterpolator interpolator = new MyBounceInterpolator(0.2, 20);
myAnim.setInterpolator(interpolator);
button.startAnimation(myAnim);
}
public class SkillsAdapter extends BaseAdapter {
private Context context;
private final String[] skillValues;
public SkillsAdapter(Context context, String[] skillValues) {
this.context = context;
this.skillValues = skillValues;
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
if (convertView == null) {
gridView = new View(context);
// get layout from mobile.xml
gridView = inflater.inflate(R.layout.skills_item, null);
// set value into textview
TextView textView = (TextView) gridView
.findViewById(R.id.label);
textView.setText(skillValues[position]);
// set image based on selected text
ImageView imageView = (ImageView) gridView
.findViewById(R.id.remove_skill_btn);
String skill = skillValues[position];
} else {
gridView = (View) convertView;
}
return gridView;
}
@Override
public int getCount() {
return skillValues.length;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
}
}
更新:
错误在第78行。首先是
mySkills = skills_array.toArray();
数组应包含函数中的值
private void collectSkills(Map<String,Object> skills) {
skills_array = new ArrayList<>();
Iterator myVeryOwnIterator = skills.keySet().iterator();
while(myVeryOwnIterator.hasNext()) {
String key=(String)myVeryOwnIterator.next();
String value=(String)skills.get(key);
skills_array.add(value);
}
}
Firebase中的ValueListener是异步的,这意味着它们不会阻止添加它们的代码。在您的代码中,您似乎假设将立即调用侦听器。相反,实际发生的情况是,在添加侦听器之后,onCreate方法仍在继续,这意味着在访问它时,skills_数组仍处于未初始化状态(null)
您应该等到监听器实际被调用之后,才能使用从中收集的数据更新UI。onCreate期间无法执行此操作。请添加堆栈跟踪。谢谢您的评论。我刚刚修复了帖子。PostSkillsActivity.java的第78行是什么?同步与异步并不是真正的问题。理解事件和听众是非常重要的。(这里只是吹毛求疵的措辞……您的答案的内容通常是正确的。)Firebase文档的作者认为,从一开始就需要注意的一个重要区别是:“Firebase数据写入FirebaseDatabase引用,并通过将异步侦听器附加到该引用来检索。”好的,感谢您的反馈。如何确保首先调用ValueEventListener。到目前为止,我已经尝试将更新数据的代码移动到onStart()方法和collectSkills函数中,但还没有成功。是的,在这种情况下侦听器是异步的。但是,无论使用何种线程模型,在添加侦听器时都不会立即调用它们。重要的是,要避免事件通知(异步)与状态通知(同步)之间可能出现的混淆。预先声明它是异步的,这无疑澄清了这种区别。
private void collectSkills(Map<String,Object> skills) {
skills_array = new ArrayList<>();
Iterator myVeryOwnIterator = skills.keySet().iterator();
while(myVeryOwnIterator.hasNext()) {
String key=(String)myVeryOwnIterator.next();
String value=(String)skills.get(key);
skills_array.add(value);
}
}
02-21 20:34:32.647 4153-4153/com.example.android.oddjobs E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.oddjobs, PID: 4153
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.android.oddjobs/com.example.android.oddjobs.PostSkillsActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object[] java.util.ArrayList.toArray()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2572)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2654)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1488)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5728)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object[] java.util.ArrayList.toArray()' on a null object reference
at com.example.android.oddjobs.PostSkillsActivity.onCreate(PostSkillsActivity.java:78)
at android.app.Activity.performCreate(Activity.java:6301)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1113)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2519)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2654)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1488)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5728)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
02-21 20:34:34.022 4153-4239/com.example.android.oddjobs
E/NativeCrypto: ssl=0xaf9bb6c0 cert_verify_callback x509_store_ctx=0x9a87820c arg=0x0
02-21 20:34:34.022 4153-4239/com.example.android.oddjobs E/NativeCrypto: ssl=0xaf9bb6c0 cert_verify_callback calling verifyCertificateChain authMethod=ECDHE_RSA