1

Ok so I am trying to sort a recyclerView that has been initialized in the beginning from a XML. I can see the emails when I start the app and I can also click on them. The button to sort is located in Settings activity but whenever I come back to my main activity where my RecyclerView is, after clicking the button, my recyclerView goes blank.

Here is my MainActivity

package com.example.assignment_1;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    //Variables
    private ArrayList<String> mNames = new ArrayList<>();
    private ArrayList<String> mImageurls = new ArrayList<>();
    private ArrayList<String> mHeaders = new ArrayList<>();
    private ArrayList<String> mContent = new ArrayList<>();
    static ArrayList<AssignmentEmail> emails = new ArrayList<>();
    private RecyclerViewAdapdter adapter;
    private RecyclerView recyclerView;
    private Context mContext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        EmailProvider emailProvider = new EmailProvider();
        Context context = getApplicationContext();
        if(emails.isEmpty() == true){
            emails = emailProvider.getEmails(context);
            loadEmails();
        }
    }

    private void loadEmails(){
        Log.d(TAG, "loadEmails: initBitmaps Called");
        for(int i = 0; i < emails.size(); i++) {
            mImageurls.add("@drawable/e1.jpg");
            mNames.add(emails.get(i).getAuthor());
            mHeaders.add(emails.get(i).getTitle());
            mContent.add(emails.get(i).getBody());
        }
        initRecyclerView();
    }

    public static ArrayList<AssignmentEmail> getEmails(){
        return emails;
    }

    public void sortEmails(ArrayList<AssignmentEmail> arrayOfEmails){
        Comparator<AssignmentEmail> compareByAuthor = (AssignmentEmail o1, AssignmentEmail o2) -> o1.getAuthor().compareTo( o2.getAuthor());
        Collections.sort(arrayOfEmails, compareByAuthor);
        mImageurls.clear();
        mNames.clear();
        mHeaders.clear();
        mContent.clear();
        for(int i = 0; i < arrayOfEmails.size(); i++) {
            mImageurls.add("@drawable/e1.jpg");
            mNames.add(arrayOfEmails.get(i).getAuthor());
            mHeaders.add(arrayOfEmails.get(i).getTitle());
            mContent.add(arrayOfEmails.get(i).getBody());
        }
        adapter = new RecyclerViewAdapdter(mImageurls,mNames,mHeaders,mContent,this);
        adapter.notifyDataSetChanged();
    }

    private void initRecyclerView(){
        Log.d(TAG, "initRecyclerView: init RecyclerView");
        recyclerView  = findViewById(R.id.recyclerview);
        adapter = new RecyclerViewAdapdter(mImageurls,mNames,mHeaders,mContent,this);
        recyclerView.setAdapter(adapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate activity menu items.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item){
        int id = item.getItemId();

        if (id == R.id.action_settings){
            Intent intent = new Intent(getApplicationContext(), Settings.class);
            startActivity(intent);
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

Here is my RecyclerViewAdapter

package com.example.assignment_1;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import de.hdodenhof.circleimageview.CircleImageView;

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

    private static final String TAG = "RecyclerViewAdapter";
    private ArrayList<String> mImages = new ArrayList<>();
    private ArrayList<String> mEmailTitle = new ArrayList<>();
    private ArrayList<String> mEmailHeader = new ArrayList<>();
    private ArrayList<String> mEmailContent = new ArrayList<>();
    private Context mContext;

    public RecyclerViewAdapdter(ArrayList<String> mImages, ArrayList<String> mEmailTitle, ArrayList<String> mEmailHeader, ArrayList<String> mEmailContent, Context mContext) {
        this.mImages = mImages;
        this.mEmailTitle = mEmailTitle;
        this.mEmailHeader = mEmailHeader;
        this.mEmailContent = mEmailContent;
        this.mContext = mContext;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
        Log.d(TAG, "onBindViewHolder: Called");

        Glide.with(mContext)
                .asBitmap()
                .load(mImages.get(position))
                .into(holder.Image);

        holder.email_from.setText(mEmailTitle.get(position));
        holder.email_header.setText(mEmailHeader.get(position));
        holder.email_contents.setText(mEmailContent.get(position));
        holder.Email_interface.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Log.d(TAG, "onClick: Email Clicked");
                //Toast.makeText(mContext, mEmailTitle.get(position),Toast.LENGTH_SHORT).show();
                Intent intent = new Intent(mContext.getApplicationContext(), LayoutItemsActivity.class);
                intent.putExtra("EmailFrom",mEmailTitle.get(position));
                intent.putExtra("EmailHeader",mEmailHeader.get(position));
                intent.putExtra(("EmailContents"),mEmailContent.get(position));
                mContext.startActivity(intent);
            }
        });
    }

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


    public class ViewHolder extends RecyclerView.ViewHolder{

        CircleImageView Image;
        TextView email_from;
        TextView email_header;
        TextView email_contents;
        RelativeLayout Email_interface;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            Image = itemView.findViewById(R.id.image);
            email_from = itemView.findViewById(R.id.EmailFrom);
            email_header = itemView.findViewById(R.id.EmailHeader);
            email_contents = itemView.findViewById(R.id.EmailContents);
            Email_interface = itemView.findViewById(R.id.email_interface);
        }
    }
}

