How to set an Observer to Update Navigation Drawer after onActivityResult method's received an Intent result

╄→гoц情女王★ 提交于 2019-12-10 06:59:07

问题


In my app I want to update the Navigation Drawer with the username's nickname and email after he's logged in.

From my MainActivity I am starting a LoginActivity with the startActivityForResult(intent, PICK_ACCOUNT_REQUEST); method to get the users registered or logged in.

After the LoginActivity returns the Intent data result (his NAME and EMAIL) back to MainActivity, the method onActivityResult() is called and there I try to update the class' global variables NAME and EMAIL with the newly received data, with no success: after every registration or log the two fields never show in the navigation drawer. Here's my code:

In the beginning of the MainActivity class I assign two variables:

String NAME = "Sign in", EMAIL = "";

These two values are inserted in my navigation drawer. After I receive the result from LoginActivity I want to update these two fields in the onActivityResult() method. This way:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
    // Check which request we're responding to
    if (requestCode == PICK_ACCOUNT_REQUEST) {
        // Make sure the request was successful
        if (resultCode == RESULT_OK) {
            // The user picked a contact.
            String usr = data.getStringExtra("username");
            String mal = data.getStringExtra("email");
            this.NAME = usr;this.EMAIL=mal;
        }
    }
}

with no success, in fact after completion of LoginActivity I still visualize the old values within the Navigation Drawer because I'm not able to access the 2 EditText holding Username and Password from MainActivity. In fact the 2 EditText are managed inside RecyclerView.ViewHolder.

How can I set an Observer or something similar to dinamically update my Navigation Drawer's RecyclerView.Adapter?

More details below

* EDIT *

Ps. My Navigation Drawer is implemented with RecyclerView, I therefore have a RecyclerView.Adapter class and a RecyclerView.ViewHolder class inside the adapter. In MainActivity I have this code:

public class MainActivity extends ActionBarActivity{
    ArrayList<DrawerItem> dataList; 
    RecyclerView mRecyclerView;                // Declaring RecyclerView
    RecyclerView.Adapter mAdapter;              // Declaring Adapter For Recycler View
    RecyclerView.LayoutManager mLayoutManager; // Declaring Layout Manager as a linear layout manager
    private DrawerLayout mDrawerLayout;
    private ActionBarDrawerToggle mDrawerToggle;
    private CharSequence mTitle, mDrawerTitle;
    Toolbar toolbar;

    String NAME, EMAIL; int AVATARresID; //TODO update Navigation Drawer fields

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        /* Assigning the toolbar object to the view
        and setting the the Action bar to our toolbar */
        toolbar = (Toolbar) findViewById(R.id.tool_bar);
        setSupportActionBar(toolbar);
        // enable ActionBar app icon to behave as action to toggle nav drawer
        getSupportActionBar().setDisplayHomeAsUpEnabled(true); //pulsante drawer
        getSupportActionBar().setHomeButtonEnabled(true);      //pulsante dietro

        //Initializing
        mTitle = mDrawerTitle = getTitle();

        AVATARresID = R.mipmap.aka;
        // Add Drawer Item to dataList
        dataList = new ArrayList<>();
        dataList.add(new DrawerItem(NAME,EMAIL,AVATARresID));
        dataList.add(new DrawerItem("Account", R.mipmap.ic_account));
        dataList.add(new DrawerItem("Tuoi Tour", R.mipmap.ic_events));
        dataList.add(new DrawerItem("Prenota Tour", R.mipmap.ic_action_search));
        // dataList.add(new DrawerItem("My Favorites")); // adding a header to the list
        dataList.add(new DrawerItem("Others")); // adding a header to the list
        dataList.add(new DrawerItem("Contatti", R.mipmap.ic_about));
        dataList.add(new DrawerItem("Tutorial", R.mipmap.ic_help));

        mRecyclerView = (RecyclerView) findViewById(R.id.RecyclerView);
        mRecyclerView.setHasFixedSize(true);
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);

        mAdapter = new MyAdapter(dataList, mSelectedPositions);

        mRecyclerView.setAdapter(mAdapter);
        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);

        mDrawerToggle = new ActionBarDrawerToggle(this,mDrawerLayout,toolbar,
            R.string.drawer_open, R.string.drawer_close){
                    @Override 
                    public void onDrawerOpened(View drawerView) {...}
                    @Override
                    public void onDrawerClosed(View drawerView) {...}
        };


        // Drawer Listener set to the Drawer toggle
        mDrawerLayout.setDrawerListener(mDrawerToggle);
        mDrawerToggle.syncState(); 
        mRecyclerView.addOnItemTouchListener(
            new RecyclerItemClickListener(this, mRecyclerView, new RecyclerItemClickListener.OnItemClickListener() {...});

    }
}

回答1:


I've solved it!

My solution is twofold: I both update the dataList dataStructure on the fly after the user's login, and then make this update persistent with SharedPreferences.

