加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

AutoCompleteTextView+SQLite实现自动检索

发布时间:2020-12-12 20:19:37 所属栏目:百科 来源:网络整理
导读:比如某些网页或 搜索引擎会把用户搜索过的内容记录下来,当下次输入曾经搜索过的内容也会列出来。来个图,就明白了 保存记录有四种方法:Preferences,Files,Databases,Network。这里以 Databases 为例,首先搭建个Provider(不会的童鞋可以参考sdk 里的de

比如某些网页或搜索引擎会把用户搜索过的内容记录下来,当下次输入曾经搜索过的内容也会列出来。来个图,就明白了

保存记录有四种方法:Preferences,Files,Databases,Network。这里以Databases 为例,首先搭建个Provider(不会的童鞋可以参考sdk 里的demo:NotePad-记事本)。

先看看目录结构:

Message.java定义一些常量,数据库字段及Uri:

package com.xyz.autocomplete.provider;

import android.net.Uri;
import android.provider.BaseColumns;

public class Message {
    public static final String AUTHORITY = "com.xyz.auto";

    public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.xyz.auto";
    public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.xyz.auto";

    public static final class Info implements BaseColumns {
        public static final String TABLE_NAME = "messages";
        public static final Uri CONTENT_URI = Uri.parse("content://"
                + AUTHORITY + "/messages");
        public static final Uri DELETE_ALL_URI = Uri.parse("content://"
                + AUTHORITY + "/messages/del/all");
        public static final String MESSAGE_CONTENT = "message";
        public static final String DEFAULT_SORT_ORDER = " message ASC ";
    }
}


DatabaseHelper.java创建数据库及建表:

package com.xyz.autocomplete.provider;

import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class DatabaseHelper extends SQLiteOpenHelper {

    public static final String DB_NAME = "msg.db";
    private static final int DB_VERSION = 1;


    public DatabaseHelper(Context context) {
        super(context,DB_NAME,null,DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // TODO Auto-generated method stub
        db.execSQL("CREATE TABLE " + Message.Info.TABLE_NAME + " ("
                + Message.Info._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
                + Message.Info.MESSAGE_CONTENT + " TEXT);");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion) {
        // TODO Auto-generated method stub
        db.execSQL("DROP TABLE IF EXISTS " + Message.Info.TABLE_NAME);
        onCreate(db);
    }

}


AutoProvider.java是继承ContentProvider对数据库进行插入,删除,查询,更新等操作,本例只需插入,查询,删除表几个操作:

package com.xyz.autocomplete.provider;

import java.sql.SQLException;
import java.util.HashMap;

import com.xyz.autocomplete.R;
import com.xyz.autocomplete.provider.Message.Info;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.widget.Toast;

public class AutoProvider extends ContentProvider {

    private static HashMap<String,String> sInfoProjectionMap;
    private static final int MESSAGE = 1;
    private static final int MESSAGE_ID = 2;
    private static final int DELETE_ALL = 3;

    private static final UriMatcher sUriMatcher;

    private DatabaseHelper mOpenHelper;

    static {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(Message.AUTHORITY,Info.TABLE_NAME,MESSAGE);
        sUriMatcher.addURI(Message.AUTHORITY,Info.TABLE_NAME + "/#",MESSAGE_ID);
        sUriMatcher.addURI(Message.AUTHORITY,Info.TABLE_NAME + "/del/all",DELETE_ALL);

        sInfoProjectionMap = new HashMap<String,String>();
        sInfoProjectionMap.put(Info._ID,Info._ID);
        sInfoProjectionMap.put(Info.MESSAGE_CONTENT,Info.MESSAGE_CONTENT);
    }

    ...

    @Override
    public boolean onCreate() {
        // TODO Auto-generated method stub
        mOpenHelper = new DatabaseHelper(getContext());
        return true;
    }
    
    @Override
    public Uri insert(Uri uri,ContentValues values) {
        // TODO Auto-generated method stub
        if (sUriMatcher.match(uri) != MESSAGE) {
            throw new IllegalArgumentException("Provider insert() Unknown URI "
                    + uri);
        }
        if (!values.containsKey(Info.MESSAGE_CONTENT)) {
            values.put(Info.MESSAGE_CONTENT,"default");
        }
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        long rowId = db.insert(Info.TABLE_NAME,values);
        if (rowId <= 0) {
            try {
                throw new SQLException("Failed to insert row into " + uri);
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        Uri retUri = ContentUris.withAppendedId(Info.CONTENT_URI,rowId);
        getContext().getContentResolver().notifyChange(retUri,null);
        Toast.makeText(
                getContext(),getContext().getString(R.string.insert_info)
                        + values.getAsString(Info.MESSAGE_CONTENT),Toast.LENGTH_SHORT).show();
        return retUri;
    }

    @Override
    public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder) {
        // TODO Auto-generated method stub
        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
        queryBuilder.setTables(Info.TABLE_NAME);
        switch (sUriMatcher.match(uri)) {
        case MESSAGE:
            queryBuilder.setProjectionMap(sInfoProjectionMap);
            break;
        case MESSAGE_ID:
            queryBuilder.setProjectionMap(sInfoProjectionMap);
            queryBuilder.appendWhere(Info._ID + " = "
                    + uri.getPathSegments().get(1));
            break;
        default:
            throw new IllegalArgumentException("Provider query() Unknown URI "
                    + uri);
        }
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        Cursor cursor = queryBuilder.query(db,projection,selection,selectionArgs,sortOrder);
        cursor.setNotificationUri(getContext().getContentResolver(),uri);
        return cursor;
    }
    
    @Override
    public int delete(Uri uri,String[] selectionArgs) {
        // TODO Auto-generated method stub
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        int count;
        switch (sUriMatcher.match(uri)) {
        ...
        case DELETE_ALL:
            db.execSQL("DROP TABLE IF EXISTS " + Info.TABLE_NAME);
            db.execSQL("CREATE TABLE " + Message.Info.TABLE_NAME + " ("
                    + Message.Info._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
                    + Message.Info.MESSAGE_CONTENT + " TEXT);");
            return -1;
        default:
            throw new IllegalArgumentException("Provider delete() Unknown URI "
                    + uri);
        }
        getContext().getContentResolver().notifyChange(uri,null);
        return count;
    }
    ...

}

上面3个文件就把Provider搭建好了,剩下要做的就是把记录集里以AutoCompleteTextView输入内容为头(startWith)的记录检索出来并显示出来。AutoCompleteTextView有个很重要的属性是android:completionThreshold,用于表明最小要敲入多少字符才开始显示list filter。AutoCompleteTextView要列出内容肯定要给它传一个数据源(记录集),就是通过setAdapter,这个适配器有个要求就是要实现android.widget.Filterable 接口,最简单的可以用ArrayAdapter ,如果用它的话,PopupListView样式不怎么好看,自定义适配器,自定义布局就好多了,请看:AutoCompleteAdapter.java(参考ArrayAdapter):

package com.xyz.autocomplete;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

public class AutoCompleteAdapter extends BaseAdapter implements Filterable {

    private int mLayoutId;
    private AutoFilter mFilter;
    private Context mContext;
    private List<String> mData;
    private List<String> mObjects;

    private Object mLock = new Object();

    public AutoCompleteAdapter(Context ctx,int layout,ArrayList<String> data) {
        mContext = ctx;
        mLayoutId = layout;
        mData = data;
        mObjects = data;
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return mObjects.size() > 0 ? mObjects.size() + 1 : 0;
    }

    @Override
    public String getItem(int position) {
        // TODO Auto-generated method stub
        return position < getCount() - 1 ? mObjects.get(position) : mContext
                .getString(R.string.clear_info);
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @Override
    public View getView(int position,View convertView,ViewGroup parent) {
        // TODO Auto-generated method stub
        ViewHolder holder = new ViewHolder();
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(
                    R.layout.auto_complete_item,null);
            holder.mShowText = (TextView) convertView.findViewById(R.id.item);
            holder.mIcon = (ImageView) convertView.findViewById(R.id.icon);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        if (position == 0) {
            convertView.setBackgroundResource(R.drawable.item_corner_top);
            holder.mShowText.setText(getItem(position));
            holder.mIcon.setVisibility(View.GONE);
        } else if (position == getCount() - 1) {
            convertView.setBackgroundResource(R.drawable.item_corner_bottom);
            holder.mShowText.setText(mContext.getString(R.string.clear_info));
            holder.mIcon.setVisibility(View.VISIBLE);
        } else {
            convertView.setBackgroundResource(R.drawable.item_corner_shape);
            holder.mShowText.setText(getItem(position));
            holder.mIcon.setVisibility(View.GONE);
        }
        return convertView;
    }

    class ViewHolder {
        TextView mShowText;
        ImageView mIcon;
    }

    @Override
    public Filter getFilter() {
        // TODO Auto-generated method stub
        if (mFilter == null) {
            mFilter = new AutoFilter();
        }
        return mFilter;
    }

    private class AutoFilter extends Filter {

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            // TODO Auto-generated method stub
            FilterResults results = new FilterResults();
            if (constraint == null || constraint.length() == 0) {
                ArrayList<String> list;
                synchronized (mLock) {
                    list = new ArrayList<String>(mData);
                }
                results.values = list;
                results.count = list.size();
            } else {
                String prefixString = constraint.toString().toLowerCase();
                ArrayList<String> values;
                synchronized (mLock) {
                    values = new ArrayList<String>(mData);
                }

                final int count = values.size();
                final ArrayList<String> newValues = new ArrayList<String>();

                for (int i = 0; i < count; i++) {
                    final String value = values.get(i);
                    final String valueText = value.toString().toLowerCase();

                    // First match against the whole,non-splitted value
                    if (valueText.startsWith(prefixString)) {
                        newValues.add(value);
                    } else {
                        final String[] words = valueText.split(" ");
                        final int wordCount = words.length;

                        // Start at index 0,in case valueText starts with
                        // space(s)
                        for (int k = 0; k < wordCount; k++) {
                            if (words[k].startsWith(prefixString)) {
                                newValues.add(value);
                                break;
                            }
                        }
                    }
                }
                results.values = newValues;
                results.count = newValues.size();
            }
            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint,FilterResults results) {
            // TODO Auto-generated method stub
            mObjects = (List<String>) results.values;
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }
    }
}

MainActivity.java做的事情是查询数据库,绑定数据源给AutoCompleteTextView:

package com.xyz.autocomplete;

import java.util.ArrayList;
import java.util.List;

import com.xyz.autocomplete.provider.DatabaseHelper;
import com.xyz.autocomplete.provider.Message.Info;

import android.app.Activity;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener,OnItemClickListener {

    private EditText mInputText;
    private Button mBtn;
    private AutoCompleteTextView mAutoCompleteView;
    private static final int QUERY_AUTO_TOKEN = 100;
    private ArrayList<String> mData = new ArrayList<String>();
    private AutoCompleteAdapter mAutoAdaper = null;
    private DbChangeResolver mDbChangeResolver;

    private QueryHandler mQueryHandler = null;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mInputText = (EditText) findViewById(R.id.input);
        mBtn = (Button) findViewById(R.id.add);
        mBtn.setOnClickListener(this);
        mAutoCompleteView = (AutoCompleteTextView) findViewById(R.id.auto_complete);
        mAutoCompleteView.setOnItemClickListener(this);

        mAutoAdaper = new AutoCompleteAdapter(this,R.layout.auto_complete_item,mData);
        mAutoCompleteView.setAdapter(mAutoAdaper);
        mQueryHandler = new QueryHandler(getContentResolver());
        startQuery();
        mDbChangeResolver = new DbChangeResolver(new Handler());
        getContentResolver().registerContentObserver(
                Info.CONTENT_URI,true,mDbChangeResolver);
    }
    
    private void startQuery() {
        mQueryHandler.startQuery(QUERY_AUTO_TOKEN,new Integer(0),Info.CONTENT_URI,new String[] { Info.MESSAGE_CONTENT },Info.DEFAULT_SORT_ORDER);
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        if (!TextUtils.isEmpty(mInputText.getText().toString().trim())) {
            ContentValues cv = new ContentValues(1);
            cv.put(Info.MESSAGE_CONTENT,mInputText.getText().toString().trim());
            getContentResolver().insert(Info.CONTENT_URI,cv);
            mInputText.getText().clear();
        } else {
            Toast.makeText(this,getString(R.string.toast_info),Toast.LENGTH_LONG).show();
        }
    }

    @Override
    public void onItemClick(AdapterView<?> parent,View view,int position,long id) {
        // TODO Auto-generated method stub
        if (position == parent.getCount() - 1) {
            getContentResolver().delete(Info.DELETE_ALL_URI,null);
            mAutoCompleteView.getText().clear();
            mData.clear();
            Toast.makeText(this,"所有记录都清除啦",Toast.LENGTH_LONG).show();
        }
    }

    private class QueryHandler extends AsyncQueryHandler {

        public QueryHandler(ContentResolver cr) {
            super(cr);
            // TODO Auto-generated constructor stub
        }

        @Override
        protected void onQueryComplete(int token,Object cookie,Cursor cursor) {
            if (QUERY_AUTO_TOKEN == token) {
                if (cursor == null) {
                    return;
                }
                mData.clear();
                while (cursor.moveToNext()) {
                    mData.add(cursor.getString(cursor
                            .getColumnIndexOrThrow(Info.MESSAGE_CONTENT)));
                }
                mAutoAdaper.notifyDataSetChanged();
            }
        }
    }
    
    private class DbChangeResolver extends ContentObserver {
        private Handler mHandler;

        public DbChangeResolver(Handler handler) {
            super(handler);
            // TODO Auto-generated constructor stub
            mHandler = handler;
        }

        @Override
        public void onChange(boolean selfChange) {
            // TODO Auto-generated method stub
            super.onChange(selfChange);
            mHandler.removeCallbacks(mDataChangeRunnable);
            mHandler.postDelayed(mDataChangeRunnable,300);
        }
    }
    
    private Runnable mDataChangeRunnable = new Runnable() {
        @Override
        public void run() {
            // TODO Auto-generated method stub
            startQuery();
        }
    };
}

过多的就不解释了。

源码下载地址:http://download.csdn.net/detail/zhouyuanjing/5187264

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读