如何在 onActivityResult 方法收到 Intent 结果后设置观察者以更新导航抽屉 [英] How to set an Observer to Update Navigation Drawer after onActivityResult method's received an Intent result
问题描述
在我的应用程序中,我想在用户登录后使用用户名的昵称和电子邮件更新导航抽屉.
从我的 MainActivity
我开始一个 LoginActivity
与 startActivityForResult(intent, PICK_ACCOUNT_REQUEST);
方法让用户注册或登录.
LoginActivity
将Intent data
结果(他的NAME
和EMAIL
)返回给 后MainActivity
,方法 onActivityResult()
被调用,在那里我尝试更新类的全局变量 NAME
和 EMAIL
新收到的数据,但没有成功:每次注册或登录后,导航抽屉中永远不会显示这两个字段.这是我的代码:
在MainActivity
类的开头我分配了两个变量:
String NAME = "登录", EMAIL = "";
这两个值被插入到我的导航抽屉中.从 LoginActivity
收到结果后,我想更新 onActivityResult()
方法中的这两个字段.这样:
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data){//检查我们正在响应哪个请求如果(请求代码 == PICK_ACCOUNT_REQUEST){//确保请求成功如果(结果代码 == RESULT_OK){//用户选择了一个联系人.String usr = data.getStringExtra("用户名");String mal = data.getStringExtra("email");this.NAME = usr;this.EMAIL=mal;}}}
没有成功,实际上在 LoginActivity
完成后,我仍然可以看到导航抽屉中的旧值,因为我无法从 MainActivity 访问包含用户名和密码的 2 EditText代码>.事实上,这 2 个 EditText 是在
RecyclerView.ViewHolder
内管理的.
如何设置观察者或类似的东西来动态更新我的导航抽屉的 RecyclerView.Adapter?
更多详情如下
* 编辑 *
附言.我的导航抽屉是用 RecyclerView 实现的,因此我在适配器中有一个 RecyclerView.Adapter
类和一个 RecyclerView.ViewHolder
类.在 MainActivity
我有这个代码:
公共类 MainActivity 扩展 ActionBarActivity{ArrayList数据列表;RecyclerView mRecyclerView;//声明 RecyclerViewRecyclerView.Adapter mAdapter;//为 Recycler View 声明适配器RecyclerView.LayoutManager mLayoutManager;//将布局管理器声明为线性布局管理器私人 DrawerLayout mDrawerLayout;私人 ActionBarDrawerToggle mDrawerToggle;私人 CharSequence mTitle, mDrawerTitle;工具栏工具栏;字符串名称,电子邮件;INT AVATARRESID;//TODO 更新导航抽屉字段@覆盖protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);/* 将工具栏对象分配给视图并将操作栏设置为我们的工具栏 */工具栏 = (工具栏) findViewById(R.id.tool_bar);setSupportActionBar(工具栏);//启用 ActionBar 应用程序图标作为切换导航抽屉的动作getSupportActionBar().setDisplayHomeAsUpEnabled(true);//脉冲抽屉getSupportActionBar().setHomeButtonEnabled(true);//脉冲饮食//初始化mTitle = mDrawerTitle = getTitle();AVATARresID = R.mipmap.aka;//将 Drawer Item 添加到 dataListdataList = 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"));//在列表中添加一个标题dataList.add(new DrawerItem("其他"));//在列表中添加一个标题dataList.add(new DrawerItem("Contatti", R.mipmap.ic_about));dataList.add(new DrawerItem("教程", 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){@覆盖public void onDrawerOpened(View drawerView) {...}@覆盖public void onDrawerClosed(View drawerView) {...}};//抽屉监听器设置为抽屉切换mDrawerLayout.setDrawerListener(mDrawerToggle);mDrawerToggle.syncState();mRecyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, mRecyclerView, new RecyclerItemClickListener.OnItemClickListener() {...});}}
我已经解决了!
我的解决方案是双重的:我在用户登录后即时更新 dataList
数据结构,然后使用 SharedPreferences
使此更新持久化.
以下说明不起作用的原因:
String usr = data.getStringExtra("用户名");String mal = data.getStringExtra("email");this.NAME = usr;this.EMAIL=mal;
是因为 RecyclerView.Adapter mAdapter
(保存我的数据的对象)无法知道发生了某种变化,因此它没有更新其数据.>
要让它知道确实发生了某种变化,首先我必须修改ArrayList
,其次我必须用 mAdapter.notifyItemChanged(0)
方法通知 Adapter
变化(类似于 Observer-可观察的模式).这样,导航抽屉会立即更新为新的 dataList
.
这还不是全部.简单地动态更新 dataList
是一个不稳定的解决方案,因为每次用户更改活动然后返回到 MainActivity
时,NavigationDrawer 都会使用旧数据再次初始化(丢失在过去状态期间获得的任何信息,因此加载空的 NAME 和 EMAIL 变量).因此,为了使帐户信息持久化,必须将它们保存到 SharedPreferences
中.
这是onActivityResult()
动态更新导航抽屉并将账户信息持久保存到SharedPreferences
的代码:
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data){//检查我们正在响应哪个请求如果(请求代码 == PICK_ACCOUNT_REQUEST){//确保请求成功如果(结果代码 == RESULT_OK){//用户选择了一个联系人.String usr = data.getStringExtra("用户名");String mail = data.getStringExtra("email");SharedPreferences usrData = getSharedPreferences(usr_loggedin, MODE_PRIVATE);SharedPreferences.Editor 编辑器 = usrData.edit();editor.clear();editor.putBoolean("usraccount",true).commit();editor.putString("用户名",usr).commit();editor.putString("email",mail).commit();dataList.remove(0);dataList.add(0,new DrawerItem(usr,mail,AVATARresID));mAdapter.notifyItemChanged(0);}}}
这是在 MainActivity
我检查用户是否登录的地方,如果是,则从 SharedPreferences 加载帐户信息:
//...字符串名称,电子邮件;INT AVATARRESID;@覆盖protected void onCreate(Bundle savedInstanceState) {//...//初始化SharedPreferences usrData = getSharedPreferences(usr_loggedin, MODE_PRIVATE);AVATARresID = R.mipmap.aka;//将 Drawer Item 添加到 dataListdataList = 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")){字符串 usr,mail;usr = usrData.getString("用户名",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);//... ...}
另一方面,为了解决我的问题,我不得不注意到(通过大量调试)在方法 onActivityResult()
完成后,MainActivity 的 onCreate()
不会被第二次调用,类的执行以 onActivityResult()
的结尾结束.
出于这个原因,我不能仅仅依靠 SharedPreferences
来更新用户的信息.事实上,即使 SharedPreferences
通过在项目的任何地方提供所有需要的信息而做得很好,当 onCreate
方法没有被第二次调用时,无法使用新信息和额外代码更新 RecyclerView.Adapter
,使得 SharedPreferences
变得毫无意义.
由于这些原因,如果没有 mAdapter.notifyItemChanged(0)
,更新 MainActivity
的帐户字段是不可能的,它可以即时完成工作.
话虽如此,在 MainActivity
中对 onCreate()
方法的任何后续调用都会从 SharedPreferences()
加载帐户信息,直到用户不会在其他地方注销.
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() {...});
}
}
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.
这篇关于如何在 onActivityResult 方法收到 Intent 结果后设置观察者以更新导航抽屉的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!