The reason why the following instructions were not working:

String usr = data.getStringExtra("username");
String mal = data.getStringExtra("email");
this.NAME = usr; this.EMAIL=mal;

was because the RecyclerView.Adapter mAdapter (the object holding my data) did not have any way to know that a certain change took place, and it therefore didn't update its data.

For it to know that a certain change had actually occurred, first of all I had to modify the ArrayList<DrawerItems> dataList, and secondly I had to notify the Adapter of the change with the method mAdapter.notifyItemChanged(0) (similarly to how it happens with the Observer-Observable pattern). This way the Navigation Drawer is immediately updated with the new dataList.

This wasn't all. Simply updating the dataList on the fly was a volatile solution, since every time the user changes activity and then goes back to the MainActivity, the NavigationDrawer is initialized again with the old data (losing any acquired information during past states, and therefore loading empty NAME and EMAIL variables). Thus, in order to make the account information persistent was necessary to save them into SharedPreferences.

This is the code of onActivityResult() updating the navigation drawer on the fly and also saving the account's information persistently into SharedPreferences:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
    // Check which request we're responding to
    if (requestCode == PICK_ACCOUNT_REQUEST) {
        // Make sure the request was successful
        if (resultCode == RESULT_OK) {
            // The user picked a contact.
            String usr = data.getStringExtra("username");
            String mail = data.getStringExtra("email");

            SharedPreferences usrData = getSharedPreferences(usr_loggedin, MODE_PRIVATE);
            SharedPreferences.Editor editor = usrData.edit();
            editor.clear();
            editor.putBoolean("usraccount",true).commit();
            editor.putString("username",usr).commit();
            editor.putString("email",mail).commit();

            dataList.remove(0);
            dataList.add(0,new DrawerItem(usr,mail,AVATARresID));
            mAdapter.notifyItemChanged(0);
        }
    }
}

This is where in MainActivity I check if the user is logged in, and if so the account information are loaded from SharedPreferences:

//...
String NAME,EMAIL; int AVATARresID;

@Override
protected void onCreate(Bundle savedInstanceState) {
    //...

    //Initializing
    SharedPreferences usrData = getSharedPreferences(usr_loggedin, MODE_PRIVATE);
    AVATARresID = R.mipmap.aka;
    // Add Drawer Item to dataList
    dataList = new ArrayList<>();
    dataList = prepareDatalist(dataList, NAME, EMAIL, AVATARresID);

    mRecyclerView = (RecyclerView) findViewById(R.id.RecyclerView);
    mRecyclerView.setHasFixedSize(true);
    mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);

    mAdapter = new MyAdapter(dataList, mSelectedPositions);

    if(usrData.contains("usraccount")){
        String usr,mail;
        usr = usrData.getString("username",usr_loggedin);
        mail = usrData.getString("email",usr_loggedin);
        dataList.remove(0);
        dataList.add(0,new DrawerItem(usr,mail,AVATARresID));
        mAdapter.notifyItemChanged(0);
    }

    mRecyclerView.setAdapter(mAdapter);
    //... ...
}

As a side not, to solve my problems I had to notice (with a great deal of debugging) that after the method onActivityResult() has finished, the MainActivity's onCreate() is not called a second time and the execution of the class ends with the end of onActivityResult().

For this reason I couldn't rely only on SharedPreferences to update the user's information. In fact even though the SharedPreferences do their job well by making all the needed information available everywhere in the project, when the onCreate method isn't called a second time, there would be no way of update the RecyclerView.Adapter with the new information and no extra code, making the SharedPreferences to become pointless.

For these reasons, updating MainActivity's account fields was impossible to perform without the mAdapter.notifyItemChanged(0), which did the job on the fly.

Having said that, any subsequent call to onCreate() method in MainActivity would load the account information from SharedPreferences() until the user wouldn't logout somewhere else.




回答2:


I cannot comment, so posting as an answer - you are updating the variables, but are you updating the DrawerLayout's view itself? I assume you have some kind of TextViews or EditTexts for the Strings, are you calling .setText(NAME)/.setText(EMAIL) on them? Can't quite make this out from your question. :)




回答3:


In your navigation drawer I believe you are using the textviews to display the name and email. You need to pass these values with the help of a listener and then set these texts in the drawer text views.

Create a listener which has a method which takes name and email

public interface ChangeListener {
     void displayNameAndEmail(String name, String email );
}

You implement this listener in the drawer menu and set the text views in this method based on the values received.

@Override 
private void displayNameAndEmail(String name, String email ) {
      mEmailTextView.setText(email);
      mNameTextView.setText(name);
};

In your onActivityResult() call this method and pass the values

ChangeListener.displayNameAndEmail(name, email );


来源:https://stackoverflow.com/questions/29775020/how-to-set-an-observer-to-update-navigation-drawer-after-onactivityresult-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!