如何设置观察者在onActivityResult方法接收到Intent结果后更新导航抽屉。

4

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

从我的MainActivity中,我使用startActivityForResult(intent, PICK_ACCOUNT_REQUEST);方法启动一个LoginActivity,以获取已注册或已登录的用户。

LoginActivity返回Intent data结果(他的NAMEEMAIL)回到MainActivity之后,将调用onActivityResult()方法,并在那里尝试使用新接收到的数据更新类的全局变量NAMEEMAIL,但是没有成功:在每次注册或登录后,这两个字段都不会显示在导航抽屉中。以下是我的代码:

MainActivity类的开头,我分配了两个变量:

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内管理的。

我该如何设置观察者或类似的机制来动态更新我的导航抽屉的 RecyclerView.Adapter

更多详细信息如下:

*编辑*

PS: 我的导航抽屉是使用 RecyclerView 实现的,因此适配器中有一个 RecyclerView.Adapter 类和一个在适配器中的 RecyclerView.ViewHolder 类。在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() {...});

    }
}

你需要使用数据更新视图 tvEmail.setText(this.EMAIL); tvName.setText(this.NAME); - Apollo
我尝试了,但它出现了NullPointerException。由于我的NavigationDrawer已经使用RecyclerView实现,并且两个TextView(我应该更新的)被分配到另一个类中的xml中(即RecyclerView适配器)。确切地说,在RecyclerView.Adapter类中也在RecyclerView.ViewHolder类中...是否还有其他方法? - Cris
3个回答

3

我解决了!

我的方法有两部分:我在用户登录后实时更新dataList数据结构,然后使用SharedPreferences将此更新持久化。

以下指令无法工作的原因是:

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

原因是RecyclerView.Adapter mAdapter (保存数据的对象)没有任何方法可以知道某个更改已经发生,因此它没有更新数据。

为了让它知道确实发生了某个更改,首先我必须修改ArrayList<DrawerItems> dataList,其次我必须使用方法mAdapter.notifyItemChanged(0)通知Adapter进行更改(类似于Observer-Observable模式)。这样导航抽屉就会立即使用新的dataList进行更新。

但这还不够。简单地实时更新dataList是一种不稳定的解决方案,因为每次用户更改活动并返回到MainActivity时,导航抽屉都会初始化旧数据(失去过去状态下获得的任何信息,因此加载空的名称和电子邮件变量)。因此,为了使帐户信息持久化,必须将它们保存在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() 不会第二次被调用,并且类的执行随着 onActivityResult() 的结束而结束。
因此,我不能仅依赖 SharedPreferences 来更新用户信息。实际上,尽管 SharedPreferences 通过在项目中使所有必需的信息可用来很好地完成它们的工作,但是当 onCreate 方法不被第二次调用时,没有办法用新信息更新 RecyclerView.Adapter,而无需额外的代码,使 SharedPreferences 变得毫无意义。
因此,在没有 mAdapter.notifyItemChanged(0) 的情况下,更新 MainActivity 的帐户字段是不可能实现的,它可以即时完成工作。
话虽如此,任何对 MainActivity 中 onCreate() 方法的后续调用都将从 SharedPreferences() 加载帐户信息,直到用户在其他地方退出登录为止。

1
在您的导航抽屉中,我认为您正在使用textviews来显示名称和电子邮件。您需要通过监听器传递这些值,然后在抽屉文本视图中设置这些文本。
创建一个具有接受名称和电子邮件的方法的监听器。
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 );

我尝试了一下,但是出现了“NullPointerException”,我认为你的代码不适用于我的NavigationDrawer,因为它已经使用了“RecyclerView”进行实现,并且我需要更新的两个TextView被分配到另一个类的xml中。确切地说,在“RecyclerView.ViewHolder”类中也在“RecyclerView.Adapter”类中...我该如何将你的解决方案调整到我的问题上,或者还有其他方法吗? - Cris
1
好的,然后您使用RecyclerView的构造函数传递值,并在RecyclerView中创建一个公共方法来设置TextView。现在当您创建RecyclerView对象时,传递名称和电子邮件的值并调用该方法将这些值设置到视图中。 - Iqbal S

1

我无法评论,所以作为答案发布 - 您正在更新变量,但您是否在更新 DrawerLayout 的视图本身?我假设您有某种用于字符串的 TextViews EditTexts ,您是否在对它们调用 .setText(NAME) / .setText(EMAIL)?从您的问题中无法确定这一点。:)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接