昨天我问了this我在哪里通过内容提供商向sqlite提供静态数据的问题。现在我想更进一步。我从网络服务器(使用Volley)下载一些数据并将它们再次存储在SQLite中。接下来我想用CursorLoader读取它们。但是我只能在Gridview中显示图像的标题。所以让我从我的代码开始。
MainActivityFragment
public class MainActivityFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>{
static public ArrayList<MyCity> cityList;
private static final String LOG_TAG = MainActivityFragment.class.getSimpleName();
private MyCityAdpapter myCityAdpapter;
private static final int CURSOR_LOADER_ID = 0;
private GridView mGridView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public MainActivityFragment() {
// Required empty public constructor
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
Cursor c =
getActivity().getContentResolver().query(MyCityContract.MyCityEntry.CONTENT_URI,
new String[]{MyCityContract.MyCityEntry._ID},
null,
null,
null);
if (c.getCount() == 0){
updateImagesList();
}
// initialize loader
getLoaderManager().initLoader(CURSOR_LOADER_ID, null, this);
super.onActivityCreated(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
// inflate fragment_main layout
final View rootView = inflater.inflate(R.layout.fragment_main_activity, container, false);
cityList = new ArrayList<>();
// initialize our FlavorAdapter
myCityAdpapter = new MyCityAdpapter(getActivity(), null, 0, CURSOR_LOADER_ID);
// initialize mGridView to the GridView in fragment_main.xml
mGridView = (GridView) rootView.findViewById(R.id.flavors_grid);
// set mGridView adapter to our CursorAdapter
mGridView.setAdapter(myCityAdpapter);
return rootView;
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args){
return new CursorLoader(getActivity(),
MyCityContract.MyCityEntry.CONTENT_URI,
null,
null,
null,
null);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
myCityAdpapter.swapCursor(data);
}
public void updateImagesList() {
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(getActivity());
// Request a string response from the provided URL.
JsonArrayRequest jsObjRequest = new JsonArrayRequest(Request.Method.GET, API.API_URL, new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
cityList.clear();
Log.d(TAG, response.toString());
//hidePD();
// Parse json data.
// Declare the json objects that we need and then for loop through the children array.
// Do the json parse in a try catch block to catch the exceptions
try {
for (int i = 0; i < response.length(); i++) {
//insert images information into the database
JSONObject post = response.getJSONObject(i);
MyCity item = new MyCity();
item.setName(post.getString("title"));
item.setImage(API.IMAGE_URL + post.getString("image"));
ContentValues imageValues = new ContentValues();
imageValues.put(MyCityContract.MyCityEntry._ID, post.getString("id"));
imageValues.put(MyCityContract.MyCityEntry.COLUMN_NAME, post.getString("title"));
imageValues.put(MyCityContract.MyCityEntry.COLUMN_ICON, post.getString("image"));
getActivity().getContentResolver().insert(MyCityContract.MyCityEntry.CONTENT_URI, imageValues);
cityList.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
// Update list by notifying the adapter of changes
myCityAdpapter.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
//hidePD();
}
});
queue.add(jsObjRequest);
}
@Override
public void onLoaderReset(Loader<Cursor> loader){
myCityAdpapter.swapCursor(null);
}
}
MyCityAdapter
public class MyCityAdpapter extends CursorAdapter {
private static final String LOG_TAG = MyCityAdpapter.class.getSimpleName();
private Context mContext;
private static int sLoaderID;
public MyCityAdpapter(Context context, Cursor c, int flags,int loaderID) {
super(context, c, flags);
Log.d(LOG_TAG, "MyCityAdpapter");
mContext = context;
sLoaderID = loaderID;
}
public static class ViewHolder {
public final ImageView imageView;
public final TextView textView;
public ViewHolder(View view){
imageView = (ImageView) view.findViewById(R.id.flavor_image);
textView = (TextView) view.findViewById(R.id.flavor_text);
}
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
int layoutId = R.layout.flavor_item;
Log.d(LOG_TAG, "In new View");
View view = LayoutInflater.from(context).inflate(layoutId, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
return view;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
Log.d(LOG_TAG, "In bind View");
int versionIndex = cursor.getColumnIndex(MyCityContract.MyCityEntry.COLUMN_NAME);
final String versionName = cursor.getString(versionIndex);
Log.i(LOG_TAG, "Text reference extracted: " + versionName);
viewHolder.textView.setText(versionName);
int imageIndex = cursor.getColumnIndex(MyCityContract.MyCityEntry.COLUMN_ICON);
int image = cursor.getInt(imageIndex);
Log.i(LOG_TAG, "Image reference extracted: " + image);
viewHolder.imageView.setImageResource(image);
}
}
请记住,这个类的logcat给了我
I/MyCityAdpapter: Text reference extracted: Ancient Theatre - Larissa
I/MyCityAdpapter: Image reference extracted: 0
I/MyCityAdpapter: Text reference extracted: Old trains
I/MyCityAdpapter: Image reference extracted: 0
等等。
MyCityContract
public class MyCityContract {
public static final String CONTENT_AUTHORITY = "theo.testing.customloaders.app";
public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
public static final class MyCityEntry implements BaseColumns{
//table name
public static final String TABLE_MY_CITY = "my_city";
//columns
public static final String _ID = "_id";
public static final String COLUMN_NAME = "name";
public static final String COLUMN_ICON = "icon";
// create content uri
public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon()
.appendPath(TABLE_MY_CITY).build();
// create cursor of base type directory for multiple entries
public static final String CONTENT_DIR_TYPE =
ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + TABLE_MY_CITY;
// create cursor of base type item for single entry
public static final String CONTENT_ITEM_TYPE =
ContentResolver.CURSOR_ITEM_BASE_TYPE +"/" + CONTENT_AUTHORITY + "/" + TABLE_MY_CITY;
// for building URIs on insertion
public static Uri buildFlavorsUri(long id){
return ContentUris.withAppendedId(CONTENT_URI, id);
}
}
}
我的 MyCityDbHelperClass 可能存在错误,我存储了所有数据。
public class MyCityDbHelper extends SQLiteOpenHelper{
public static final String LOG_TAG = MyCityDbHelper.class.getSimpleName();
//name & version
public static final String DATABASE_NAME = "city.db";
public static final int DATABASE_VERSION = 7;
// Create the database
public MyCityDbHelper(Context context) {
super(context, DATABASE_NAME,null,DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
final String SQL_CREATE_MY_CITY_TABLE = "CREATE TABLE " +
MyCityContract.MyCityEntry.TABLE_MY_CITY + "(" + MyCityContract.MyCityEntry._ID +
" INTEGER PRIMARY KEY AUTOINCREMENT, " +
MyCityContract.MyCityEntry.COLUMN_NAME + " TEXT NOT NULL, " +
MyCityContract.MyCityEntry.COLUMN_ICON + " INTEGER NOT NULL);";
sqLiteDatabase.execSQL(SQL_CREATE_MY_CITY_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
Log.w(LOG_TAG, "Upgrading database from version " + oldVersion + " to " +
newVersion + ". OLD DATA WILL BE DESTROYED");
// Drop the table
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + MyCityContract.MyCityEntry.TABLE_MY_CITY);
sqLiteDatabase.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" +
MyCityContract.MyCityEntry.TABLE_MY_CITY + "'");
// re-create database
onCreate(sqLiteDatabase);
}
}
最后我有我的提供者。
public class MyCityProvider extends ContentProvider {
private static final String LOG_TAG = MyCityProvider.class.getSimpleName();
private static final UriMatcher sUriMatcher = buildUriMatcher();
private MyCityDbHelper myCityDbHelper;
//Codes for UriMatcher
private static final int MY_CITY = 100;
private static final int MY_CITY_WITH_ID = 200;
private static UriMatcher buildUriMatcher(){
// Build a UriMatcher by adding a specific code to return based on a match
// It's common to use NO_MATCH as the code for this case.
final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
final String authority = MyCityContract.CONTENT_AUTHORITY;
//add code for each URI
matcher.addURI(authority,MyCityContract.MyCityEntry.TABLE_MY_CITY,MY_CITY);
matcher.addURI(authority,MyCityContract.MyCityEntry.TABLE_MY_CITY + "/#",MY_CITY_WITH_ID);
return matcher;
}
@Override
public boolean onCreate() {
myCityDbHelper = new MyCityDbHelper(getContext());
return true;
}
@Override
public String getType(Uri uri) {
final int match = sUriMatcher.match(uri);
switch (match){
case MY_CITY: {
return MyCityContract.MyCityEntry.CONTENT_DIR_TYPE;
}
case MY_CITY_WITH_ID:{
return MyCityContract.MyCityEntry.CONTENT_ITEM_TYPE;
}
default:{
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder){
Cursor retCursor;
switch(sUriMatcher.match(uri)){
// All Flavors selected
case MY_CITY:{
retCursor = myCityDbHelper.getReadableDatabase().query(
MyCityContract.MyCityEntry.TABLE_MY_CITY,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
return retCursor;
}
// Individual flavor based on Id selected
case MY_CITY_WITH_ID:{
retCursor = myCityDbHelper.getReadableDatabase().query(
MyCityContract.MyCityEntry.TABLE_MY_CITY,
projection,
MyCityContract.MyCityEntry._ID + " = ?",
new String[] {String.valueOf(ContentUris.parseId(uri))},
null,
null,
sortOrder);
return retCursor;
}
default:{
// By default, we assume a bad URI
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
}
@Override
public Uri insert(Uri uri, ContentValues contentValues) {
final SQLiteDatabase db = myCityDbHelper.getWritableDatabase();
Uri returnUri;
switch (sUriMatcher.match(uri)){
case MY_CITY:
long _id = db.insertWithOnConflict(MyCityContract.MyCityEntry.TABLE_MY_CITY,null,contentValues,SQLiteDatabase.CONFLICT_REPLACE);
Log.d("id",String.valueOf(_id));
// insert unless it is already contained in the database
if(_id>0){
returnUri = MyCityContract.MyCityEntry.buildFlavorsUri(_id);
}else {
throw new android.database.SQLException("Failed to insert row into: " + uri);
}
break;
default: {
throw new UnsupportedOperationException("Unknown uri: " + uri );
}
}
getContext().getContentResolver().notifyChange(uri,null);
return returnUri;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
final SQLiteDatabase db = myCityDbHelper.getWritableDatabase();
final int match = sUriMatcher.match(uri);
int numDeleted;
switch(match){
case MY_CITY:
numDeleted = db.delete(
MyCityContract.MyCityEntry.TABLE_MY_CITY, selection, selectionArgs);
// reset _ID
db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" +
MyCityContract.MyCityEntry.TABLE_MY_CITY + "'");
break;
case MY_CITY_WITH_ID:
numDeleted = db.delete(MyCityContract.MyCityEntry.TABLE_MY_CITY,
MyCityContract.MyCityEntry._ID + " = ?",
new String[]{String.valueOf(ContentUris.parseId(uri))});
// reset _ID
db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" +
MyCityContract.MyCityEntry.TABLE_MY_CITY + "'");
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
return numDeleted;
}
@Override
public int update(Uri uri, ContentValues contentValues, String selection, String[] selectionArgs){
final SQLiteDatabase db = myCityDbHelper.getWritableDatabase();
int numUpdated = 0;
if (contentValues == null){
throw new IllegalArgumentException("Cannot have null content values");
}
switch(sUriMatcher.match(uri)){
case MY_CITY:{
numUpdated = db.update(MyCityContract.MyCityEntry.TABLE_MY_CITY,
contentValues,
selection,
selectionArgs);
break;
}
case MY_CITY_WITH_ID: {
numUpdated = db.update(MyCityContract.MyCityEntry.TABLE_MY_CITY,
contentValues,
MyCityContract.MyCityEntry._ID + " = ?",
new String[] {String.valueOf(ContentUris.parseId(uri))});
break;
}
default:{
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
if (numUpdated > 0){
getContext().getContentResolver().notifyChange(uri, null);
}
return numUpdated;
}
}
为什么图像不在那里?我一直想解决存储动态数据的问题,并在离线模式下读取它们:)。
谢谢,
西奥。
答案 0 :(得分:1)
您正在将数据库存储在数据库中,但是您正在MyCityAdapter
中读取整数。您需要在bindView()
方法中再次获取图片网址。获得图像的网址后,您将不得不下载并存储图像。但是没有必要自己写出来。我推荐Picasso库。将此库添加到您的dependecies后,您可以将图像设置为imageView,如下所示:Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
所以,你的bindView()
方法体将是这样的:
@Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
Log.d(LOG_TAG, "In bind View");
int versionIndex = cursor.getColumnIndex(MyCityContract.MyCityEntry.COLUMN_NAME);
final String versionName = cursor.getString(versionIndex);
Log.i(LOG_TAG, "Text reference extracted: " + versionName);
viewHolder.textView.setText(versionName);
int imageIndex = cursor.getColumnIndex(MyCityContract.MyCityEntry.COLUMN_ICON);
String imageUrl = cursor.getString(imageIndex);
Log.i(LOG_TAG, "Image reference extracted: " + image);
Picasso.with(context).load(imageUrl).into(viewHolder.imageView);
}