How to store and retrive RecyclerView Items for offline use

2.1k Views Asked by At

Guys please dont make this question as a duplicate as I have not found any simple or easy implementation of realm in my app. I am in the process of creating a chat app and what I want to do is make it possible for the user to be able to access and read earlier messages that he received even without internet connection.

In short I want my app to be still accessible without an internet connection but am finding it difficult doing that as am new to local data storage.

Below are my codes for your perusal:

Fragment

public class ChatFragment extends Fragment {

public RecyclerView mChatsList;
public View mView;
public List<ChatsModel> mChatsModel;
public ChatsAdapter mChatsAdapter;
private Realm realm;


public ChatFragment() {
    // Required empty public constructor
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    mView = inflater.inflate(R.layout.fragment_chat, container, false);
    ((AppCompatActivity) getActivity()).getSupportActionBar().setShowHideAnimationEnabled(true);
    initUI();
    realm = Realm.getDefaultInstance();
    return mView;
}

//Method and views initializer
public void initUI() {

    mChatsList = (RecyclerView) mView.findViewById(R.id.chatsList);

    LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());

    mChatsModel = new ArrayList<ChatsModel>();
    mChatsAdapter = new ChatsAdapter(getActivity(), mChatsModel);
    mChatsList.setLayoutManager(layoutManager);
    mChatsList.setHasFixedSize(true);
    mChatsAdapter.notifyDataSetChanged();
    mChatsList.setAdapter(mChatsAdapter);
    RecyclerView.ItemAnimator itemAnimator = new DefaultItemAnimator();
    itemAnimator.setAddDuration(1000);
    itemAnimator.setRemoveDuration(1000);
    mChatsList.setItemAnimator(itemAnimator);
    prepareItems();

    Realm realm = Realm.getInstance(getActivity());
    realm.executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            ChatsModel chat = realm.createObject(ChatsModel.class);
            chat.setUsername("username");
            chat.setDate("date");
            chat.setPicture("Picture");
        }
    }, new Realm.Transaction.Callback() {
        @Override
        public void onSuccess() {
            Main.Mess(getString(R.string.real_sucess));
        }

        @Override
        public void onError(Exception e) {
            Main.Mess(getString(R.string.real_error));
        }
    });

}



// This is a simple method to add items to our recyclerview
private void prepareItems() {
    Rests mRests = RestService.createService(Rests.class, Session.getToken(getActivity()));
    mRests.suggest(new Callback<List<ChatsModel>>() {
        @Override
        public void success(List<ChatsModel> mChatsModel, Response response) {
            RealmList<ChatsModel> mChatsModel2 = new RealmList<ChatsModel>();
            mChatsAdapter.setUsers(mChatsModel);

        }

        @Override
        public void failure(RetrofitError error) {
            Main.Mess(getString(R.string.server_error));
        }
    });
}

}

My Adapter

public class ChatsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
private RealmList<ChatsModel> mChatsModel;
private Realm realm;
public Activity mActivity;

public ChatsAdapter(@NonNull Activity mActivity) {
    super();
    this.mChatsModel = new RealmList<>();
    this.realm = Realm.getDefaultInstance();
    this.mActivity = mActivity;
}


@Override
public RecyclerView.ViewHolder onCreateViewHolder (ViewGroup parent, int viewType) {
    if(viewType == TYPE_HEADER) {
        View v = LayoutInflater.from (parent.getContext ()).inflate (R.layout.ad_view, parent, false);
        return new HeaderViewHolder (v);
    } else if(viewType == TYPE_ITEM) {
        View v = LayoutInflater.from (parent.getContext ()).inflate (R.layout.chats_item, parent, false);
        return new ContentViewHolder (v);
        }
    return null;
}

private ChatsModel getItem (int position) {
    return mChatsModel.get (position);
}

@Override
public void onBindViewHolder (RecyclerView.ViewHolder holder, final int position) {
    if (holder instanceof HeaderViewHolder) {
        HeaderViewHolder headerHolder = (HeaderViewHolder) holder;
        if (Constant.SHOW_ADS) {
            headerHolder.mAdView.setVisibility(View.VISIBLE);
            AdRequest adRequest = new AdRequest.Builder().build();
            headerHolder.mAdView.loadAd(adRequest);
        } else {
            headerHolder.mAdView.setVisibility(View.GONE);
        }
    }else if (holder instanceof ContentViewHolder) {
        ContentViewHolder contentHolder = (ContentViewHolder) holder;
        ChatsModel item  = getItem (position - 1);

        contentHolder.username.setText(item.getUsername());
        contentHolder.date.setText(item.getDate());
        contentHolder.message.setText(item.getMessage());

        Picasso.with(mActivity.getApplicationContext())
                .load(Constant.IMAGE_SMALL + item.getPicture())
                .error(R.drawable.user)
                .into(contentHolder.picture);
    }
}

@Override
public int getItemViewType (int position) {
    if(isPositionHeader (position)) {
        return TYPE_HEADER;
    }
    return TYPE_ITEM;
}

public void setUsers(RealmList<ChatsModel> friendsItems) {
    this.mChatsModel = friendsItems;
    notifyDataSetChanged();
}

public List<ChatsModel> getSuggestionsModel() {
    return this.mChatsModel;
}

private boolean isPositionHeader (int position) {
    return position == 0;
}


@Override
public int getItemCount () {
    return mChatsModel.size ();
}


public class HeaderViewHolder extends RecyclerView.ViewHolder {
    public AdView mAdView;

    public HeaderViewHolder(View itemView) {
        super(itemView);
        mAdView = (AdView) itemView.findViewById(R.id.ad_view);
    }
}
public class ContentViewHolder extends RecyclerView.ViewHolder {

    public ImageView picture;
    public TextView username, date, message;
    public LinearLayout chat;

    public ContentViewHolder(View v) {
        super(v);
        picture = (ImageView) v.findViewById(R.id.picture);
        username = (TextView) v.findViewById(R.id.username);
        date = (TextView) v.findViewById(R.id.date);
        message = (TextView) v.findViewById(R.id.message);
    }
}
}

Okay so thats my code.

2

There are 2 best solutions below

0
On

You can use a SQLite database for storing the chats offline, watch this YouTube tutorial, it is extensive but you can skip through some parts.

When downloading/sending chat messages, mirror them into your database and use the database and ONLY THE DATABASE as the data source for your RecyclerView (never let any online data directly go into the list, always store it in the database first and read it from the database when putting it into your layout).

To improve performance, you can store relevant chat messages in memory (in a separate ArrayList for example) instead of always reading data from the DB that you just wrote into it.

0
On

As @geisshirt says in comment, use RealmRecyclerViewAdapter instead of RecyclerView.Adapter. Couple words about android realm adapters you can found in official doc.

Also, you can look at RealmRecyclerViewAdapter example