Android 我需要将一个对象数组转换为一个字符串数组,但它总是返回一个空指针

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

所以我试图从Firebase数据库收集数据,将其存储在ArrayList中,将ArrayList转换为对象数组,然后将其转换为字符串数组

在我尝试将ArrayList转换为对象数组之前,我的代码基本正常,然后我得到了一个空指针

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