2

I have no idea, which factor may cause this problem, as even after debugging, still cannot figure it out. The problem is, that after start of application, I am trying to fill up text fields for login and password with saved data from previous login. However I cannot get reference to TextFields :/ It always get's null, and dunno why. What I have so far is.

public class Login extends ActionBarActivity {

private String SHARED_PREFS_KEY = "SBJP";
private String LOGIN_KEY = "login";
private String PASS_KEY = "pass";

private EditText userName;
private EditText password;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);
    PlaceholderFragment phFrag = new PlaceholderFragment();

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, phFrag)
                .commit();
    }

    loadPreferences(phFrag);

}


@Override
public boolean onCreateOptionsMenu(Menu menu) {

    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.login, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}

/**
 * A placeholder fragment containing a simple view.
 */
public static class PlaceholderFragment extends Fragment {

    public PlaceholderFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_login, container, false);
        return rootView;
    }
}

/**
 * Handles login action
 */
public void loginClick(View v){
    this.userName = (EditText) findViewById(R.id.login_screen_tf_login);
    this.password = (EditText) findViewById(R.id.login_screen_tf_password);

    String userNameStr = userName.getText().toString();
    String passStr = password.getText().toString();

    //Log.d("SB", userNameStr+":"+passStr);
    SharedPreferences prefs = getSharedPreferences(SHARED_PREFS_KEY, MODE_PRIVATE);
    Editor editor = prefs.edit();

    editor.putString(PASS_KEY, passStr);
    editor.putString(LOGIN_KEY, userNameStr);
    editor.commit();
}

/**
 * Handles creating new account
 */
public void createNewAccountClick(View v){
    Log.d("SB", "Here comes account creation");
}

private void loadPreferences(PlaceholderFragment rootView){
    SharedPreferences prefs = getSharedPreferences(SHARED_PREFS_KEY, MODE_PRIVATE);
    String loginStr = prefs.getString(LOGIN_KEY, null);
    String passStr = prefs.getString(PASS_KEY, null);

    this.userName = (EditText) rootView.getView().findViewById(R.id.login_screen_tf_login);
    this.password = (EditText) rootView.getView().findViewById(R.id.login_screen_tf_password);

    Log.d("SB","Login/sn:"+loginStr+passStr);

    if(loginStr != null && userName != null){
        userName.setText(loginStr);
    }
    if(passStr != null && password != null){
        password.setText(passStr);
    }

}

}

Does anybody know, why do I always get userName and password variables as null in loadPreferences method? In loginClick method it works fine :/ ...

Thanks in advance

jpact
  • 1,042
  • 10
  • 23
  • 1
    does the layout.xml file for the ACTIVITY have edit text items with those ids ? – rperryng May 20 '14 at 17:56
  • Yop, as I have mentioned before, in another method it works fine (using same ids there[loginClick])... – jpact May 20 '14 at 17:57
  • That doesn't necessarily mean anything. What @Rperryng is presumably implying is that if your views (and their onClick's) are set in the fragment's xml then your loginClick() would work but your loadPreferences() wouldn't – zgc7009 May 20 '14 at 18:00
  • Post your layout xml file. – ashishduh May 20 '14 at 18:20
  • Just call findViewById Once, when you call it a second ttime it looks for another view in the same layout hierarchy with the same id. Just call findViewById once in the oncreate method – rperryng May 20 '14 at 18:36

2 Answers2

1
this.userName = (EditText) findViewById(R.id.login_screen_tf_login);
this.password = (EditText) findViewById(R.id.login_screen_tf_password);

Here you need to get a root view of a fragment, but inside a code of your PlaceholderFragment class:

userName = (EditText) getView().findViewById(R.id.login_screen_tf_login);
password = (EditText) getView().findViewById(R.id.login_screen_tf_password);

http://developer.android.com/reference/android/app/Fragment.html#getView()

Of course we suggest that login_screen_tf_login and login_screen_tf_login EditText-s is located in your fragment_login layout.

ADDITION:

You can redesign PlaceholderFragment as follow:

public static class PlaceholderFragment extends Fragment {

private String login;
private String password;

public void setAuthData(String login, String password){ this.login = login; this.password = password; }

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_login, container, false);

    EditText userName = (EditText) rootView.findViewById(R.id.login_screen_tf_login);
    userName.setText(login); 
    EditText passwordET = (EditText) rootView.findViewById(R.id.login_screen_tf_password); 
    passwordET.setText(password);
    return rootView;
}
}

And use PlaceholderFragment class as follow:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);

    SharedPreferences prefs = getSharedPreferences(SHARED_PREFS_KEY, MODE_PRIVATE);
    String login = prefs.getString(LOGIN_KEY, null);
    String password = prefs.getString(PASS_KEY, null);

    PlaceholderFragment phFrag = new PlaceholderFragment();
    phFrag.setAuthData(login, password);

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
            .add(R.id.container, phFrag)
            .commit();
    }
 }
DenisMath
  • 547
  • 4
  • 8
  • Denis, I have tried to edit code, as you wrote, but still no success :/ take a look at it please, I have edited code in my main post. – jpact May 20 '14 at 18:08
  • The problem is, that view inside PlaceholderFragment is null, so it fails and causes NullPointerException once I want to invoke getView() method :/ – jpact May 20 '14 at 18:12
  • It`s obviously why! :) You call loadPreferences before getting of rootView from onCreateView in PlaceholderFragment. To solve this problem you can locate a code of loadPreferences in PlaceholderFragment class and redesign the application. – DenisMath May 20 '14 at 18:27
  • Yeah, this is a better answer than mine. I'd just like to point out that the `new PlaceholderFragment()` line and the `setAuthData` line after it can both go into the `if(savedInstanceState == null)` to avoid a small waste of memory. – nkorth May 20 '14 at 20:10
0

Since the TextViews are in the layout for PlaceholderFragment, their logic should be there too. You can technically use findViewById to get the fragment's views from the parent activity, but it's better to keep it within the fragment if possible, so that you could have multiple fragments without id conflicts. (For example; I know two login forms isn't a likely scenario.)

So the first thing I would do is move both loginClick and loadPreferences into PlaceholderFragment. (You can rename PlaceholderFragment into something more useful too, of course.) Once it's moved, you'll call loadPreferences in onCreateView instead of Activity.onCreate. This should make more sense to you - loadPreferences is populating the view, so it should happen as the view is being created.

However, getView() still won't work here. Instead, you have to use the rootView that's being created in the process of onCreateView. This is because getView only finds out what the root view is after it's returned from onCreateView. Therefore, a good way to solve the problem would be to simply pass rootView into loadPreferences, and use rootView.findViewById.

nkorth
  • 1,684
  • 1
  • 12
  • 28