与CursorLoader和简单的startManagingCursor冲突

时间:2014-10-25 08:54:07

标签: android sqlite android-cursorloader

我通过CursorLoader从db读取数据,但搜索方法使用startmanaging游标。该应用程序有一个错误 - 10-25 11:42:53.651:E / AndroidRuntime(1461):致命异常:主

有没有办法只使用CursorLoader读取数据库和搜索以及如何在我的代码中执行此操作?谢谢!

package com.example.citycode;

import java.util.concurrent.TimeUnit;

import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SearchView;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;

public class MainActivity extends ActionBarActivity implements LoaderCallbacks<Cursor> {

  ListView lvData;
  DBHelper db;
  SimpleCursorAdapter scAdapter;

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

    // Get the intent, verify the action and get the query
    Intent intent = getIntent();
    if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
      String query = intent.getStringExtra(SearchManager.QUERY);
      doMySearch(query);
    }

    // Открываем подключение к БД
    db = new DBHelper(this);
    db.open();

    // Формируем столбцы сопоставления
    String[] from = new String[] { DBHelper.COLUMN_r_name, DBHelper.COLUMN_region, DBHelper.COLUMN_code};
    int[] to = new int[] { R.id.city_name, R.id.region_name, R.id.city_code };

    // Создаем адаптер и настраиваем список
    scAdapter = new SimpleCursorAdapter(this, R.layout.item, null, from, to, 0);
    lvData = (ListView) findViewById(R.id.listdata);
    lvData.setAdapter(scAdapter);

    // Создаем лоадер для чтения данных
    getSupportLoaderManager().initLoader(0, null, this);


  }

  protected void onDestroy() {
    super.onDestroy();
    // Закрываем подключение к БД при выходе
    db.close();
  }

  public void doMySearch(String query) {
        db = new DBHelper(this);
        db.open();
        //Ищем совпадения
        Cursor cursor1 = db.fetchRecordsByQuery(query);
        startManagingCursor(cursor1);
        String[] from = new String[] { DBHelper.COLUMN_r_name, DBHelper.COLUMN_region, DBHelper.COLUMN_code};
        int[] to = new int[] { R.id.city_name, R.id.region_name, R.id.city_code };

        SimpleCursorAdapter records = new SimpleCursorAdapter(this,
                R.layout.item, cursor1, from, to);
        //Обновляем адаптер
        lvData.setAdapter(records);
      }

     @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.options_main, menu);

        // Get the SearchView and set the searchable configuration
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView = (SearchView) menu.findItem(R.id.action_settings).getActionView();
        // Assumes current activity is the searchable activity
        //searchView.setSubmitButtonEnabled(true);
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        searchView.setIconifiedByDefault(false); // Do not iconify the widget; expand it by default

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            //onSearchRequested();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

  @Override
  public Loader<Cursor> onCreateLoader(int id, Bundle bndl) {
    return new MyCursorLoader(this, db);
  }

  @Override
  public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    scAdapter.swapCursor(cursor);
  }

  @Override
  public void onLoaderReset(Loader<Cursor> loader) {
  }

  static class MyCursorLoader extends CursorLoader {

      DBHelper db;

    public MyCursorLoader(Context context, DBHelper db) {
      super(context);
      this.db = db;
    }

    @Override
    public Cursor loadInBackground() {
      Cursor cursor = db.getAllData();
      try {
        TimeUnit.SECONDS.sleep(2);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      return cursor;
    }

  }
}

这是日志:

10-25 13:09:58.351: D/AndroidRuntime(4639): Shutting down VM
10-25 13:09:58.351: W/dalvikvm(4639): threadid=1: thread exiting with uncaught exception (group=0x416d7ba8)
10-25 13:09:58.351: E/AndroidRuntime(4639): FATAL EXCEPTION: main
10-25 13:09:58.351: E/AndroidRuntime(4639): Process: com.example.citycode, PID: 4639
10-25 13:09:58.351: E/AndroidRuntime(4639): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.citycode/com.example.citycode.MainActivity}: java.lang.NullPointerException
10-25 13:09:58.351: E/AndroidRuntime(4639):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2184)
10-25 13:09:58.351: E/AndroidRuntime(4639):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)
10-25 13:09:58.351: E/AndroidRuntime(4639):     at android.app.ActivityThread.access$800(ActivityThread.java:135)
10-25 13:09:58.351: E/AndroidRuntime(4639):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
10-25 13:09:58.351: E/AndroidRuntime(4639):     at android.os.Handler.dispatchMessage(Handler.java:102)
10-25 13:09:58.351: E/AndroidRuntime(4639):     at android.os.Looper.loop(Looper.java:136)
10-25 13:09:58.351: E/AndroidRuntime(4639):     at android.app.ActivityThread.main(ActivityThread.java:5001)
10-25 13:09:58.351: E/AndroidRuntime(4639):     at java.lang.reflect.Method.invokeNative(Native Method)
10-25 13:09:58.351: E/AndroidRuntime(4639):     at java.lang.reflect.Method.invoke(Method.java:515)
10-25 13:09:58.351: E/AndroidRuntime(4639):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
10-25 13:09:58.351: E/AndroidRuntime(4639):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
10-25 13:09:58.351: E/AndroidRuntime(4639):     at dalvik.system.NativeStart.main(Native Method)
10-25 13:09:58.351: E/AndroidRuntime(4639): Caused by: java.lang.NullPointerException
10-25 13:09:58.351: E/AndroidRuntime(4639):     at com.example.citycode.MainActivity.doMySearch(MainActivity.java:75)
10-25 13:09:58.351: E/AndroidRuntime(4639):     at com.example.citycode.MainActivity.onCreate(MainActivity.java:35)
10-25 13:09:58.351: E/AndroidRuntime(4639):     at android.app.Activity.performCreate(Activity.java:5231)
10-25 13:09:58.351: E/AndroidRuntime(4639):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
10-25 13:09:58.351: E/AndroidRuntime(4639):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2148)
10-25 13:09:58.351: E/AndroidRuntime(4639):     ... 11 more
10-25 13:09:59.881: I/Process(4639): Sending signal. PID: 4639 SIG: 9

我使用db类中的两个查询来获取数据:

String sqlQuery = "SELECT * FROM city AS t1, region AS t2 WHERE t1.region_number = t2._id;";

// Получить все данные из БД
public Cursor getAllData() {
  return  myDataBase.rawQuery(sqlQuery, new String[] {});
}

  String sqlQuery1 = "SELECT * FROM city AS t1, region AS t2 ON t1.region_number = t2._id WHERE t1.name LIKE '%' || ? || '%';";

     //Поиск запросом LIKE
  public Cursor fetchRecordsByQuery(String query) {
      return  myDataBase.rawQuery(sqlQuery1, new String[] {query});
  }

1 个答案:

答案 0 :(得分:0)

如果要过滤ListView,通常会使用包含选择的Arguments Bundle调用restartloader。

或多或少的伪代码,因为我没有测试过它:

在onCreate中未经过滤,你调用:getSupportLoaderManager()。initLoader(0,null,this);

在search()中你会做这样的事情:

public void search(String searchName){
  Bundle args = new Bundle();
  args.put(KEY_SELECTION, searchName);
  getSupportLoaderManager().restartLoader(0, args, this);
}
你的onCreateLoader回调中的

从args读取searchName并将其提供给你的CursorLoader实现。在那里你必须提供一个查询可能性,它接受一个String并通过这个String过滤Cursor。如果您使用contentProvider,它就会更容易,因为您只需要提供选择和URI并准备就绪。

此处提供了一个很好的概述:Loaders

修改 不,你不需要同时使用两个加载器,假设你只显示一个带有未过滤数据(所有行)或过滤数据的列表(行请求查询字符串。 你可以使用一个Loader和一个&#34; WHERE你的列LIKE&#39; querystring&#39;&#34;或没有WHERE条款。

在没有直接提供内容的情况下使用数据库可以轻松采用的一个简单示例是:

public boolean onQueryTextChanged(String newText) {
// Called when the action bar search text has changed.  Update
// the search filter, and restart the loader to do a new query
// with this filter.
mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
getLoaderManager().restartLoader(0, null, this);
return true;
}

public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// NOTE: The Loader is instantiated with the user's query  

// Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed.
return new MyCursorLoader(getActivity(), dbHelper, mCurFilter);
}



static class MyCursorLoader extends CursorLoader {

  DBHelper db;
String mCurFilter;

public MyCursorLoader(Context context, DBHelper db, String filter) {
  super(context);
  this.db = db;
this.mCurFilter = filter;
}

@Override
public Cursor loadInBackground() {
  Cursor cursor = null;
 if (mCurFilter != null) {
   cursor = db.rawQuery("SELECT * FROM example_table WHERE name = ? , new String[]{mCurFiler});
} else {
     cursor = db.rawQuery("SELECT * FROM example_table);
}
  return cursor;
}

}