启动片段活动

3

我有一个包含多个片段的应用程序,当单击按钮时,我试图从一个片段转到另一个片段。

我遇到了麻烦的部分是startActivity(新的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;
}
}

在我完成这个方案之后,代码看起来像这样:

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;
}
}

但是当我运行它时,应用程序会崩溃并关闭。 这是我的AndroidManifest代码:
<?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>

这是我的聊天记录:

enter image description here

顺便说一下,我使用了这个源代码并对其进行了修改:

http://www.androidhive.info/2013/11/android-sliding-menu-using-navigation-drawer
3个回答

6
Fragment中,您应该使用getActivity()获取托管活动(上下文)。请尝试使用此方法代替:
startActivity(new Intent(getActivity(), FindPeopleFragment.class));  

在您的清单文件中声明FindPeopleFragment类:
<activity
    android:name="com.packagename.FindPeopleFragment" />  

所有的活动(不包括片段)必须在您的清单文件中声明。此外,请检查FindPeopleFragment是否扩展了Activity或FragmentActivity。如果它扩展了Fragment,请不要使用Intent。您必须进行FragmentTransaction以替换(或添加到)您的旧Fragment(HomeFragment)。

更新

您在实现此功能的方式上有误。您尝试启动一个新的Activity,而在您的情况下,它是一个Fragment,而不是一个activity(扩展Fragment)。要实现这一点,您可以:

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

然后,在你的FragmentActivity中,将该方法设置为:
// 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();
}  

更新2

正如@Squonk在评论和他的答案中所说,我上面的答案是一种解决方案,但不是正确的解决方案。要有真正适当的解决方案,您需要声明一个回调接口并将Fragment与任何Activity相关联。

首先,在您的片段中声明一个接口并将其附加到您的活动中:

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..");
    }
}  

然后在您的点击事件中调用此函数:
@Override
public void onClick(View v) {
    mCallback.OnFragSelected(800);
}  

最后,在你的片段活动中:
... 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();
    }

}  

这种方法“更加灵活[...]多个活动现在可以嵌入您的片段,它们只需实现通信接口” 。这很重要,因为“您的片段是可重用的,因此不依赖于特定的活动”。此外,如果您“在其他地方使用该片段,则消除了由于强类型而导致的RuntimeException风险”。
这个问题和这些关于片段2片段通信的答案可以向您展示区别。这里,您有谷歌的例子和这个答案:从片段到活动的onAttach回调,可能会帮助您理解。

代码看起来很好……但是当我启动应用程序并单击按钮时,应用程序崩溃了 :( - Rabeea Qabaha
请编辑您的问题并发布错误和您拥有的LogCat。 - Blo
这是FindPeople片段:"public class FindPeopleFragment extends Fragment { ",我添加了logchat,你可以看到它。 - Rabeea Qabaha
当你阅读LogCat时,你会看到这样的提示:"无法找到显式活动类[...],你是否在AndroidManifest.xml中声明了此活动?" - 这意味着你没有声明正确的活动,在清单文件中没有声明或者(在你的情况下)你正在尝试使用启动Activity方法来启动一个Fragment。我将编辑我的答案,以便将此行为与Fragment而不是Activity相关联。 - Blo
1
@Fllo:虽然OP已经接受了你的答案,但这不是Fragment与其父Activity通信的好方法。在你的“UPDATE”示例代码中,它依赖于Fragment连接到父级MyFragmentActivity - 这将防止Fragment与任何其他类型的Activity一起使用而不必重写代码。相反,Fragment应该声明一个回调接口,使用该Fragment的任何Activity都应该实现该接口。通过这种方式,Fragment永远不需要知道它连接到哪种类型的Activity - Squonk
显示剩余5条评论

1
将以下操作应用于您的intent:

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

并将此添加到您的清单中:
<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>

将您的活动添加到应用程序标记中。

现在应该可以正常工作了.. :)


代码看起来很好……但是当我启动应用并点击按钮时,应用程序崩溃了 :( - Rabeea Qabaha
你的其他活动在清单中注册了吗?如果是,请发布你的日志。 - mike20132013
我不知道它是否已经注册,我在上面发布了清单代码。 - Rabeea Qabaha
还没有生效,我编辑了问题并更新了它 @mike20132013 - Rabeea Qabaha
错误提示说你的活动在清单文件中没有声明。 - mike20132013

0

Fragment 应该是模块化、自包含和可重用的 - 它不应该知道其他应用程序组件。

不要直接从 Fragment 启动一个 Activity。相反,您应该声明一个接口,您的父 Activity 实现它。当您在 Fragment 中单击按钮时,它应该调用接口中的方法,告诉父 Activity 按下了哪个按钮。然后,父 Activity 可以启动所需的任何 Activity

请参见 创建事件回调


@RabeeaQabaha:我已经编辑了我的答案,展示了一个链接,解释了如何将接口作为回调添加到“Activity”中。 - Squonk

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