同步适配器模式(一)
来源:互联网 发布:家电售后服务软件 编辑:程序博客网 时间:2024/05/27 20:52
此篇文章为《打造高质量的Android应用 Android开发必知的50个诀窍》中的Hank23-同步适配器模式,主要模拟Gmail可以很好的处理在线和离线状态,给用户带来良好的用户体验。
Gmail通过同步适配器(AyncAdapter)实现上述功能,遗憾的是,尽管同步适配器是android提供的最好特性之一,但是却缺乏相应文档。
本文以what to do为例,实现前后端的代码,模拟离线和在线的状态,基本效果如下图:
这一部分先说客户端的离线实现方式。
1. 实现上面的ui效果,数据源为空时,显示暂无数据,虽然这样的效果实现方式有多种,这里还是提供一种高大上的方式,代码如下:
listView.setEmptyView(findViewById(R.id.kong));
<TextView android:id="@+id/kong" android:layout_width= "match_parent" android:layout_height= "match_parent" android:gravity="center" android:text="暂无数据" android:textSize="26sp" />
2. listView中的数据从数据库来,实现数据库的代码如下:
public class DatabaseHelper extends SQLiteOpenHelper { public static final String DATABASE_NAME = "todo.db"; public static final int DATAASE_VERSION = 1; public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATAASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { String sql = "CREATE TABLE " + ToDoContentProvider.TODO_TABLE_NAME + " (" + ToDoContentProvider. COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + ToDoContentProvider. COLUMN_SERVER_ID + " INTEGER, " + ToDoContentProvider. COLUMN_TITLE + " LONGTEXT, " + ToDoContentProvider. COLUMN_STATUS_FLAG + " INTEGER);"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { String sql = "drop table if exists todo"; db.execSQL(sql); onCreate(db); }}
3.Dao实现代码:dao中目前实现了增和删的操作,其关键代码是使用contentResolver操作内容提供者。dao其实可有可无,完全可以直接操作内容提供者。
public class ToDoDao { private static final ToDoDao instance = new ToDoDao(); private ToDoDao() { } public static ToDoDao getInstance() { return instance; } public void addNewToDo(ContentResolver contentResolver, ToDo todo, int flag) { ContentValues cv = new ContentValues(); cv.put(ToDoContentProvider. COLUMN_SERVER_ID, todo.getId()); cv.put(ToDoContentProvider. COLUMN_TITLE, todo.getTitle()); cv.put(ToDoContentProvider. COLUMN_STATUS_FLAG, flag); contentResolver.insert(ToDoContentProvider. CONTENT_URI, cv); } public void deleteToDo(ContentResolver contentResolver, int id) { contentResolver.delete(ToDoContentProvider. CONTENT_URI, ToDoContentProvider. COLUMN_ID + "=" + id, null); }}
4. 内容提供者代码
public class ToDoContentProvider extends ContentProvider { public static final String TODO_TABLE_NAME = "todos"; // getCanonicalName获取类全名(包名.类名) public static final String AUTHORITY = ToDoContentProvider.class .getCanonicalName(); public static final String COLUMN_ID = "_id"; public static final String COLUMN_SERVER_ID = "server_id"; public static final String COLUMN_TITLE = "title"; public static final String COLUMN_STATUS_FLAG = "status_flag"; private static final int TODO = 1; private static final int TODO_ID = 2; private static HashMap<String, String> projectionMap; private static UriMatcher sUriMatcher; // 带id表示单个,不带id表示多个 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.androidhacks.todo" ; public static final String CONTENT_TYPE_ID = "vnd.android.cursor.item/vnd.androidhacks.todo" ; public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + TODO_TABLE_NAME); private DatabaseHelper dbHelper; static { // 根据内容uri判断执行流程 sUriMatcher = new UriMatcher(UriMatcher. NO_MATCH); sUriMatcher.addURI( AUTHORITY, TODO_TABLE_NAME, TODO); sUriMatcher.addURI( AUTHORITY, TODO_TABLE_NAME + "/#", TODO_ID); projectionMap = new HashMap<>(); projectionMap.put( COLUMN_ID, COLUMN_ID); projectionMap.put( COLUMN_SERVER_ID, COLUMN_SERVER_ID); projectionMap.put( COLUMN_TITLE, COLUMN_TITLE); projectionMap.put( COLUMN_STATUS_FLAG, COLUMN_STATUS_FLAG); } @Override public boolean onCreate() { dbHelper = new DatabaseHelper(getContext()); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); switch ( sUriMatcher.match(uri)) { case TODO: qb.setTables( TODO_TABLE_NAME); qb.setProjectionMap( projectionMap); break; case TODO_ID: qb.setTables( TODO_TABLE_NAME); qb.setProjectionMap( projectionMap); qb.appendWhere( COLUMN_ID + "=" + uri.getPathSegments().get(1)); break; default: throw new RuntimeException( "Unknow uri"); } SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder);// 在cursor返回给调用者之前,我们注册了“ uri内容变动通知”,这样cursor会监控 uri内容变化,当发现 uri内容改变时,cursor会自动更新数据。 c.setNotificationUri(getContext().getContentResolver(), uri); return c; } @Override public String getType(Uri uri) { int match = sUriMatcher.match(uri); switch (match) { case TODO: return CONTENT_TYPE; case TODO_ID: return CONTENT_TYPE_ID; default: throw new RuntimeException( "no matcher uri"); } } @Override public Uri insert(Uri uri, ContentValues values) { // 操作数据库 SQLiteDatabase db = dbHelper.getWritableDatabase(); long _id = db.insertOrThrow( TODO_TABLE_NAME, null, values); // 通知数据已经改变 getContext().getContentResolver().notifyChange(uri, null); return buildUri( CONTENT_URI, String. valueOf(_id)); } public Uri buildUri(Uri uri, String id) { return uri.buildUpon().appendPath(id).build(); } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // 操作数据库 dbHelper.getWritableDatabase().delete( TODO_TABLE_NAME, selection, selectionArgs); // 通知数据改变 getContext().getContentResolver().notifyChange(uri, null); return 1; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { return 0; } public class StatusFlag { public static final int NORMAL = 0; public static final int DELETE = 1; public static final int CLEAN = 2; }}
5. listview设置的adapter是cursorAdapter
public class ToDoAdapter extends CursorAdapter { private Activity mActivity; private Holder holder; public ToDoAdapter(Context context, Cursor c) { super(context, c); mActivity = (Activity) context; } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { // 实例化view且处理逻辑 View view = View. inflate(context, R.layout.item_layout, null ); holder = new Holder(); holder. idView = (TextView) view.findViewById(R.id.id); holder. titleView = (TextView) view.findViewById(R.id.title ); holder. delete = (Button) view.findViewById(R.id.delete ); int columnId = cursor.getColumnIndex(ToDoContentProvider.COLUMN_ID ); int columnTitle = cursor .getColumnIndex(ToDoContentProvider. COLUMN_TITLE); final int id = cursor.getInt(columnId); String title = cursor.getString(columnTitle); holder. idView.setText(id + ""); holder. titleView.setText(title); holder. delete.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { ToDoDao. getInstance().deleteToDo( mActivity.getContentResolver(), id); ; } }); view.setTag( holder); return view; } @Override public void bindView(View view, Context context, Cursor cursor) { holder = (Holder) view.getTag(); // view不为null,只处理逻辑 int columnId = cursor.getColumnIndex(ToDoContentProvider.COLUMN_ID ); int columnTitle = cursor .getColumnIndex(ToDoContentProvider. COLUMN_TITLE); final int id = cursor.getInt(columnId); String title = cursor.getString(columnTitle); holder. idView.setText(id + ""); holder. titleView.setText(title); holder. delete.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { ToDoDao. getInstance().deleteToDo( mActivity.getContentResolver(), id);// 这里未调用notifyDataSetChanged,是因为之前调用过setNotificationUri方法,当通过provider更新数据库的时候, contentprovider返回的cursor也会被更新 } }); } static class Holder { TextView idView, titleView; Button delete; }}
6. 其实也可以不用内容提供者,直接使用数据库,这样做的好处是,通过cursor可以直接更新数据,还有2010年google开发者大会的一篇《rest》的文章,可能不充分,再补充。
0 0
- 同步适配器模式(一)
- 同步适配器模式(二)
- 同步适配器模式(三)
- 同步适配器模式(四)
- 适配器模式(一)
- 适配器模式(一)
- 适配器模式(一)
- 适配器模式(Adapter Pattern)(一):适配器模式介绍
- (结构型模式一)适配器模式
- 设计模式(一)之适配器模式
- 设计模式之接口型模式(一)----适配器模式
- 设计模式<一>适配器模式
- 设计模式<一>适配器模式
- 设计模式一日一练:适配器模式(Adapter)
- 设计模式初探(一)「适配器模式」
- 不兼容结构的协调——适配器模式(一):适配器模式概述
- 结构型设计模式(一)(适配器模式,桥接模式,组合模式,装饰模式)
- Java结构型设计模式-适配器(一)
- tomcat缓存清理
- 利用特性扩展元数据
- JSP如何获取用户的真实IP地址
- 整理了一些各类开发者都会用到的优秀资源
- try - catch - finally使用总结
- 同步适配器模式(一)
- myeclipse中servers视图优化(删除自带tomcat derby)配制& 删除MyEclipse中的 tomcat 6.x [Custom]
- 调用GetLastError 错误代码 含义
- 员工如何面对客户呢?
- WebDriver为何物?
- shortcut of moving line
- iOS基本控件-UIProgressView 进度条,(例如游戏进入的时候的加载条)
- 整理了8款炫酷的HTML5特效源码,大家可以学习下载
- jquery iframe 夸页面调用