You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

首次开发Android应用:现在引入Fragment实现ViewPager是否太晚?

关于在NFC应用中引入Fragment+ViewPager的代码迁移建议

兄弟,完全不用慌,现在引入Fragment一点都不晚!而且根本不需要把MainActivity里的所有代码都迁移到Fragment,你只需要把和UI交互、业务逻辑(比如NFC扫描、QR码扫描的具体处理)相关的部分移过去,Activity只需要承担「容器」的核心职责就行。下面给你拆解清楚:

一、MainActivity该保留什么?

  • 全局初始化与系统级配置:比如Slidr.attach(this)、NFC适配器的全局初始化、PendingIntent的创建(因为涉及Activity上下文绑定)。
  • ViewPager管理:负责创建ViewPager、设置Adapter、添加Fragment到ViewPager,这是Activity作为容器的核心工作。
  • 生命周期绑定的系统操作:比如onResume/onPause里的NFC前台调度(enableForegroundDispatch/disableForegroundDispatch),这部分和Activity生命周期强绑定,留在Activity更稳妥。
  • 系统回调转发:onNewIntent、onActivityResult这类系统回调,Activity只需要把事件转发给对应的Fragment处理即可。

二、哪些代码应该迁移到MainFragment?

  • UI控件与交互逻辑:比如nfcButton、qrButton的初始化、点击事件,还有动画效果manageBlinkEffect,这些属于Fragment负责的页面内交互。
  • 业务核心逻辑:NFC扫描的解析(resolveIntent)、结果弹窗处理(getResult),以及QR码扫描的结果处理,这些和页面内容直接相关,放在Fragment更符合单一职责。

三、结合你的代码给出具体迁移示例

1. 改造后的MainActivity

public class MainActivity extends FragmentActivity {
    private NfcAdapter nfcAdapter;
    private PendingIntent pendingIntent;
    private SlidrInterface slidr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        slidr = Slidr.attach(this);
        setContentView(R.layout.activity_main);

        // 初始化ViewPager和Fragment适配器
        ViewPager viewPager = findViewById(R.id.view_pager);
        FragmentPagerAdapter adapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
            @NonNull
            @Override
            public Fragment getItem(int position) {
                return new MainFragment();
            }

            @Override
            public int getCount() {
                return 1; // 后续新增页面时修改数量
            }
        };
        viewPager.setAdapter(adapter);

        // NFC全局初始化
        this.nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        this.pendingIntent = PendingIntent.getActivity(this, 0,
                new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (nfcAdapter != null) {
            if (!nfcAdapter.isEnabled()) {
                showWirelessSettings();
            }
            nfcAdapter.enableForegroundDispatch(this, pendingIntent, null, null);
        }
        // 把NFC检测状态传递给Fragment
        MainFragment fragment = getCurrentMainFragment();
        if (fragment != null) fragment.setDetect(1);
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (nfcAdapter != null) {
            nfcAdapter.disableForegroundDispatch(this);
        }
        // 通知Fragment停止检测
        MainFragment fragment = getCurrentMainFragment();
        if (fragment != null) fragment.setDetect(0);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        // 把NFC意图转发给Fragment处理
        MainFragment fragment = getCurrentMainFragment();
        if (fragment != null) fragment.handleNewIntent(intent);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        // 把QR扫描结果转发给Fragment
        MainFragment fragment = getCurrentMainFragment();
        if (fragment != null) fragment.handleActivityResult(requestCode, resultCode, data);
    }

    private MainFragment getCurrentMainFragment() {
        return (MainFragment) getSupportFragmentManager()
                .findFragmentByTag("android:switcher:" + R.id.view_pager + ":0");
    }

    private void showWirelessSettings() {
        Toast.makeText(this, "Veuillez activer le service NFC", Toast.LENGTH_SHORT).show();
        startActivity(new Intent("android.settings.WIRELESS_SETTINGS"));
    }
}

2. 新建的MainFragment

