Android App Crashes on FragmentTransaction.replace - android-fragments

I'm attempting to create a dynamic UI using the support.v4 library to insert fragments into a framelayout I have defined for my main activity.
Here is my activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:baselineAligned="false" >
<LinearLayout
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:orientation="vertical" >
<Button
android:id="#+id/button_report"
android:text="#string/button_report"
android:textSize="22sp"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<Button
android:id="#+id/button_pay"
android:text="#string/button_pay"
android:textSize="22sp"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<Button
android:id="#+id/button_contact"
android:text="#string/button_contact"
android:textSize="22sp"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
<FrameLayout
android:id="#+id/container"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="2" />
</LinearLayout>
And here is the MainActivity.java:
package com.example.Test;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends FragmentActivity
{
// Declare button variables
protected Button btnReport;
protected Button btnPay;
protected Button btnContact;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Assign buttons
btnReport = (Button)findViewById(R.id.button_report);
btnPay = (Button)findViewById(R.id.button_pay);
btnContact = (Button)findViewById(R.id.button_contact);
// Import fragments
final Fragment fragmentPhone = new FragmentPhone();
final Fragment fragmentReport = new FragmentReport();
final Fragment fragmentPay = new FragmentPay();
final android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
final FragmentTransaction ft = fm.beginTransaction();
// Check for existing fragment, if none then add FragmentPhone.class
if (savedInstanceState != null) return;
else {
ft.add(R.id.container, fragmentPhone);
ft.commit();
}
// "Report" button
btnReport.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
ft.replace(R.id.container, fragmentReport); //Replace the details_container
ft.addToBackStack(null); // Add transaction to back stack
ft.commit(); // Commit the transaction
}
});
// "Pay" button
btnPay.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
ft.replace(R.id.container, fragmentPay);
ft.addToBackStack(null);
ft.commit();
}
});
// "Contact" button
btnContact.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
ft.replace(R.id.container, fragmentPhone);
ft.addToBackStack(null);
ft.commit();
}
});
}
}
And here is my FragmentPhone class:
package com.example.Test;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class FragmentPhone extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_phone, container, false);
}
}
When I launch the app, the xml loads correctly and the framelayout gets filled with fragmentPhone, but pressing any of the buttons creates an "app has stopped unexpectedly" dialogue and prompts me to force close.
Any ideas or suggestions will be greatly appreciated. Thanks!

I ended up re-getting and re-declaring FragmentManager and FragmentTransaction within each onClickListener. I also removed "addToBackStack" as I decided it was unneeded. Here is my current, working code:
// "Report" button
btnReport.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
android.support.v4.app.FragmentManager fragmentManager1 = getSupportFragmentManager();
FragmentTransaction fragmentTransaction1 = fragmentManager1.beginTransaction();
fragmentTransaction1.replace(R.id.container, fragmentReport);
fragmentTransaction1.commit();
}
});

(untested)
make ft a global field so it's available in the click handler.

Related

Android Android registration and login with firebase

