从onCreateView方法外部更新片段中的ListView适配器

时间:2016-11-30 02:16:41

标签: android listview android-fragments

我正在尝试构建一个从JSON收到的ListView中填充ListView的应用程序。当我尝试使用notifyDataSetChanged更新列表视图时,我得到以下异常。

  

尝试调用虚方法' void   com.example.android.Wordtrend.CustomArrayAdapter.notifyDataSetChanged()'   在空对象引用上

ListView位于片段内。我使用onPostExecute方法调用片段内的更新方法来更新ArrayAdapter。 UI加载onCreateView方法中提供的虚拟数据,但在更新期间失败。

我是新手,所以任何建议都会有很大帮助。我很困惑,因为ArrayAdapter为null,并且updateArray的大小在update方法中为零。

活动:

公共类ClassicActivity扩展了AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activitycategory);
        getSupportFragmentManager().beginTransaction().replace(R.id.container,new ClassicFragment()).commit();
    }       
}

片段:

public class ClassicFragment extends Fragment {
    CustomArrayAdapter adapter;
    ArrayList<dataobjects> dataArray=new ArrayList<>();

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        dataArray.clear();
        dataArray.add(new dataobjects("word","Explanation",R.drawable.placeholder,R.raw.color_black));
        dataArray.add(new dataobjects("word","Explanation",R.drawable.placeholder,R.raw.color_black));
        dataArray.add(new dataobjects("word","Explanation",R.drawable.placeholder,R.raw.color_black));

        View rootView=inflater.inflate(R.layout.word_list,container,false);
        ListView listView=(ListView)rootView.findViewById(R.id.list);
        adapter=new CustomArrayAdapter(getActivity(),dataArray,R.color.classic);
        listView.setAdapter(adapter);
        return rootView;
    }


      public void update(ArrayList<FinalData> e){
         ArrayList<dataobjects> newDataArray=new ArrayList<>();  // update Adapter from JSON 
         for(int i=0;i<e.size();i++) {
           FinalData FinalDataObject = e.get(i);
           String word=FinalDataObject.getWord();
           String meaning=FinalDataObject.getMeaning();
           newDataArray.add(new dataobjects(word,meaning,R.drawable.placeholder,R.raw.color_black));         
          }

 Log.d("Classic"," Size of Data"+dataArray.size());   // Shows zero but im not clearing it manually. Should be two.


             dataArray.addAll(newDataArray);  // Size changes to 7 as expected.
               adapter.notifyDataSetChanged();

        }

//从Dataprocess类中调用update方法

public class Data extends AsyncTask<String,Void,String> {

        String Mdata;
        @Override
        protected void onPostExecute(String s) {
            Mdata=s;
            Dataprocess d=new Dataprocess();
            d.process(Mdata);
            super.onPostExecute(s);
        }.....}
public class Dataprocess {

    Finaldata f;
    ArrayList<Finaldata> wordList=new ArrayList<>();
    ClassicFragment classicfragment=new ClassicFragment();
    public void process(String s ){
        if(s!=null){
            try {
                JSONObject data = new JSONObject(s);
                JSONArray word = data.getJSONArray("WordArray");
                for (int i = 0; i < word.length(); i++){
                    JSONObject c = word.getJSONObject(i);
                    String word1=c.getString("word");
                    String meaning=c.getString("meaning");
                    f=new Finaldata(word1,meaning);
                    wordList.add(f);
                }
                classicfragment.update(wordList);
            }catch (Exception e){
            }
        }
    }
}

CustomArray适配器:

    public class CustomArrayAdapter extends ArrayAdapter<dataobjects> {
        int color;
        public  static MediaPlayer mediaPlayer;
        static AudioManager am;
        private TextToSpeech tts;

        static MediaPlayer.OnCompletionListener oncom=new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                release();
            }
        };

        public CustomArrayAdapter(Activity context, ArrayList<dataobjects> a, int color) {
            super(context,0,a);
            this.color=color;
        }

        @Override

        public View getView(int position, View convertView, ViewGroup parent) {

            View listitemview=convertView;
            if(listitemview==null){
                listitemview= LayoutInflater.from(getContext()).inflate(R.layout.customlayout,parent,false);
            }
            dataobjects currentword=getItem(position);
            TextView t1=(TextView)listitemview.findViewById(R.id.textView);
            TextView t2=(TextView)listitemview.findViewById(R.id.textView2);
            View background1=listitemview.findViewById(R.id.back);
            View background2=listitemview.findViewById(R.id.back2);
            background1.setBackgroundColor(colorid);
            background2.setBackgroundColor(colorid);
            int ex=currentword.getImageURL();
            int aud=currentword.getSound();
            t1.setText(currentword.getWord());
            t2.setText(currentword.getTransalation());
            int colorid= ContextCompat.getColor(getContext(),color);

            ImageView im1=(ImageView)listitemview.findViewById(R.id.media);

            im1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                     test();

                }
            });

            return listitemview;

        }

4 个答案:

答案 0 :(得分:0)

尝试将所有代码放在方法onActivityCreated()

答案 1 :(得分:0)

在您的片段中使用以下方法:

  1. dataArray.clear();
  2. dataArray = new ArraryList&lt;&gt;();
  3. dataArray = getListBynet();从网上获取数据
  4. newAdapter = new CustomArrayAdapter(dataArray);
  5. listView.setAdapter(newAdapter);
  6. 希望这很有用

答案 2 :(得分:0)

嗯,您已经将适配器作为片段类的字段,因此您只需要在CustomArrayAdapter中包含以下内容:

首先在适配器中为包含数据的ArrayList添加字段

private ArrayList<dataobjects> data;

并在适配器构造函数中,根据您传入的内容设置该字段的值:

public CustomArrayAdapter(Activity context, ArrayList<dataobjects> a, int color) {
        super(context, 0, a);

        this.data = a;

        this.color=color;
    }

然后添加一个新方法来更改适配器中的数据:

public void setItems(ArrayList<dataobjects> items){
    this.data = items;
    notifyDataSetChanged();
}

您还需要覆盖getItem()以从data字段返回该项目。

@Override
public dataobjects getItem(int position){
    return this.data.get(position);
}

然后,当您稍后更新适配器时,只需从您的片段中调用adapter.setItems(data);即可。

希望它有所帮助!

答案 3 :(得分:0)

您的代码有点复杂,但基本上发生的情况是,当您调用update()时,片段尚未初始化。

了解Fragment生命周期。

简而言之:

  • 您创建了一个片段(就像您的代码中使用new ClassicFragment())。到目前为止,只有Fragment构造函数被称为

  • 然后使用事务将其插入屏幕,例如

    FragmentTransaction ft = getFragmentManager()。beginTransaction(); ft.add(frame.getId(),mFragment).commit(); FragmentTransaction ft = getFragmentManager()。beginTransaction(); ft.add(frame.getId(),mFragment).commit();

  • 然后,异步地,Android渲染引擎将调用片段方法onAttach(),后跟其他类似onCreateView()onViewCreated()

在您的代码中,适配器在onViewCreated()中初始化,因此只有在插入并初始化片段后,您才能调用update()。如果您之前致电update,您将获得NullPointerException,因为适配器尚未初始化。

您需要重构代码,在片段未被引入时检测对update()的调用并推迟更新,或者稍后再调用update。