3

I have an application with many fragments, and am trying to go from one fragment to another when a button is clicked.

The part I'm having trouble with is startActivity(new Intent(HomeFragment.this, FindPeopleFragment.class));

package info.androidhive.slidingmenu;

import info.androidhive.slidingmenu.HomeFragment;
import android.app.Fragment;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.Toast;

public class HomeFragment extends Fragment {

public HomeFragment() {
}

ImageButton bSearchByLocation, bSearchByNumber;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    super.onCreateView(inflater, container, savedInstanceState);
    View InputFragmentView = inflater.inflate(R.layout.fragment_home,
            container, false);

    bSearchByNumber = ((ImageButton) InputFragmentView
            .findViewById(R.id.bSearchByLocation));
    bSearchByLocation = ((ImageButton) InputFragmentView
            .findViewById(R.id.bSearchByNumber));

    bSearchByLocation.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            if (v.getId() == R.id.bSearchByNumber) {
                Toast.makeText(getActivity(), "1", Toast.LENGTH_SHORT)
                        .show();
                 startActivity(new Intent(HomeFragment.this, FindPeopleFragment.class));
            }
        }
    });
    bSearchByNumber.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            if (v.getId() == R.id.bSearchByLocation) {
                Toast.makeText(getActivity(), "2", Toast.LENGTH_SHORT)
                        .show();
            }
        }
    });
    return InputFragmentView;
}
}

after i do the solution the code look like this :

package info.androidhive.slidingmenu;

import info.androidhive.slidingmenu.HomeFragment;
import android.app.Fragment;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

public class HomeFragment extends Fragment {

public HomeFragment() {
}

ImageButton bSearchByLocation, bSearchByNumber;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    super.onCreateView(inflater, container, savedInstanceState);
    View InputFragmentView = inflater.inflate(R.layout.fragment_home,
            container, false);

    bSearchByNumber = ((ImageButton) InputFragmentView
            .findViewById(R.id.bSearchByLocation));
    bSearchByLocation = ((ImageButton) InputFragmentView
            .findViewById(R.id.bSearchByNumber));

    bSearchByLocation.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            if (v.getId() == R.id.bSearchByNumber) {
                Toast.makeText(getActivity(), "1", Toast.LENGTH_SHORT)
                        .show();
                startActivity(new Intent(getActivity(), FindPeopleFragment.class));
            }
        }
    });
    bSearchByNumber.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            if (v.getId() == R.id.bSearchByLocation) {
                Toast.makeText(getActivity(), "2", Toast.LENGTH_SHORT)
                        .show();
            }
        }
    });
    return InputFragmentView;
}
}

but when i Run it , the application crash and closed. this is my androidmanifest code :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="info.androidhive.slidingmenu"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="11"
    android:targetSdkVersion="17" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
    android:name="info.androidhive.slidingmenu.MainActivity"
    android:label="@string/app_name" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity android:name="info.androidhive.slidingmenu.FindPeopleFragment"></activity>
</application>

</manifest>

and this is my logchat: enter image description here

by the way .... i use this surce code and work on it : http://www.androidhive.info/2013/11/android-sliding-menu-using-navigation-drawer

Anson VanDoren
  • 956
  • 1
  • 12
  • 22
Rabeea Qabaha
  • 378
  • 3
  • 8
  • 23

3 Answers3

6

In Fragment, you should get the hosting activity (the context) as getActivity(). Try this instead:

startActivity(new Intent(getActivity(), FindPeopleFragment.class));  

Declare the FindPeopleFragment class in your manifest:

<activity
    android:name="com.packagename.FindPeopleFragment" />  

All Activities (not Fragment) must to be declare in your manifest file.

Also, check if FindPeopleFragment extends Activity or FragmentActivity. If this extends Fragment, don't do an Intent. You must to make a FragmentTransaction to replace (or add above) your old Fragment (HomeFragment).


UPDATE

You are wrong in the way to achieve this. You try to start a new Activity which, in your case, is a Fragment and not an activity (extends Fragment). To achieve this, you can:

// call a method when click event
((MyFragmentActivity) getActivity()).replaceFragments();

Then, inside your FragmentActivity, set the method as:

// replace the fragment container with this method
public void replaceFragments() {
    Fragment newFragment = new FindPeopleFragment();
    FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(R.id.fragment_container, newFragment);
    transaction.commit();
}  

UPDATE2