I have a view (activity_SingIn) and its Presenter now in the onCreate method gives me the following error related to "singInPresenter.singInUser(v);"
2022-09-18 17:30:51.785 3811-3811/com.example.Natour21 E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.Natour21, PID: 3811
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.NaTour21.Presenter.Activity.SingInPresenter.singInUser(android.view.View)' on a null object reference
at com.example.NaTour21.View.Activity.activity_singIn$2.onClick(activity_singIn.java:61)
package com.example.NaTour21.Presenter.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.Handler;
import android.view.View;
import android.widget.EditText;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.example.NaTour21.View.Activity.activity_Home;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.material.snackbar.Snackbar;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import android.widget.ProgressBar;
public class SingInPresenter extends AppCompatActivity {
private EditText EmailLgn,PasswordLgn;
String[] messaggio = {"Campi vuoti inserili"};
private ProgressBar progressBar;
public void singInUser(View view) {
String email = EmailLgn.getText().toString();
String password = PasswordLgn.getText().toString();
FirebaseAuth.getInstance().createUserWithEmailAndPassword(email, password).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
progressBar.setVisibility(View.VISIBLE);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
home();
}
}, 3000);
} else {
String error;
try{
throw task.getException();
}catch(Exception e){
error ="Errore di accesso utente";
}
Snackbar snackbar = Snackbar.make(view,error,Snackbar.LENGTH_SHORT);
snackbar.setBackgroundTint(Color.WHITE);
snackbar.setTextColor(Color.BLACK);
snackbar.show();
}
}
});
}
public void home() {
Intent intent = new Intent(this, activity_Home.class);
startActivity(intent);
finish();
}
#Override
public void onStart() {
super.onStart();
FirebaseUser UtenteCorrente = FirebaseAuth.getInstance().getCurrentUser();
if(UtenteCorrente != null){
home();
}
}
}
package com.example.NaTour21.View.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import androidx.appcompat.app.AppCompatActivity;
import com.example.NaTour21.Presenter.Activity.SingInPresenter;
import com.example.NaTour21.R;
import com.google.android.material.snackbar.Snackbar;
import android.view.View;
import android.widget.ProgressBar;
public class activity_singIn extends AppCompatActivity{
private EditText EmailLgn,PasswordLgn;
private Button loginLgn;
private Button registratiLgn;
private SingInPresenter singInPresenter;
private ProgressBar progressbar;
String[] messaggio = {"Campi vuoti inserirli",
"Accesso effettuato con successo",
"Formato email non valido",
"La password deve avere minimo 6 caratteri"};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_singin);
getSupportActionBar().hide();
initializeComponent();
registratiLgn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(activity_singIn.this, activity_singUp.class);
startActivity(intent);
}
});
loginLgn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String email = EmailLgn.getText().toString();
String password = PasswordLgn.getText().toString();
if (email.isEmpty() || password.isEmpty()) {
Snackbar snackbar = Snackbar.make(v, messaggio[0], Snackbar.LENGTH_SHORT);
snackbar.setBackgroundTint(Color.WHITE);
snackbar.setTextColor(Color.BLACK);
snackbar.show();
} else if (!isValidEmail(email)) {
Snackbar snackbar = Snackbar.make(v, messaggio[2], Snackbar.LENGTH_SHORT);
snackbar.setBackgroundTint(Color.WHITE);
snackbar.setTextColor(Color.BLACK);
snackbar.show();
}else if (!(password.length() < 6)) {
Snackbar snackbar = Snackbar.make(v, messaggio[3], Snackbar.LENGTH_SHORT);
snackbar.setBackgroundTint(Color.WHITE);
snackbar.setTextColor(Color.BLACK);
snackbar.show();
}else{
Snackbar snackbar = Snackbar.make(v, messaggio[1], Snackbar.LENGTH_SHORT);
snackbar.setBackgroundTint(Color.WHITE);
snackbar.setTextColor(Color.BLACK);
snackbar.show();
singInPresenter.singInUser(v); //??????
}
}
});
}
private boolean isValidEmail(String email) {
return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches();
}
private void initializeComponent() {
registratiLgn = findViewById(R.id.btRegistratiLgn);
EmailLgn = findViewById(R.id.tilEmailLgn);
PasswordLgn = findViewById(R.id.tilPasswordLgn);
loginLgn = findViewById(R.id.btLoginLgn);
progressbar = findViewById(R.id.progressbarLgn);
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/sfondo"
android:id="#+id/activity_singin"
android:clickable="true"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:layout_width="336dp"
android:layout_height="196dp"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="#+id/txtNomeApp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="7dp"
android:clickable="true"
android:fontFamily="sans-serif-medium"
android:gravity="center"
android:text="NaTour21"
android:textColor="#color/white"
android:textSize="60sp" />
</LinearLayout>
<LinearLayout
android:layout_width="361dp"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp">
<EditText
android:id="#+id/tilEmailLgn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="25dp"
android:drawableLeft="#drawable/ic_email"
android:ems="10"
android:hint="Email"
android:textColor="#color/white"
android:inputType="textEmailAddress"
app:backgroundTint="#color/white"/>
<EditText
android:id="#+id/tilPasswordLgn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:drawableLeft="#drawable/ic_password"
android:drawableRight="#drawable/ic_occhio"
android:ems="10"
android:hint="Password"
android:inputType="textPassword"
android:textColor="#color/white"
app:backgroundTint="#color/white"/>
<ProgressBar
android:id="#+id/progressbarLgn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"
app:layout_constraintTop_toBottomOf="#id/containerComponents" />
<Button
android:id="#+id/btLoginLgn"
android:layout_width="232dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="30dp"
android:background="#drawable/button_login"
android:text="Login"
android:textColor="#color/white"
android:textSize="16sp"
android:textStyle="bold"/>
<Button
android:id="#+id/btRegistratiLgn"
android:layout_width="232dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="20dp"
android:background="#drawable/button_registrati"
android:text="Registrati"
android:textColor="#color/white"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
Dear #Fabiola Salomone if you are trying to use MVP because you said you have a presenter then i am afraid you are not doing it correctly at least according to what i know about MVP please study about it that will be better instead of me or anyone else telling you the code directly because you will not know how it works that way , for a head start you need to make an interface and presenter and inside that presenter you will make three more interfaces View Model and Presenter again and then you will initialize that presenter inside you main activity , here you are extending you presenter with appcompactActivty that itself is wrong a lot about your code is wrong its not MVP by any means so i don't how can i help you exactly with this apart from what i just said, Once you know how MVP work then me or other users can surely help you with this, Still if you need any clearance you can ask :)

Why is my floating action button not responding to clicks?

I have two floating action buttons in a fragment that is being created by a ViewPager. My intention is for the FABs to do the same thing that can be done in the ViewPager, so that the user can have a choice in terms of navigation. My problem is that the FABs do not respond to clicks initially, so if I click the left FAB, and then click the right FAB, the ViewPager will flip to the left instead of flipping to the right. What am I doing wrong?
Here is my code:
activity_view_pager:
<?xml version="1.0" encoding="utf-8"?>
<androidx.viewpager.widget.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
fragment_test:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="Title"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/a"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="200dp"
android:text="Description"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/b"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="250dp"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/c"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="300dp"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/left_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="50dp"
android:layout_marginTop="450dp"
android:src="#drawable/ic_left_arrow"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/right_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="450dp"
android:layout_marginEnd="50dp"
android:src="#drawable/ic_right_arrow"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
ViewPagerActivity:
package com.fl4me.android.exampleapplication;
import static com.fl4me.android.exampleapplication.TestAdapter.EXTRA_ID;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.ViewPager;
public class ViewPagerActivity extends AppCompatActivity {
public static int index;
public static ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_pager);
index = (int) getIntent().getSerializableExtra(EXTRA_ID);
viewPager = (ViewPager) findViewById(R.id.view_pager);
FragmentManager fragmentManager = getSupportFragmentManager();
viewPager.setAdapter(new FragmentStatePagerAdapter(fragmentManager) {
#Override
public Fragment getItem(int position) {
return TestFragment.newInstance(position);
}
#Override
public int getCount() {
return 5;
}
});
for(int i = 0; i < Test.testData.length; i++) {
if(i == index) {
viewPager.setCurrentItem(i);
break;
}
}
}
}
TestFragment:
package com.fl4me.android.exampleapplication;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
public class TestFragment extends Fragment {
private static final String ARG_ID = "Id";
private int Id;
private String a;
private TextView aTV;
private String b;
private TextView bTV;
private int c;
private TextView cTV;
private FloatingActionButton leftBtn;
private FloatingActionButton rightBtn;
public static TestFragment newInstance(int Id) {
Bundle args = new Bundle();
args.putSerializable(ARG_ID, Id);
TestFragment fragment = new TestFragment();
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_test, container, false);
Id = getArguments().getInt(ARG_ID);
a = Test.testData[Id].getA();
b = Test.testData[Id].getB();
c = Test.testData[Id].getC();
aTV = (TextView) view.findViewById(R.id.a);
aTV.setText(a);
bTV = (TextView) view.findViewById(R.id.b);
bTV.setText(b);
cTV = (TextView) view.findViewById(R.id.c);
cTV.setText(String.valueOf(c));
leftBtn = view.findViewById(R.id.left_btn);
rightBtn = view.findViewById(R.id.right_btn);
leftBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ViewPagerActivity.viewPager.setCurrentItem(ViewPagerActivity.index--);
}
});
rightBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ViewPagerActivity.viewPager.setCurrentItem(ViewPagerActivity.index++);
}
});
return view;
}
}
This is probably happening because you are post-incrementing or post-decrementing the index instead of pre-incrementing or pre-decrementing it. I think that you should know how post and pre incrementation works, but here is something to read.
Basically the index that you are providing for the setCurrentItem is not evaluated on the spot as index + 1 or index - 1, but it gets its new value only after the execution of the line of code in which there is an expression index++ or index--. This is why you got that "lag" in switching pages that you have described.
So, in your listener for the rightBtn the code should probably be like this:
ViewPagerActivity.viewPager.setCurrentItem(++ViewPagerActivity.index);
The listener for the leftBtn will be analogous, but with --.