Here is where my button is located


package com.example.assignment_1;

import android.content.Intent;
import android.os.Bundle;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

import android.view.View;
import android.widget.Button;

import java.util.ArrayList;

public class Settings extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_settings);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        Button resetButton = findViewById(R.id.button2);
        resetButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                MainActivity mainActivity = new MainActivity();
                ArrayList<AssignmentEmail> emailArray = mainActivity.getEmails();
                mainActivity.sortEmails(emailArray);
            }
        });
    }

}
emiclo007
  • 49
  • 4
  • you can't access method like you have used. because 'new MainActivity()' every time create new instance of class not an instance of current activity. – Abhay Koradiya Oct 04 '19 at 05:02
  • Creating a new Instance won't be helpfull try creating a bean class to hold data then sort it from other activity once the activity with RecyclerView is resumed use onResume() to notifyDataSetChanged, use null checks in onResume – trinadh thatakula Oct 04 '19 at 05:12

3 Answers3

1

If you still want to refresh the recycler view from setting activity use this library.

https://github.com/greenrobot/EventBus

Implementation link

https://stackoverflow.com/a/40987755/6452937

You can't communicate between activities like you mentioned.

Malavan
  • 789
  • 7
  • 27
1

From your MainActivity call the Settings using startActivityForResult() method

For example:

    if (id == R.id.action_settings){
        Intent intent = new Intent(getApplicationContext(), Settings.class);
        startActivityForResult(intent,1);
        return true;
    }

In your Settings Activity set the data which you want to return back to MainActivity. If you don't want to return back, don't set any.

resetButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent returnIntent = new Intent();
                setResult(Activity.RESULT_OK,returnIntent);
                finish();
            }
        });

Now in you main activity you have to write following code for the onActivityResult() method.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    if (requestCode == 1) {
        if(resultCode == Activity.RESULT_OK){
            // here you can sorting your recyclerview
            sortEmails(getEmails());
        }
        if (resultCode == Activity.RESULT_CANCELED) {
            //Write your code if there's no result
        }
    }
}

Another way

If you don't want to terminate your setting activity after resetbutton clicked then you can use shared preference.

Example

public class SharedPrefManager{
  private static SessionManager jInstance;
  private final SharedPreferences prefs;
  private final SharedPreferences.Editor editor;

  // private constructor to force use of 
  // getInstance() to create Singleton object 
  private SharedPrefManager(Context context) {
      prefs = context.getSharedPreferences("Your_Preference_name", Context.MODE_PRIVATE);
      editor = prefs.edit();
  }

  // create the instance when it is accessed for the first time
  public static synchronized SharedPrefManager getInstance(Context context) {
      if (jInstance != null) {
          return jInstance;
      } else {
          jInstance = new SharedPrefManager(context);
          return jInstance;
      }
  }

  
  public void isSortedByEmail(boolean emailSorting){
      editor.putString("emailSorting",emailSorting);
      editor.apply();
  }

 
  public boolean isSortedByEmail(){
      return prefs.getBoolean("emailSorting",false);
  }
}

In your setting activity you have to do like below

resetButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
      SharedPrefManager.getInstance(context).isSortedByEmail(true);
    }
});

