首次开发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
相关产品推荐
相关产品推荐

