简介
Loaders机制是在Android3.0 版本之后引入的异步加载数据的方法,能解决长时间加载数据的问题
特点
1.适用于任何Activity和Fragment
2.提供了异步加载数据的机制
3.检测数据源,当数据源的内容改变是他们能够传递新的结果
相关API
LoaderManager:管理Loader,每个Activity或Fragment都对应一个LoaderManager
LoaderCallbacks:包含和Loader相关的回调方法
AsyncTaskLoader:抽象类,提供异步加载的方法
Cursors Loader:AsyncTaskLoader的子类,提供游标数据的加载,本地数据库数据的加载
案例:使用Loader加载本地联系人:
package com.hejun.loader; import android.Manifest; import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.provider.ContactsContract; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v4.app.LoaderManager; import android.support.v4.content.ContextCompat; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v7.app.AppCompatActivity; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.widget.CursorAdapter; import android.widget.EditText; import android.widget.ListView; import android.widget.SimpleCursorAdapter; import butterknife.BindView; import butterknife.ButterKnife; public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> { //绑定资源 @BindView(R.id.listView) ListView listView; @BindView(R.id.ed) EditText ed; private SimpleCursorAdapter cursorAdapter; private LoaderManager loaderManager; private String content; private Uri contentUri; private CursorLoader cursorLoader; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); requestPermission(); //获取loaderManager对象 loaderManager = getSupportLoaderManager(); //初始化Loader 参数1 ID 参数2 传递的参数 参数3 LoaderCallbacks 回调接口 loaderManager.initLoader(0, null, this); cursorAdapter = new SimpleCursorAdapter(this, android.R.layout.activity_list_item, null, new String[]{ContactsContract.Contacts.DISPLAY_NAME}, new int[]{android.R.id.text1}, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); listView.setAdapter(cursorAdapter); ed.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { content = s.toString(); //重新加载Loader loaderManager.restartLoader(0,null,MainActivity.this); } @Override public void afterTextChanged(Editable s) { } }); } /** * 创建Loader对象 * * @param i * @param bundle * @return */ @NonNull @Override public Loader<Cursor> onCreateLoader(int i, @Nullable Bundle bundle) { contentUri = ContactsContract.Contacts.CONTENT_URI; if (!TextUtils.isEmpty(content)){ contentUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI,Uri.encode(content)); } cursorLoader = new CursorLoader(this, contentUri, null, null, null, null); return cursorLoader; } /** * 在UI线程中运行,加载数据完成后,更新UI * * @param loader * @param cursor */ @Override public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor cursor) { //在主线程中完成, 切换cursorAdapter中的游标 cursorAdapter.swapCursor(cursor); } /** * 重置Loader * * @param loader */ @Override public void onLoaderReset(@NonNull Loader<Cursor> loader) { //销毁游标 cursorAdapter.swapCursor(null); } //动态申请权限 private void requestPermission() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 0);//申请权限 } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case 0: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { return; } else { finish(); } break; } } }
自定义Loader:使用Loader加载自定义数据类型
步骤:
1.继承AsycnTaskLoader类
2.实现loadInBackground方法
3.使用LoadManager初始化Loader
4.在LoaderCallbacks接口的OnCreateLoader方法中返回自定义Loader
案例:从网上加载用户信息(name password)
用户类
class Userbean { private String name; private String password; public Userbean(String name, String password) { this.name = name; this.password = password; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
自定义Loader
package com.hejun.loader; import android.content.Context; import android.os.AsyncTask; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.content.AsyncTaskLoader; import java.util.ArrayList; import java.util.List; /** * 自定义Loader,加载UserBean数据集合 */ public class LoaderUser extends AsyncTaskLoader<List<Userbean>> { public LoaderUser(@NonNull Context context) { super(context); } @Override protected void onStartLoading() { super.onStartLoading(); //Loader开始执行后,强制调用loadInBackground()方法 if (isStarted()){ forceLoad(); } } /** * 在子线程中加载数据 * @return */ @Nullable @Override public List<Userbean> loadInBackground() { //模拟从网上获取数据 List<Userbean> users = new ArrayList<>(); users.add(new Userbean("zhangsan","123456")); users.add(new Userbean("lisi","123456")); users.add(new Userbean("wangwu","123456")); users.add(new Userbean("zhaoliu","123456")); return users; } }
MainActivity:
package com.hejun.loader; import android.content.Context; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.support.v7.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; import java.util.ArrayList; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public class Main2Activity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<List<Userbean>> { @BindView(R.id.listView) ListView listView; private List<Userbean> list = new ArrayList<>(); private Adapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); ButterKnife.bind(this); LoaderManager loaderManager = getSupportLoaderManager(); loaderManager.initLoader(0, null, this); adapter = new Adapter(this); listView.setAdapter(adapter); } @NonNull @Override public Loader<List<Userbean>> onCreateLoader(int i, @Nullable Bundle bundle) { //返回自定义Loader return new LoaderUser(this); } @Override public void onLoadFinished(@NonNull Loader<List<Userbean>> loader, List<Userbean> uerbeanList) { adapter.addUsers(uerbeanList); adapter.notifyDataSetChanged(); } @Override public void onLoaderReset(@NonNull Loader<List<Userbean>> loader) { } class Adapter extends BaseAdapter { private Context context; private List<Userbean> users = new ArrayList<>(); public Adapter(Context context) { this.context = context; } public void addUsers(List<Userbean> userList) { users.addAll(userList); notifyDataSetChanged(); } @Override public int getCount() { return users.size(); } @Override public Userbean getItem(int position) { return users.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null; if (convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.item, parent, false); viewHolder = new ViewHolder(convertView); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } Userbean userbean = users.get(position); viewHolder.name.setText(userbean.getName()); viewHolder.password.setText(userbean.getPassword()); return convertView; } class ViewHolder { @BindView(R.id.name) TextView name; @BindView(R.id.password) TextView password; ViewHolder(View view) { ButterKnife.bind(this, view); } } } }
总结
可以用CursorsLoader加载数据库,ContentProvider数据
对于自定义数据类型,可以自定义Loader来实现