Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Destroy a Fragment when replaced

I've got a Fragment (fragment_address) that is shown in a Fragment container in my main activity. My fragment_address Fragment brings up a list of paired devices. When a listed item is clicked the Fragment is replaced in my main activity by another fragment. This Fragment has buttons to bring up other fragments. This all works fine until I click a button to bring up a new Fragment and the fragment_address is shown in the background as well as my new fragment. As the address fragment is only ever needed once is there a way to ensure this fragment is destroyed when replaced ?

My Main Activity.

import android.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity implements AddressFragment.OnAddressListener {
    private static final String TAG = "Main Activity";
    // MAC-address of Bluetooth module (you must edit this line)
    private static String address = "No Device Selected";
    private static String deviceName = "No Device Selected";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public void onAddressChanged(String itemAddress, String itemName){
        // Set your address
        address = itemAddress;
        deviceName = itemName;
        MainFragment fragMain = new MainFragment();
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        fragMain.setVariables(address, deviceName);
        ft.replace(R.id.main_frag, fragMain);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        ft.commit();
    }
}

The xml.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        class="com.ming.pondcontroller.AddressFragment"
        android:id="@+id/main_frag"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

My Address Fragment

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.Bundle;
import android.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import java.util.ArrayList;
import java.util.Set;

public class AddressFragment extends Fragment {

    private static final String TAG = "Address Activity";
    private BluetoothAdapter BA = null;
    private Set<BluetoothDevice> pairedDevices;
    LayoutInflater inflater2;
    ListView lv;
    String address;
    String itemName;
    String itemString;
    OnAddressListener mListener;

    public AddressFragment() {
        // Required empty public constructor
    }

    // Container Activity must implement this interface
    public interface OnAddressListener {
        public void onAddressChanged(String address, String itemName);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        inflater2 = inflater;
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_address, container, false);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (OnAddressListener ) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnAddressListener");
        }
    }

    @Override
    public void onStart(){
        super.onStart();
        lv = (ListView)getView().findViewById(R.id.listView);
        BA = BluetoothAdapter.getDefaultAdapter();
        checkBTState();

        // get paired devices
        pairedDevices = BA.getBondedDevices();
        ArrayList list = new ArrayList();
        // get a list of paired devices
        for(BluetoothDevice bt:pairedDevices){
            list.add(bt.getName()+"\n"+bt.getAddress());
        }
        // display the list in the list view
        final ArrayAdapter adapter = new ArrayAdapter(inflater2.getContext(),android.R.layout.simple_list_item_1,list);
        lv.setAdapter(adapter);

        // onItemClick Listener
        lv.setOnItemClickListener(new AdapterView.OnItemClickListener(){
            @Override
            public void onItemClick(AdapterView<?> adapterView,View view, int position, long l){
                // get the text of the item clicked from position
                itemString = (String)(lv.getItemAtPosition(position));
                // get last 17 characters for MAC address
                address = itemString.substring(itemString.length()-17);
                itemName = itemString.substring(0,itemString.length()-17);
                // send strings back to main Activity
                mListener.onAddressChanged(address,itemName);
            }
        }); //end of onClickListener
    }

    private void checkBTState() {
        // Check for Bluetooth support and then check to make sure it is turned on
        // Emulator doesn't support Bluetooth and will return null
        if(BA==null) {
            Log.d("Fatal Error", "Bluetooth not support");
        } else {
            if (BA.isEnabled()) {
                Log.d(TAG, "...Bluetooth ON...");
            } else {
                //Prompt user to turn on Bluetooth
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBtIntent, 1);
            }
        }
    }
}

My address Fragment xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorMainBack"
    tools:context="com.ming.pondcontroller.AddressFragment">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:id="@+id/textView"
        android:background="@color/colorPrimary"
        android:textColor="@color/colorWhite"
        android:textSize="20dp"
        android:text="Select Device"/>
    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/textView"
        android:background="@color/colorTextBack">
    </ListView> />
</RelativeLayout>

And my OnStart that is replacing the MainFragment with the ControlOutputs Fragment when butControlOutputs is called.

