Android Loader(三) 结合CursorLoader分析Loader相关源码
根据文档,自定义Loader需要实现的方法有,onStartLoading(),onStopLoading(), onForceLoad(), onReset()。
实现自定义Loader,很少直接继承Loader,可以继承Loader的子类AsyncTaskLoader,AsyncTaskLoader已经帮我们写好了 onForceLoad异步加载数据的逻辑,由于是从网络获取文本数据,采用Http的get协议访问比较合适,由于HttpGET是短连接,所以onStopLoading和onReset可以不用重写,考虑重写onStartLoading的逻辑即可。
加载数据的Loader: NetworkLoader.java
public class NetworkLoader extends AsyncTaskLoader<String> { private String result; public NetworkLoader(Context context) { super(context); } @Override protected void onStartLoading() { super.onStartLoading(); if (result != null) { deliverResult(result); } else { forceLoad(); } } @Override public String loadInBackground() { String url = "http://gc.ditu.aliyun.com/geocoding?a=苏州市"; return doGet(url); } private String doGet(String url) { BufferedReader in = null; try { HttpClient client = new DefaultHttpClient(); HttpGet request = new HttpGet(url); HttpResponse response = client.execute(request); in = new BufferedReader(new InputStreamReader(response.getEntity() .getContent())); StringBuffer sb = new StringBuffer(""); String line = ""; String NL = System.getProperty("line.separator"); while ((line = in.readLine()) != null) { sb.append(line + NL); } in.close(); String page = sb.toString(); return page; } catch (Exception e) { e.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } return url; } }onStartLoading方法进行判断,如果需要获取的数据已经存在,则直接调用deliverResult,前篇已经分析过,deliverResult会触发onLoadeFinished回调。如果没有数据,则进行异步加载数据过程,forceLoad内部会启动内部的AsyncTask,最终调用loadInBackground,耗时的加载网络数据的操作写在这里就可以。本例是通过一个URL获取一串字符串,这里URL地址找了个公开的测试接口。
再来看使用这个Loader的Fragment:
MsgFragment.java:
public class MsgFragment<T extends String> extends Fragment implements LoaderManager.LoaderCallbacks<String> { private TextView content; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.main, null); content = (TextView) v.findViewById(R.id.content); return v; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); getLoaderManager().initLoader(0, null, this); } @Override public Loader<String> onCreateLoader(int id, Bundle args) { return new NetworkLoader(getActivity()); } @Override public void onLoadFinished(Loader<String> loader, String data) { content.setText(data); } @Override public void onLoaderReset(Loader<String> loader) { } }这里在onLoadFinished中处理获取的字符串数据。
接下来就是Activity的代码;
MainActivity.java:
public class MainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); FragmentManager fm = getFragmentManager(); if (fm.findFragmentById(android.R.id.content) == null) { MsgFragment list = new MsgFragment(); fm.beginTransaction().add(android.R.id.content, list).commit(); } } }
布局文件就是一个简单的TextView。
Manifest:<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.httploader" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="21" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".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> </application> </manifest>工程目录:
最终效果: