如何在 onActivityResult 方法收到 Intent 结果后设置观察者以更新导航抽屉 [英] How to set an Observer to Update Navigation Drawer after onActivityResult method's received an Intent result

查看:15
本文介绍了如何在 onActivityResult 方法收到 Intent 结果后设置观察者以更新导航抽屉的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用程序中,我想在用户登录后使用用户名的昵称和电子邮件更新导航抽屉.

从我的 MainActivity 我开始一个 LoginActivitystartActivityForResult(intent, PICK_ACCOUNT_REQUEST); 方法让用户注册或登录.

LoginActivityIntent data 结果(他的NAMEEMAIL)返回给 后MainActivity,方法 onActivityResult() 被调用,在那里我尝试更新类的全局变量 NAMEEMAIL新收到的数据,但没有成功:每次注册或登录后,导航抽屉中永远不会显示这两个字段.这是我的代码:

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;dataList,其次我必须用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