Android Fragment not showing up in my application

I have a strange issue with my Fragment, I get no errors at runtime (I'm using Android Studio v8.7 and the Gradle compiles just fine) but when my app runs on my phone it's now showing up, it looks like an empty Activity.
Activity.class
package android.bignerdranch.com.criminalintent;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.os.Bundle;
import android.view.MenuItem;
public class CrimeActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crime);
// These are Fragments from the app.v4 package, it's needed to make the app compatible with API < 11
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);
if(fragment == null) {
fragment = new Fragment();
fm.beginTransaction().add(R.id.fragmentContainer, fragment).commit();
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Fragment.class
package android.bignerdranch.com.criminalintent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
public class CrimeFragment extends Fragment {
private Crime mCrime;
private EditText mTitleField;
private Button mDateButton;
private CheckBox mSolvedCheckbox;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_crime, container, false);
mTitleField = (EditText)v.findViewById(R.id.crime_title);
mTitleField.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
mCrime.setTitle(s.toString());
}
#Override
public void afterTextChanged(Editable s) {
}
});
mDateButton = (Button)v.findViewById(R.id.crime_date);
mDateButton.setText(mCrime.getDate().toString());
mDateButton.setEnabled(false);
mSolvedCheckbox = (CheckBox)v.findViewById(R.id.crime_solved);
mSolvedCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mCrime.setSolved(isChecked);
}
});
return v;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCrime = new Crime();
}
}
Activity.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Fragment.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/crime_title_label"
style="?android:listSeparatorTextViewStyle" />
<EditText
android:id="#+id/crime_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/crime_title_hint" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/crime_details_label"
style="?android:listSeparatorTextViewStyle" />
<Button
android:id="#+id/crime_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp" />
<CheckBox
android:id="#+id/crime_solved"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:text="#string/crime_solved_label" />
</LinearLayout>
Can somebody point me in the right direction and tell me what could solve my issue?
Ok i found the errors, I was instantiating the wrong Fragment.
Instead of
if(fragment == null) {
fragment = new Fragment();
fm.beginTransaction().add(R.id.fragmentContainer, fragment).commit();
It should be
if(fragment == null) {
fragment = new CrimeFragment();
fm.beginTransaction().add(R.id.fragmentContainer, fragment).commit();

Declaring a LinearLayout from Android 3.0 Cookbook Chapter 2

I'm following the instructions from chapter 2 (Declaring a layout) from the Android 3.0 Application Development Cookbook, and I can't seem to get it to work. Here's the code:
The book has you edit the main.xml file so that it looks like this in res/layout/activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:text="#string/vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:text="#string/button_click_horizontal"
android:id="#+id/horizontal_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Then, as second step, it asks you make a copy of the activity_main.xml file and name it my_layout.xml, and its code looks like this (res/layout/my_layout.xml):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:text="#string/horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:text="#string/click_for_vertical"
android:id="#+id/vertical_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
And the code for the main activity file looks like this:
package com.example.declaringlayouts;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity implements View.OnClickListener {
private Button mHorizontalButton;
private Button mVerticalButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mVerticalButton = (Button) findViewById(R.id.vertical_button);
mHorizontalButton = (Button) findViewById(R.id.horizontal_button);
}
#Override
public void onClick(View view) {
if (view == mHorizontalButton) {
setContentView(R.layout.activity_main);
} else if (view == mVerticalButton) {
setContentView(R.layout.my_layout);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
The idea is that clicking in horizontal button will switch to the vertical layout, and vice-versa. Clicking on the button does not work at all.
You need to tell the buttons that this class is the onClickListener, so that it will call your onClick method when they are clicked.
This has to be set up every time you create a new content view, so you should put your button reference setup and listener assignment into a method. So this is how I would revise the class:
public class MainActivity extends Activity implements View.OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
prepareButtons();
}
void prepareButtons(){
Button button = (Button) findViewById(R.id.vertical_button);
if (button==null)
button = (Button) findViewById(R.id.horizontal_button);
mVerticalButton.setOnClickListener(this);
mHorizontalButton.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (view == mHorizontalButton) {
setContentView(R.layout.activity_main);
prepareButtons();
} else if (view == mVerticalButton) {
setContentView(R.layout.my_layout);
prepareButtons();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}

Show/Hide Fragments and change the visibility attribute programmatically

This is a 2 part problem. What I'm having is a 3 Fragment layout where the 3'rd Fragment(FragmentC) is added dynamically when the user taps a button found in another fragment. Then, after it's added the 3'rd Fragment has a button to maximize/minimize it.
UPDATE: Scrool at the end for SOLUTION
PROBLEM 1:
I'm trying to change the visibility attribute of a FrameLayout that acts as a container for the 3'rd fragment(R.id.fragment_C).
What the code is supposed to do is to generate another fragment that, originally has an XML containing android:visibility = "gone". Then, the Fragment is added when tapping a button and the visibility is suppose to change to VISIBLE.
I know this has been covered before, but after 4 hours of trying to make it work I decided to ask what I'm doing wrong.
PROBLEM 2:
After the 3'rd fragment is generated I have a minimize/maximize button that's supposed to hide the first 2 Fragments and allow the 3'rd Fragment to fill the screen.
The problem is the Views of the first 2 Fragments are not removed when using .setVisibility(View.GONE). This has been covered before as well, but I can't figure out why it doesn't work in my code.
The code so far(sorry if it's to verbose but I thought it's better to include all details for you folks):
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:orientation="vertical"
>
<FrameLayout
android:id="#+id/fragment_A"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:background="#CCCCCC"
>
</FrameLayout>
<FrameLayout
android:id="#+id/fragment_B"
android:layout_width="fill_parent"
android:layout_height="300dp"
android:layout_below="#id/fragment_A"
android:layout_centerHorizontal="true"
android:layout_marginTop="15dp"
android:background="#B4B4B4"
>
</FrameLayout>
<FrameLayout
android:id="#+id/fragment_C"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#id/fragment_B"
android:layout_centerHorizontal="true"
android:layout_marginTop="0dp"
android:background="#A3A3A3"
android:visibility="gone"
>
</FrameLayout>
</RelativeLayout>
land/main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:paddingLeft="0dp"
android:paddingRight="0dp" >
<LinearLayout
android:id="#+id/fragments_container"
android:layout_width="fill_parent"
android:layout_height="200dp"
android:baselineAligned="false" >
<FrameLayout
android:id="#+id/fragment_A"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="0.5"
android:background="#CCCCCC" >
</FrameLayout>
<FrameLayout
android:id="#id/fragment_B"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="0.5"
android:background="#B4B4B4"
>
</FrameLayout>
</LinearLayout>
<FrameLayout
android:id="#+id/fragment_C"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#id/fragment_container"
android:layout_centerHorizontal="true"
android:layout_marginTop="0dp"
android:background="#A3A3A3"
android:visibility="gone" >
</FrameLayout>
</RelativeLayout>
MainActivity.java
package com.example.android.fragments_proto.activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import com.example.android.fragments_proto.R;
import com.example.android.fragments_proto.fragment.GMC_DateSelectionFragment;
import com.example.android.fragments_proto.fragment.GMC_ProdUnitSelectionFragment;
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
FragmentManager fm = getSupportFragmentManager();
Fragment fragmentA = fm.findFragmentById(R.id.fragment_A);
Fragment fragmentB = fm.findFragmentById(R.id.fragment_B);
if (fragmentA == null) {
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_A, new FragmentA());
ft.commit();
}
if (fragmentB == null) {
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_B, new FragmentB());
ft.commit();
}
}
}
Now the XML and .java files for the first Fragment.
fragment_A.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
>
<DatePicker
android:id="#+id/datePicker1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
FragmentA.java
package com.example.android.fragments_proto.fragment;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.DatePicker;
import android.widget.Toast;
import com.example.android.fragments_proto.R;
public class FragmentA extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_A, container, false);
DatePicker datePicker = (DatePicker) view.findViewById(R.id.datePicker1);
datePicker.setCalendarViewShown(true);
datePicker.setSpinnersShown(false);
datePicker.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Activity activity = getActivity();
if (activity != null) {
Toast.makeText(activity, "You Touched ME!", Toast.LENGTH_SHORT).show();
}
return false;
}
});
return view;
}
}
Now the XML and .java files for the Fragment that contains the button that when tapped adds the content in R.id.fragment_C
fragment_B.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="0.1"
>
<ListView
android:id="#+id/listView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
</ListView>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:orientation="horizontal"
android:gravity="center"
android:layout_height="wrap_content">
<Button
android:id="#+id/button"
android:text="#string/btn_fragment"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
</LinearLayout>
FragmentB.java
package com.example.android.fragments_proto.fragment;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import com.example.android.fragments_proto.R;
public class FragmentB extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragmentB, container, false);
ListView listView = (ListView) view.findViewById(R.id.listView1);
Button button = (Button) view.findViewById(R.id.button);
String[] machines = new String[] { "MachineId-001", "MachineId-002", "MachineId-003", "MachineId-004", "MachineId-005", "MachineId-006", "MachineId-007", "MachineId-008"};
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.select_dialog_multichoice, machines));
final FrameLayout frameLayout = (FrameLayout) view.findViewById(R.id.fragment_C);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Activity activity = getActivity();
if (activity != null) {
getFragmentManager().beginTransaction().replace(R.id.fragment_C, new FragmentC()).setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE).addToBackStack(null).commit();
frameLayout.setVisibility(View.VISIBLE);
}
}
});
return view;
}
}
The XML and .java files for the Fragment that's supposed to be added.
fragment_C.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:orientation="horizontal"
android:gravity="center"
android:layout_height="wrap_content">
<Button
android:id="#+id/maximize_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Maximize Me!" />
</LinearLayout>
<TextView
android:id="#+id/text_view"
android:textIsSelectable="true"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FF33FF"
/>
</LinearLayout>
FragmentC.java
package com.example.android.fragments_proto.fragment;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import com.example.android.fragments_proto.R;
public class FragmentC extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_C, container, false);
TextView textView = (TextView) view.findViewById(R.id.text_view);
final Fragment fragmentA = getFragmentManager().findFragmentById(R.id.fragment_A);
final Fragment fragmentB = getFragmentManager().findFragmentById(R.id.fragment_B);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
if (fragmentA.isVisible() && fragmentB.isVisible()) {
ft.hide(fragmentA);
ft.hide(fragmentB);
fragmentA.getView().setVisibility(View.GONE);
fragmentB.getView().setVisibility(View.GONE);
button.setText("Minimize Me!");
ft.addToBackStack(null);
} else {
ft.show(fragmentA);
ft.show(fragmentB);
fragmentA.getView().setVisibility(View.VISIBLE);
fragmentB.getView().setVisibility(View.VISIBLE);
button.setText("Maximize Me!");
ft.addToBackStack(null);
}
ft.commit();
}
});
return view;
}
}
Found the problem and a solution thanks to Moesio
PROBLEM:
My error was that I was trying to find a view (in FragmentB.java) with
final FrameLayout frameLayout = (FrameLayout) view.findViewById(R.id.fragment_C);
This line was returning null so when the code reached the point where it was supposed to do a .setVisibility() then the app. would return a nullPointerException.
The same happened for FragmentC.java (so my 2 problems were related). The Views were not removed because my findViewById was null!
SOLUTION:
Just search for your View with getActivity.findViewById(R.id.your_view);
In FragmentB you're trying get a view which is not on your contentView
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_b, container, false);
// this is in fragment_b layout
ListView listView = (ListView) view.findViewById(R.id.listView1);
Button button = (Button) view.findViewById(R.id.button);
/* ... */
// ****************************************
// this is NOT in fragment_b layout, which causes null
// ****************************************
final FrameLayout frameLayout = (FrameLayout) view.findViewById(R.id.fragment_C);
/* ... */
}
Try:
final FrameLayout frameLayout = (FrameLayout) getActivity().getWindow().findViewById(R.id.fragment_C);
Whereas R.id.fragment_C is inflated and setted on MainActivity.
Moreover, I had the same problem until use an extra flag
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
final Fragment fragmentC = new FragmentC();
fragmentTransaction.add(R.id.fragment_C, fragmentC);
fragmentTransaction.commit();
menuIsOn = false;
final View fragmentCView = findViewById(R.id.fragment_C);
final Button btn = (Button) findViewById(R.id.btn);
btnPowers.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!menuIsOn) {
fragmentCView.setVisibility(View.VISIBLE);
} else {
fragmentCView.setVisibility(View.INVISIBLE);
}
menuIsOn = !menuIsOn;
}
});
Create the Instances of fragments and add instead of replace
FragA fa= new FragA();
FragB fb= new FragB();
FragC fc= new FragB();
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragmnt_container, fa);
fragmentTransaction.add(R.id.fragmnt_container, fb);
fragmentTransaction.add(R.id.fragmnt_container, fc);
fragmentTransaction.show(fa);
fragmentTransaction.hide(fb);
fragmentTransaction.hide(fc);
fragmentTransaction.commit();
suppose we want to to hide and show different fragments based on our action
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.hide(fa);
fragmentTransaction.show(fb);
fragmentTransaction.hide(fc);
fragmentTransaction.commit();

Resources