Convenient display of an empty list

Sometimes the user needs to show a prompt when the required data is missing. For example, an empty list, a server error, or no Internet connection. What should be done in the case when the hint should be complex and different for each of the cases? The implementation below should address these issues.





The bottom line is that the duty to display auxiliary information is assigned to a separate object. This gives more correct separation of logic and less code in the activity. Let's proceed to a more detailed description of the implementation.





Each hint is a separate fragment that can contain anything. To manage them, the object needs a FragmentManager and the Id of the container in which the fragments should reside. There are no more dependencies.





Each situation is an enumeration element (everything will become very clear with the code) nested in this object. When a hint needs to be changed, the method responsible for the replacement will be called, to which the new situation will be passed. This is all logic.





Now this must be done in the realities of Android. Except for the activity itself (or a fragment) that needs an object, no one else will refer to it. There is an initial, "Default" state. It will be displayed the first time it appears, until a new value appears. The values ​​themselves are stored in LiveData (which is in the ViewModel), which the activity subscribes to and passes each new one to the object. This allows you to experience re-creation of activity and maintain state.





I decided to use HTTP status codes as an example, but any can be used. For example, when querying a database of films with conditions about release date, director, actors, etc. different clues can be shown: there is no required actor, no film on this date, this director has no such films, etc.





Nuances

If, for example, you do not clear the list of data, then the hint can be displayed above (or below) this list, which will be ugly. To do this, you must first clear the list (or hide its visibility, which is better?).





Implementation





CodeSwitcher.

CodeSwitcher. I couldn't think of an adequate name.









//  
public class CodeSwitcher {
    //  
    public enum Code {
        DEFAULT,

        HTTP_OK,
        HTTP_CREATED,
        HTTP_BAD_REQUEST,
        HTTP_NOT_FOUND,

        NO_DATA
    }

    //
    private FragmentManager fragmentManager;
    private int fragmentHostId;

    public CodeSwitcher(FragmentManager fragmentManager, int fragmentHostId) {
        this.fragmentManager = fragmentManager;
        this.fragmentHostId = fragmentHostId;
    }

    //,    
    public void switchFragments(Code code) {
        FragmentTransaction transaction = fragmentManager.beginTransaction();

        switch (code) {
            case HTTP_OK:
                transaction.replace(fragmentHostId, CodeFragment.newInstance("HTTP_OK"));
                break;

            case HTTP_CREATED:
                transaction.replace(fragmentHostId, CodeFragment.newInstance("HTTP_CREATED"));
                break;

            case HTTP_BAD_REQUEST:
                transaction.replace(fragmentHostId, CodeFragment.newInstance("HTTP_BAD_REQUEST"));
                break;

            case HTTP_NOT_FOUND:
                transaction.replace(fragmentHostId, CodeFragment.newInstance("HTTP_NOT_FOUND"));
                break;

            case NO_DATA:
                transaction.replace(fragmentHostId, CodeFragment.newInstance("NO_DATA"));
                break;

            default:
                transaction.replace(fragmentHostId, CodeFragment.newInstance("Default"));
                break;
        }

        transaction.commit();
    }
}
      
      



// ViewModel

//     
public CodeShowActivityViewModel() {
    listCode = new MutableLiveData<>();
    listCode.setValue(CodeSwitcher.Code.DEFAULT);
}

//   ,    ,    
public void httpOk() {
  listCode.setValue(CodeSwitcher.Code.HTTP_OK);
  clearList();
}

public void httpBadRequest() {
  listCode.setValue(CodeSwitcher.Code.HTTP_BAD_REQUEST);
  clearList();
}
      
      



// ,   
private CodeSwitcher switcher;

// onCreate()
switcher = new CodeSwitcher(getSupportFragmentManager(), R.id._);

//  LiveData,    
codeActVM.getListCode().observe(this, code -> {
  switcher.switchFragments(code);
});
      
      



GIF (4MB) with description

From the very beginning, a default state appears, it is specially displayed in the background, but in reality it should be empty. Then the receipt of various codes and their display is emulated. At the end, it is shown that the state persists even when the activity is recreated.









What do you think of this method?





PS

Trouble with the names ...












All Articles