Failure Solution for adapter.notifyDataSetChanged()

Keywords: network Retrofit Java Android

Speaking of this method, I believe that almost every touch of Android development has been used, but many times it is not our wrong use, but inadvertently caused us. Notfy DataSetChanged () suddenly lost its effect, let us feel confused. Here are three solutions based on our own experience in using. Law.

1. The data source is not updated and the call notify DataSetChanged is invalid.

In view of this, we can interrupt point to see that the change of data source transmission has not been solved.

2. The data pointed to by the address of the data set bound at adapter initialization has not been changed.

This sentence sounds awkward to us. Let me write an example to analyze it.

//Data requested by the network  
public List<String> mDatas== new ArrayList<>();;  

/**
* Network Request
*/      
@Override
protected void initViews(Bundle savedInstanceState) {
    MyAdapter mAdapter = new MyAdapter();  
    mListView.setAdapter(mAdapter);  

        dogetData();
    }
 private void dogetData() {
    //Network Request Code Comments
      mDatas=response.getResult();//* Represents the successful writing of a network request*
      for(int i=0;i<response.getResult().size();i++){  //* Represents the successful writing of network requests II*
        mDatas.add(response.getResult().get(i));  
    }  
    //----------====
    refreshUI();
  }
  public void refreshUI(){   
    //Refresh adapter  
    mAdapter.notifyDataSetChanged();  
}

/** Custom adapters */  
class MyAdapter extends BaseAdapter{  

    @Override  
    public int getCount() {  
        if(mDatas!=null){  
            return mDatas.size();  
        }  
        return 0;  
    }  

    @Override  
    public Object getItem(int position) {  
        if(mDatas!=null){  
            return mDatas.get(position);  
        }  
        return null;  
    }  

    @Override  
    public long getItemId(int position) {  
        return position;  
    }  

    @Override  
    public View getView(int position, View convertView, ViewGroup parent) {  
        TextView tv = new TextView(getActivity());  
        tv.setText(mDatas.get(position));  
        return tv;  
    }  
}  

To observe the above two ways of writing the network request part, first of all, I want to point out that the first way is wrong, and the second way is correct. When we inadvertently write as Write 1, the adapter adapter adapter does not refresh. We know that the basic types and objects in Java are passed by value. A method cannot modify the parameters of a basic data type. A method can modify the state of the object to which a reference refers, but it is still the same. Call by value instead of by reference, both of the above passes are copied.

mDatas=response.getResult()

Our assignment is problematic. Here we have a new object set to mDatas, which is a reference value copy process, and here it is a shallow copy. Java Copy Concept Open up a space from heap memory for the created object, so mDatas will redirect to the address of the new space without pointing to the address pointed to in the original initialization process, so
When notify DataSetChanged refreshes, the data source on the original address does not change, so the refresh fails. The correct way to write it is as follows:

for(int i=0;i<response.getResult().size();i++){  
     mDatas.add(response.getResult().get(i));  
 }

3. Callback or asynchronous (thread scheduling).

public List<NewsInfo > mDatas== new ArrayList<>();
      Retrofit retrofit = new Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//New configuration
            .baseUrl(BASE_URL)
            .build();
      MyService service = retrofit.create(MyService.class);

      service.news(userid, token,index)               //Getting Observable Object
              .subscribeOn(Schedulers.newThread())//Request execution in a new thread
              .observeOn(Schedulers.io())         //Execute the request in the io thread after completion
              .doOnNext(new Action1<List<NewsInfo >>() {
                  @Override
                  public void call(List<NewsInfo > newsInfos) {
                      saveInfo(newsInfos);//Save information locally
//                     refreshUI(newsInfos); //Location 1
                  }
              })
              .observeOn(AndroidSchedulers.mainThread())//Finally, it executes in the main thread
              .subscribe(new Subscriber<List<NewsInfo >>() {
                  @Override
                  public void onCompleted() {

                  }

                  @Override
                  public void onError(Throwable e) {
                      //request was aborted
                  }

                  @Override
                  public void onNext(List<NewsInfo >newsInfos) {
                      //Successful request
                     refreshUI(newsInfos);//Location 2
                  }
              });   
            public void refreshUI(List<NewsInfo >newsInfos){   
             //Refresh adapter
             for (NewsInfo news : newsInfos) {
                           mDatas.add(news );
                   }  
                mAdapter.notifyDataSetChanged();  
           }    

Here we use RxJava to show the process of network asynchronous requests simply and clearly. When we update the refresh at location one, it is certainly not possible because we operate ui in sub-threads, but it is possible to update at location two, but we must not forget to add a switch to ui thread or use handler. Pay attention to sending it to the main thread.

Posted by psytae on Wed, 17 Jul 2019 14:52:19 -0700