问题
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