如何在 onActivityResult 方法收到 Intent 结果后设置 Observer 以更新导航抽屉

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

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

从我的 MainActivity 我开始 LoginActivity 使用 startActivityForResult(intent, PICK_ACCOUNT_REQUEST); 方法 让用户注册或登录。

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

MainActivity开头class我赋值了两个变量:

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

这两个值已插入我的导航抽屉中。从 LoginActivity 收到结果后,我想在 onActivityResult() 方法中更新这两个字段。这样:

@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;
        }
    }
}

没有成功,实际上在 LoginActivity 完成后,我仍然在导航抽屉中看到旧值,因为我无法从 MainActivity 访问包含用户名和密码的 2 个 EditText .实际上 2 个 EditText 是在 RecyclerView.ViewHolder 中管理的。

如何设置 Observer 或类似的东西来动态更新我的导航抽屉的 RecyclerView.Adapter?

下面有更多详细信息

* 编辑 *

Ps。我的导航抽屉是用 RecyclerView 实现的,因此我在适配器中有一个 RecyclerView.Adapter class 和一个 RecyclerView.ViewHolder class。在 MainActivity 我有这个代码:

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() {...});

    }
}

我无法发表评论,所以发帖作为回答 - 您正在更新变量,但您是在更新 DrawerLayout 的视图本身吗?我假设您有某种 TextViewsEditTexts 用于字符串,您是在调用它们 .setText(NAME)/.setText(EMAIL) 吗?不能完全从你的问题中看出这一点。 :)

在您的导航抽屉中,我相信您正在使用文本视图来显示姓名和电子邮件。您需要在侦听器的帮助下传递这些值,然后在抽屉文本视图中设置这些文本。

创建一个监听器,它有一个接受姓名和电子邮件的方法

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

您在抽屉菜单中实现此侦听器,并根据收到的值在此方法中设置文本视图。

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

在您的 onActivityResult() 中调用此方法并传递值

ChangeListener.displayNameAndEmail(name, email );

我已经解决了!

我的解决方案是双重的:我在用户登录后即时更新 dataList 数据结构,然后使用 SharedPreferences.

使此更新持久化

以下说明不起作用的原因:

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

是因为RecyclerView.Adapter mAdapter(保存我的数据的对象)没有任何方法知道发生了某种变化,因此它没有更新它的数据。

为了让它知道某个变化确实发生了,首先我必须修改 ArrayList<DrawerItems> dataList,然后我必须用方法 Adapter 通知变化 Adapter =18=](类似于 Observer-Observable 模式)。这样导航抽屉会立即更新为新的 dataList

这还不是全部。简单地即时更新 dataList 是一个不稳定的解决方案,因为每次用户更改 activity 然后返回到 MainActivity,NavigationDrawer 都会用旧数据再次初始化(丢失过去状态期间获取的任何信息,因此加载空的 NAME 和 EMAIL 变量)。因此,为了使帐户信息持久化,有必要将它们保存到 SharedPreferences 中。

这是 onActivityResult() 动态更新导航抽屉并将帐户信息永久保存到 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);
        }
    }
}

这是 MainActivity 我检查用户是否登录的地方,如果是,则从 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);
    //... ...
}

另一方面,为了解决我的问题,我不得不注意到(经过大量调试)方法 onActivityResult() 完成后,MainActivity 的 onCreate() 不会被第二次调用时间和 class 的执行在 onActivityResult().

结束时结束

因此,我不能仅依靠 SharedPreferences 来更新用户信息。事实上,即使 SharedPreferences 通过使所有需要的信息在项目的任何地方都可用来很好地完成他们的工作,当 onCreate 方法没有被第二次调用时,将无法更新RecyclerView.Adapter 包含新信息且没有额外代码,使 SharedPreferences 变得毫无意义。

由于这些原因,如果没有 mAdapter.notifyItemChanged(0) 更新 MainActivity 的帐户字段是不可能的,它可以即时完成工作。

话虽如此,在 MainActivity 中对 onCreate() 方法的任何后续调用都会从 SharedPreferences() 加载帐户信息,直到用户不会在其他地方注销。