2017-02-21 20 views
1

Так что я пытаюсь собрать данные из своей базы данных Firebase, сохранить их в ArrayList, преобразовать этот массив ArrayList в массив объектов, а затем преобразовать этот к String Array.Мне нужно преобразовать массив объектов в массив строк, но он продолжает возвращать нулевой указатель

Мой код работает, пока я не попытаюсь преобразовать свой массив 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; 
     } 

    } 
} 

Вот моя база данных Firebase. Мне нужно сохранить все значения для дочерних элементов в массиве, чтобы заполнить AutoTextView.

Skills: 
Android:"Android" 
C++ Programming:"C++ Programming" 
Carpentry:"Carpentry" 
Electrician:"Electrician" 
HTML:"HTML" 
Housework:"Housework" 

Update: Ошибка в строке 78. Это начинается с

mySkills = skills_array.toArray(); 

skills_array должен содержать значения из функции

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 
+1

Пожалуйста, добавьте трассировку стека. – markers

+0

Спасибо за ваш комментарий. Я только что зафиксировал сообщение. –

+0

Что такое строка 78 PostSkillsActivity.java? –

ответ

1

ValueListeners в Firebase асинхронно, что означает, что они не будут блокировать код, который добавляет их. В вашем коде, похоже, вы предполагаете, что прослушиватель будет немедленно вызван. Вместо этого то, что на самом деле происходит, заключается в том, что ваш метод onCreate продолжается после добавления слушателя, а это означает, что skill_array остается неинициализированным (null) при его доступе.

Вы должны подождать, пока слушатель фактически не будет вызван, чтобы обновить ваш пользовательский интерфейс с данными, которые собираются с него. Вы не можете сделать это во время onCreate.

+0

Синхронный и асинхронный не является проблемой. Понимание событий и слушателей. (Как раз вот, выбирая формулировку здесь ... содержание вашего ответа в целом правильное.) –

+0

Авторы документов Firebase считают, что с самого начала было важно отметить: «Данные Firebase записываются в ссылку FirebaseDatabase и извлекаются путем присоединения асинхронного слушателя к ссылке ». https://firebase.google.com/docs/database/android/read-and-write –

+0

Хорошо, спасибо за отзыв. Как именно я гарантирую, что сначала будет вызван ValueEventListener. До сих пор я пытался переместить код для обновления данных к методу onStart() и функции collectSkills, но он еще не сработал. –