public class MainFragment extends Fragment {
    ObjectAnimator anim;
    ObjectAnimator anim2;
    private int display, result, detect = 0;
    private ImageButton nfcButton;
    private TextView text;
    private ImageButton qrButton;
    private ImageButton webButton;
    String link = null;
    public final int CUSTOMIZED_REQUEST_CODE = 0x0000ffff;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_main, container, false);
        // 初始化页面UI控件
        this.text = view.findViewById(R.id.text);
        this.nfcButton = view.findViewById(R.id.nfc_button);
        this.qrButton = view.findViewById(R.id.qr_button);
        this.webButton = view.findViewById(R.id.web_button);

        // 初始化动画
        this.anim = ObjectAnimator.ofFloat(this.nfcButton, "scaleX", 0.9f);
        this.anim2 = ObjectAnimator.ofFloat(this.nfcButton, "scaleY", 0.9f);

        // QR扫描初始化
        IntentIntegrator integrator = IntentIntegrator.forSupportFragment(this);

        // NFC按钮点击事件
        this.nfcButton.setOnClickListener(v -> {
            setDisplay(1);
            manageBlinkEffect();
        });

        return view;
    }

    public void manageBlinkEffect() {
        anim.setDuration(1000);
        anim.setRepeatMode(ValueAnimator.REVERSE);
        anim.setRepeatCount(9);
        anim.start();
        anim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                if (getRes() != 1) {
                    Animation shake = AnimationUtils.loadAnimation(getContext(), R.anim.shake);
                    Toast.makeText(getContext(), "Aucun badge n'a été détécté !", Toast.LENGTH_SHORT).show();
                    nfcButton.startAnimation(shake);
                }
            }
        });
        anim2.setDuration(1000);
        anim2.setRepeatMode(ValueAnimator.REVERSE);
        anim2.setRepeatCount(9);
        anim2.start();
    }

    // 接收Activity传递的NFC意图
    public void handleNewIntent(Intent intent) {
        if (getDetect() != 1) {
            resolveIntent(intent);
        }
    }

    // 接收Activity传递的QR扫描结果
    public void handleActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode != CUSTOMIZED_REQUEST_CODE && requestCode != IntentIntegrator.REQUEST_CODE) {
            return;
        }
        switch (requestCode) {
            case CUSTOMIZED_REQUEST_CODE:
                Toast.makeText(getContext(), "REQUEST_CODE = " + requestCode, Toast.LENGTH_LONG).show();
                break;
            default:
                break;
        }
        IntentResult result = IntentIntegrator.parseActivityResult(resultCode, data);
        if (result.getContents() != null) {
            Log.d("MainFragment", "Scanned");
            AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
            builder.setTitle("Résultat du scan :");
            if (URLUtil.isValidUrl(result.getContents())) {
                builder.setNeutralButton("Visiter", (dialog, which) -> {});
                builder.setPositiveButton("Fermer", (dialog, which) -> {});
                builder.setNegativeButton("Copier", (dialog, which) -> {
                    ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
                    ClipData clip = ClipData.newPlainText("Texte copié", result.getContents());
                    clipboard.setPrimaryClip(clip);
                });
            } else {
                builder.setNeutralButton("Copier", (dialog, which) -> {
                    ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
                    ClipData clip = ClipData.newPlainText("Texte copié", result.getContents());
                    clipboard.setPrimaryClip(clip);
                });
                builder.setPositiveButton("Fermer", (dialog, which) -> {});
            }
            builder.setMessage(result.getContents().toString());
            builder.create().show();
        }
    }

    private void resolveIntent(Intent intent) {
        NdefMessage[] msgs;
        String action = intent.getAction();
        Log.d("Infos", getActivity().getIntent().toString());
        Log.d("Infos", "display = " + display);
        if (getDisplay() != 1) {
            Animation shake = AnimationUtils.loadAnimation(getContext(), R.anim.shake);
            nfcButton.startAnimation(shake);
            Toast.makeText(getContext(), "Veuillez lancer un scan", Toast.LENGTH_LONG).show();
            return;
        } else if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action) ||
                NfcAdapter.ACTION_TECH_DISCOVERED.equals(action) ||
                NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
            setRes(1);
            Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
            if (rawMsgs != null) {
                msgs = new NdefMessage[rawMsgs.length];
                for (int i = 0; i < rawMsgs.length; i++) {
                    msgs[i] = (NdefMessage) rawMsgs[i];
                }
            } else {
                byte[] empty = new byte[0];
                byte[] id = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);
                Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
                byte[] payload = NdefMessageParser.dumpTagData(tag).getBytes();
                NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN, empty, id, payload);
                NdefMessage msg = new NdefMessage(new NdefRecord[]{record});
                msgs = new NdefMessage[]{msg};
            }
            if (getDisplay() == 1) {
                getResult(msgs);
            }
        }
    }

    private void getResult(NdefMessage[] msgs) {
        if (msgs != null && msgs.length != 0) {
            final StringBuilder tmp_builder = new StringBuilder();
            List<ParsedNdefRecord> records = NdefMessageParser.parse(msgs[0]);
            int size = records.size();
            for (int i = 0; i < size; i++) {
                tmp_builder.append(records.get(i).str());
                tmp_builder.append("\n");
            }
            System.out.println(tmp_builder.toString());
            this.anim.cancel();
            this.anim2.cancel();
            setDisplay(0);
            AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
            builder.setTitle("Resultat du scan :");
            builder.setNeutralButton("Visiter", (dialog, which) -> {
                link = tmp_builder.toString();
                // 这里可以添加跳转逻辑
            });
            builder.setNegativeButton("Copier", (dialog, which) -> {
                ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
                ClipData clip = ClipData.newPlainText("Texte copié", link);
                clipboard.setPrimaryClip(clip);
            });
            builder.setPositiveButton("Fermer", (dialog, which) -> {});
            builder.setMessage(tmp_builder.toString());
            builder.create().show();
        }
    }

    // Getter & Setter
    public int getDisplay() { return display; }
    public void setDisplay(int display) { this.display = display; }
    public int getRes() { return result; }
    public void setRes(int result) { this.result = result; }
    public int getDetect() { return detect; }
    public void setDetect(int detect) { this.detect = detect; }
}

3. 布局调整

  • activity_main.xml替换为ViewPager容器:
<?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_main.xml,把原来activity_main.xml中的UI控件(TextView、ImageButton等)全部移过来。

最后补充几点建议

  • 不用一步到位:先保证ViewPager能正常运行,核心逻辑迁移完成,后续再慢慢优化细节(比如用registerForActivityResult替代onActivityResult,更符合Jetpack规范)。
  • Fragment中获取上下文用getContext()或requireContext(),避免空指针。
  • NFC前台调度留在Activity是合理的,因为它和Activity生命周期强绑定,不会因为Fragment重建导致调度异常。

内容的提问来源于stack exchange,提问作者aagrios

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 16:47:51