As @Squonk said in comment and also in his answer, my answer above is a solution but not the right one. To have a really proper solution, you need to declare a Callback interface and associate the Fragment with any Activity.

First declare an interface and attach it to your activity in your fragment:

OnFragSelected mCallback;

public interface OnFragSelected {
    public void OnFragSelected(int id);
}  

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

Then call this in your on click event:

@Override
public void onClick(View v) {
    mCallback.OnFragSelected(800);
}  

Finally, in your fragment activity:

... implements HomeFragment.OnFragSelected {

    Fragment newFragment;

    @Override
    public void OnFragSelected(int id) {
        // example: id = 800
        // ...
        newFragment = new FindPeopleFragment();
        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        transaction.replace(R.id.fragment_container, newFragment);
        transaction.commit();
    }

}  

This way "is more flexible [...] Multiple activities can now embed your Fragment, they just have to implement the communication interface". This is important because "your fragment is re-usable and therefore do not depend on that specific Activity". Also, if you "use the fragment elsewhere, you eradicate the risk of a RuntimeException because it is strongly typed."

This question and these answers about Fragment 2 fragment communicating can show you the difference. Here, you have the google example and this answer: onAttach callback from fragment to activity might you to figure it out.

Community
  • 1
  • 1
Blo
  • 11,903
  • 5
  • 45
  • 99
  • its look fine with code ... but when i start the application and clicked the button , the application crash :( @Fllo – Rabeea Qabaha Mar 22 '14 at 00:31
  • Edit your question and post errors and the LogCat that you have. – Blo Mar 22 '14 at 00:32
  • what i do now please @Fllo – Rabeea Qabaha Mar 22 '14 at 00:42
  • @RabeeaQabaha "com.yourpackagename" means "info.androidhive.slidingmenu" in your case ;) – Blo Mar 22 '14 at 01:06
  • this is the FindPeople fragment :"public class FindPeopleFragment extends Fragment { " and i added the logchat you can see it – Rabeea Qabaha Mar 22 '14 at 01:07
  • When you read your LogCat you see this: "Unable to find explicit activity class [...] have you declared this activity in your AndroidManifest.xml?" - It means that you have not declare the good activity, you have not declare this in manifest or (in your case) you're trying to start a Fragment with a start Activity method. I will edit my answer to make this behaviour with Fragment and not Activity. – Blo Mar 22 '14 at 01:11
  • 1
    @Fllo : Although the OP has accepted your answer, this is not a good way for a `Fragment` to communicate with its parent `Activity`. In your "UPDATE" example code it relies on the `Fragment` being attached to a parent `MyFragmentActivity` - this will prevent the `Fragment` being used with any other type of `Activity` without having to rewrite the code. Instead a `Fragment` should declare a callback interface and any `Activity` which uses that `Fragment` should implement the interface. In this way the `Fragment` never needs to know what kind of `Activity` it is attached to. – Squonk Mar 22 '14 at 02:09
  • @Squonk You have right! I updated my answer to show the proper way to achieve that. Feel free to edit it. Thanks. – Blo Mar 22 '14 at 03:27
  • hello @Fllo .... i Can't Understand Where should i put this three code that you updated – Rabeea Qabaha Mar 22 '14 at 19:17
  • Hi @RabeeaQabaha, you should see the 3 links at the end of my answer, espacially the google example (http://developer.android.com/training/basics/fragments/communicating.html). You'll see that the first two codes are in Fragment and the on click call the 3rd one in your FragmentActivity. Hope this helps. – Blo Mar 22 '14 at 19:23
1

Do this to your intent :

startActivity(new Intent(getActivity(), FindPeopleFragment.class));

and add this to your manifest :

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="info.androidhive.slidingmenu.MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
 <activity android:name="com.yourpackagename.FindPeopleFragment"></activity>
</application>

Add your activity to your manifest inside the applications tag.

It should work now .. :)

mike20132013
  • 5,357
  • 3
  • 31
  • 41
0

A Fragment should be modular, self-contained and reusable - it shouldn't know about other application components.

Don't start an Activity directly from a Fragment. Instead you should declare an interface which your parent Activity implements. When you click a button in your Fragment it should make a call to a method in the interface telling the parent Activity which button has been pressed. The parent Activity can then start which ever Activity is needed.

See Creating Event Callbacks

Squonk
  • 48,735
  • 19
  • 103
  • 135
  • @RabeeaQabaha : I've edited my answer to show a link which explains how to add an interface as a callback to the `Activity`. – Squonk Mar 22 '14 at 00:50