@Override
public void onStart() {
    super.onStart();
    TextView tv = (TextView)getView().findViewById(R.id.textIn);
    tv.setText(address);
    TextView tv2 = (TextView)getView().findViewById(R.id.textIn2);
    tv2.setText(deviceName);
    // Get ID's of buttons
    Button butSyncData = (Button)getActivity().findViewById(R.id.butSyncData);
    Button butControlOutputs = (Button)getActivity().findViewById(R.id.butControlOuts);
    Button butDateTime = (Button)getActivity().findViewById(R.id.butDateTime);
    Button butPreferences = (Button)getActivity().findViewById(R.id.butPreferences);
    Button butFullData = (Button)getActivity().findViewById(R.id.butFullData);
    // Create OnClick listener for each button
    butSyncData.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v){
            Log.d(TAG,"Button Get Now data Clicked");
            if(ConStatus == true){
                mConnectedThread.write(MainFragment.getNowData); // Sync Data to start
            }else if(!(address == "No Device Selected")) {
                btAdapter = BluetoothAdapter.getDefaultAdapter();       // get Bluetooth adapter
                BluetoothDevice device = btAdapter.getRemoteDevice(address);

                ConnectThread ct = new ConnectThread(device);
                ct.start();
            }
        }
    });

    butControlOutputs.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v){
            Log.d(TAG,"Control Outputs Clicked");
            // TODO rest of Control Outputs Launch
            OutputsFragment fragOutputs = new OutputsFragment();
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.replace(R.id.main_frag,fragOutputs);
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
            ft.commit();
        }
    });

    butDateTime.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v){
            Log.d(TAG,"Date & Time Clicked");
            Toast.makeText(getActivity(),"Date & Time Clicked",Toast.LENGTH_SHORT).show();
            // TODO rest of Date Time Launch
        }
    });

    butPreferences.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v){
            Log.d(TAG,"Preferences Clicked");
            Toast.makeText(getActivity(),"Preferences Clicked",Toast.LENGTH_SHORT).show();
            // TODO rest of Control Outputs Launch
        }
    });

    butFullData.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v){
            Log.d(TAG,"Full Data Clicked");
            Toast.makeText(getActivity(),"Full Data Clicked",Toast.LENGTH_SHORT).show();
            // TODO rest of Control Outputs Launch
        }
    });

    // Start thread to connect to bluetooth
    if(!(address == "No Device Selected")) {
        btAdapter = BluetoothAdapter.getDefaultAdapter();       // get Bluetooth adapter
        BluetoothDevice device = btAdapter.getRemoteDevice(address);

        ConnectThread ct = new ConnectThread(device);
        ct.start();
    }
} // End of on start

I've had the addToBackStack in and removed it again. I thought the ft.replace would destroy the previous Fragment if the previous one was not added to the back stack ??

I've added this to the OnClickListener. It adds the MainFragment but always returns 'null' for the AddressFragment.

Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_frag);
        if(fragment != null) {
            Log.d("In OAC","Fragment Not NULL");
            getSupportFragmentManager().beginTransaction().remove(fragment).commit();
        }else{
            Log.d("In OAC","Fragment NULL");
        }
        MainFragment fragMain = new MainFragment();
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        fragMain.setVariables(address, deviceName);
        ft.add(R.id.main_frag, fragMain);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        ft.commit();
like image 767
fatmanming Avatar asked Oct 15 '16 16:10

fatmanming


People also ask

How do you end a fragment?

If you are using dynamic fragments, set up via a FragmentTransaction , you could run a transaction to replace() the old fragment with the new one.

Is fragment destroyed when activity is destroyed?

As Fragment is embedded inside an Activity, it will be killed when Activity is killed. As contents of activity are first killed, fragment will be destroyed just before activity gets destroyed.


1 Answers

If you don't remove manually these fragments, they are still attached to the activity. Your activity is not destroyed so these fragments are too. To remove (so destroy) these fragments, you can call:

You need to use findFragmentById for Fragment from XML file.

call this on MainActivity

Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_frag)

And this on OnClick Listener Method

 if(fragment != null)
        getSupportFragmentManager().beginTransaction().remove(fragment).commit();
like image 165
Emdad Hossain Avatar answered Oct 04 '22 17:10

Emdad Hossain