And in your main activity inside your onStart()

@Override
protected void onStart(){
   super.onStart();
   if(SharedPrefManager.getInstance(context).isSortedByEmail()){
     // here you can sorting your recyclerview
     sortEmails(getEmails());
   }
}
Nimantha
  • 6,405
  • 6
  • 28
  • 69
Jakir Hossain
  • 3,830
  • 1
  • 15
  • 29
  • it needs the setting activity to terminated which is not a good practice. – Malavan Oct 04 '19 at 05:21
  • @CoderMal if you call `setting activity` from `main activity` and then when you go back to` main activity` from `setting activity` by pressing back button it will also terminate the `setting activity`. is not it? – Jakir Hossain Oct 04 '19 at 05:24
  • You are making the thing mandatory. It shouldn't be mandatory. – Malavan Oct 04 '19 at 05:26
  • why not? when you change some settings in setting activity and after that you wanna go back to your parent activity so how you will go then? – Jakir Hossain Oct 04 '19 at 05:29
  • Think it from a user perspective, After clicking the refresh button, activity getting terminated. The setting activity may contain some other setting also which may be he wants to change. Whatever, He is not supposed to put the refresh button in it setting activity. It should be in main activity it self. – Malavan Oct 04 '19 at 05:39
  • @CoderMal I got you. you are right. I have updated my answer with another way. Thanks. – Jakir Hossain Oct 04 '19 at 06:28
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/200378/discussion-between-coder-mal-and-jakir-hossain). – Malavan Oct 04 '19 at 06:33
0

You initialized MainActivity in Settings but that reference is different than your actual MainActivity which is being displayed. I found some other issues related to data sets in the adapter which need to be improved. After that, you need to find a way by which you can send filter information from Settings to MainActivity. There are several methods but I would recommend you to use SharedPreference in your case.

In Settings you should put your filter settings in SharedPreference and get their values in MainActivity

public class Settings extends AppCompatActivity {

    SharedPreferences.Editor editSettings;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        editSettings = getSharedPreferences("filter", Context.MODE_PRIVATE).edit();
        resetButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                editSettings.putBoolean("reset", true).apply();
            }
        });
    }
}

In Adapter make the following changes,

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

    private static final String TAG = "RecyclerViewAdapter";
    private ArrayList<String> mImages = new ArrayList<>();
    private ArrayList<String> mEmailTitle = new ArrayList<>();
    private ArrayList<String> mEmailHeader = new ArrayList<>();
    private ArrayList<String> mEmailContent = new ArrayList<>();
    private Context mContext;

    public RecyclerViewAdapdter(Context mContext) {
        this.mContext = mContext;
    }

    public void submitData((ArrayList<String> mImages, ArrayList<String> mEmailTitle, ArrayList<String> mEmailHeader, ArrayList<String> mEmailContent) {
        this.mImages.clear();
        this.mEmailTitle.clear();
        this.mEmailHeader.clear();
        this.mEmailContent.clear();

        this.mImages.addAll(mImages);
        this.mEmailTitle.addAll(mEmailTitle);
        this.mEmailHeader.addAll(mEmailHeader);
        this.mEmailContent.addAll(mEmailContent);

        notifyDataSetChanged()
    }

    ...
}

In MainActivity override onResume() and update list when the value from the SharedPreference is true,

public class MainActivity extends AppCompatActivity {

    ...

    SharedPreferences spSettings;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        spSettings = getSharedPreferences("filter", Context.MODE_PRIVATE);

        ...
    }

    @Override
    protected void onResume() {
        super.onResume();
        boolean reset = spSettings.getBoolean("reset", false);
        if(reset) {
            ArrayList<AssignmentEmail> emailArray = getEmails();
            sortEmails(emailArray);
        }
    }

    private void initRecyclerView(){
        ...

        adapter = new RecyclerViewAdapdter(mContent,this);
        adapter.submitData(mImageurls,mNames,mHeaders);

        ...
    }

    public void sortEmails(ArrayList<AssignmentEmail> arrayOfEmails){
        ...

        adapter.submitData(mImageurls,mNames,mHeaders,mContent);
    }

}
Roaim
  • 2,298
  • 2
  • 11
  • 23