新聞/資訊類 App 典型需求:Fragment 承載列表,支持下拉刷新重置數據、上拉分頁加載追加數據、點擊跳轉詳情。
Pullable 介面的 ListView,配合刷新佈局判斷是否到達頂/底部。UpDataAdapter 刷新/追加模式。
public class NewsFragment extends Fragment {
// UI 組件
private PullToRefreshLayout refreshLayout;
private PullableListView listView;
private TextView categoryTv;
// 數據
private List dataList = new ArrayList<>(); // 當前頁數據
private List allData = new ArrayList<>(); // 累計數據 (上拉追加用)
private NewsAdapter adapter;
// 分頁
private int page = 0;
private String categoryUrl; // 從 Bundle 獲取
// Handler 處理網絡回調
private Handler handler = new Handler(msg -> {
String json = (String) msg.obj;
List pageData = new Gson().fromJson(json, new TypeToken>(){}.getType());
if (msg.what == REFRESH) { // 下拉刷新
dataList.clear();
dataList.addAll(pageData);
allData.clear();
allData.addAll(pageData);
page = 1;
} else if (msg.what == LOAD_MORE) { // 上拉加載
dataList.clear(); // 適配器只顯示最新頁?或 allData.addAll(pageData) 視需求
allData.addAll(pageData);
page++;
}
adapter.notifyDataSetChanged(); // 或 adapter.upDataAdapter(allData)
refreshLayout.refreshFinish(PullToRefreshLayout.SUCCEED);
refreshLayout.loadmoreFinish(PullToRefreshLayout.SUCCEED);
return true;
});
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_news, container, false);
// 初始化視圖
refreshLayout = view.findViewById(R.id.refreshLayout);
listView = view.findViewById(R.id.listView);
categoryTv = view.findViewById(R.id.categoryTv);
// 設置日期
setCurrentDate();
// 獲取傳入參數 (category)
Bundle args = getArguments();
if (args != null) categoryUrl = UrlMap.getUrl(args.getString("category"));
// 適配器
adapter = new NewsAdapter(getActivity(), allData, listView);
listView.setAdapter(adapter);
// 點擊跳轉詳情
listView.setOnItemClickListener((parent, v, pos, id) -> {
NewsItem item = allData.get(pos);
Intent intent = new Intent(getActivity(), DetailActivity.class);
intent.putExtra("url", item.getUrl());
intent.putExtra("img", item.getImageUrl());
intent.putExtra("title", item.getTitle());
startActivity(intent);
});
// 刷新/加載監聽
refreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override public void onRefresh(PullToRefreshLayout layout) {
page = 0;
loadData(categoryUrl, REFRESH);
}
@Override public void onLoadMore(PullToRefreshLayout layout) {
loadData(categoryUrl, LOAD_MORE);
}
});
// 首次加載
loadData(categoryUrl, REFRESH);
return view;
}
private void loadData(String url, int type) {
new Thread(() -> {
String json = NetUtil.get(url + (type == LOAD_MORE ? page : ""));
handler.sendMessage(handler.obtainMessage(type, json));
}).start();
}
private void setCurrentDate() { /* Calendar 格式化設置 TextView */ }
}
page=0、清空列表;加載遞增 page++、追加數據。URL 拼接頁碼參數。dataList (適配器當前顯示) 與 allData (全量累計)。根據產品需求決定適配器綁定哪個 (瀑布流通常綁 allData)。WeakReference<Fragment>,或 Fragment.onDestroy() 移除消息 handler.removeCallbacksAndMessages(null)。NetUtil.get(),完成後 handler.sendMessage() 切回主線程解析更新 UI。Adapter.getView() 使用 ViewHolder 模式,convertView 復用。onCreateView 返回 view 前判斷 view.getParent() != null 移除,防止重複添加報錯。| 舊方案 | 現代替代 | 優勢 |
|---|---|---|
| ListView + 自定義刷新佈局 | RecyclerView + SwipeRefreshLayout / SmartRefreshLayout | 項目解耦、動畫豐富、支持 Grid/Staggered、性能更好 |
| Handler + Thread | RxJava / Coroutines (Flow) / Retrofit + LiveData | 鏈式調用、生命週期感知、取消簡單、異常處理統一 |
| Gson 手動解析 | Moshi / Kotlinx Serialization | Kotlin 友好、性能更強、類型安全 |
| Fragment 手動管理 | Jetpack Navigation + ViewBinding | 導航圖可視化、安全參數傳遞、返回棧自動管理 |
這個 Fragment 範例展示了 Android 傳統開發模式下「列表刷新分頁」的完整閉環:視圖綁定、手勢識別、異步網絡、JSON 解析、主線程更新、分頁狀態管理。理解這套邏輯,有助於維護老項目、遷移到現代架構時做對應映射。**新項目請直接上 RecyclerView + Jetpack 全家桶。**