在我的Android开发中遇到了一个问题困扰我好几天,无法解决它。以下是背景信息:
我在我的一个Fragements中使用LoaderManager,它应该通过访问远程MSSQL数据库表(命名为'todolist')来初始化加载器并返回一个Cursor;
我已将LoaderManager的初始化代码放在snippets public void onCreate()或public View onCreateView()中。但两个都返回一个错误“java.lang.NullPointerException:尝试在*****。****的空对象引用上调用接口方法'int android.database.Cursor.getCount()'。** 。** **** ******* **** COM data.AllToDoListFragment.onLoadFinished(AllToDoListFragment.java:208)“;。。。
显然,我的代码中的Cursor数据尚未初始化;
所以我的问题可以归结为:
4.1。在onCreateLoader代码段中找到一种方法来访问我的MSSQL数据库表,以便它可以成功地返回一个游标或:
4.2。有人告诉我如何在asyncTask中执行此操作。
BTW,我知道如何使用AsyncTask从我的远程MSSQL数据库表中检索我的数据,它可以显示在我的RecycleView中。但是当我了解到Cursor是一个更好的解决方案的选项,所以我想知道如何做到这一点。 不幸的是,我找不到任何与互联网相关的有用提示。
以下是AllToDoListFragment.java的代码片段
public class AllToDoListFragment extends Fragment implements
LoaderManager.LoaderCallbacks<Cursor>,
NewToDoListAdapter.NewToDoListAdapterOnClickHandler{
/*
* The columns of data that we are interested in displaying within our MainActivity's list of
* weather data.
*/
public static final String[] MAIN_TODOLIST_PROJECTION = {
ToDoListContract.ToDoListEntry._ID,
ToDoListContract.ToDoListEntry.COLUMN_PROJECTNAME,
ToDoListContract.ToDoListEntry.COLUMN_RAISEDDATE,
ToDoListContract.ToDoListEntry.COLUMN_DEADLINE,
ToDoListContract.ToDoListEntry.COLUMN_RESP1NAME,
ToDoListContract.ToDoListEntry.COLUMN_ISSUE,
};
/*
* We store the indices of the values in the array of Strings above to more quickly be able to
* access the data from our query. If the order of the Strings above changes, these indices
* must be adjusted to match the order of the Strings.
*/
public static final int INDEX_TODOLIST_ID = 0;
public static final int INDEX_TODOLIST_PROJECTNAME = 1;
public static final int INDEX_TODOLIST_RAISEDDATE = 2;
public static final int INDEX_TODOLIST_DEADLINE = 3;
public static final int INDEX_TODOLIST_RESP1NAME = 4;
public static final int INDEX_TODOLIST_ISSUE = 5;
/*
* This ID will be used to identify the Loader responsible for loading our ToDoList. In
* some cases, one Activity can deal with many Loaders. However, in our case, there is only one.
* We will still use this ID to initialize the loader and create the loader for best practice.
* Please note that 45 was chosen arbitrarily. You can use whatever number you like, so long as
* it is unique and consistent.
*/
private static final int ID_TODOLIST_LOADER = 144;
private NewToDoListAdapter mNewToDoListAdapter;
private RecyclerView mRecyclerView;
private int mPosition = RecyclerView.NO_POSITION;
private ProgressBar mLoadingIndicator;
public void onCreate(Bundle savedInstanceState) {
/*
* Ensures a loader is initialized and active. If the loader doesn't already exist, one is
* created and (if the activity/fragment is currently started) starts the loader. Otherwise
* the last created loader is re-used.
*/
// TODO 4: got to check if the following Loader is working or not
getLoaderManager().initLoader(ID_TODOLIST_LOADER, null, this);
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.fragment_all_to_do_list, container, false);
/*
* Using findViewById, we get a reference to our RecyclerView from xml. This allows us to
* do things like set the adapter of the RecyclerView and toggle the visibility.
*/
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerview_newtdl);
/*
* The ProgressBar that will indicate to the user that we are loading data. It will be
* hidden when no data is loading.
*
* Please note: This so called "ProgressBar" isn't a bar by default. It is more of a
* circle. We didn't make the rules (or the names of Views), we just follow them.
*/
mLoadingIndicator = (ProgressBar) rootView.findViewById(R.id.pb_loading_indicator_newtdl);
/*
* A LinearLayoutManager is responsible for measuring and positioning item views within a
* RecyclerView into a linear list. This means that it can produce either a horizontal or
* vertical list depending on which parameter you pass in to the LinearLayoutManager
* constructor. In our case, we want a vertical list, so we pass in the constant from the
* LinearLayoutManager class for vertical lists, LinearLayoutManager.VERTICAL.
*
* There are other LayoutManagers available to display your data in uniform grids,
* staggered grids, and more! See the developer documentation for more details.
*
* The third parameter (shouldReverseLayout) should be true if you want to reverse your
* layout. Generally, this is only true with horizontal lists that need to support a
* right-to-left layout.
*/
LinearLayoutManager layoutManager =
new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
/* setLayoutManager associates the LayoutManager we created above with our RecyclerView */
mRecyclerView.setLayoutManager(layoutManager);
/*
* Use this setting to improve performance if you know that changes in content do not
* change the child layout size in the RecyclerView
*/
mRecyclerView.setHasFixedSize(true);
/*
* The NewToDoListAdapter is responsible for linking our weather data with the Views that
* will end up displaying our weather data.
*
* Although passing in "this" twice may seem strange, it is actually a sign of separation
* of concerns, which is best programming practice. The ForecastAdapter requires an
* Android Context (which all Activities are) as well as an onClickHandler. Since our
* MainActivity implements the ForecastAdapter ForecastOnClickHandler interface, "this"
* is also an instance of that type of handler.
*/
// TODO 3: got to check if the paras below are valid or not
mNewToDoListAdapter = new NewToDoListAdapter(getContext(), this);
/* Setting the adapter attaches it to the RecyclerView in our layout. */
mRecyclerView.setAdapter(mNewToDoListAdapter);
showLoading();
// TODO 5: SyncUtils might not be needed here
// becuase asynctask is used
//SunshineSyncUtils.initialize(this);
return rootView;
}
/**
* Called by the {@link android.support.v4.app.LoaderManagerImpl} when a new Loader needs to be
* created. This Fragment only uses one loader, so we don't necessarily NEED to check the
* loaderId, but this is certainly best practice.
*
* @param loaderId The loader ID for which we need to create a loader
* @param bundle Any arguments supplied by the caller
* @return A new Loader instance that is ready to start loading.
*/
@Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle bundle) {
switch (loaderId) {
case ID_TODOLIST_LOADER:
/* URI for all rows of ToDoList data in our todolist table */
Uri todolistQueryUri = ToDoListContract.ToDoListEntry.CONTENT_URI;
/* Sort order: Ascending by date */
String sortOrder = ToDoListContract.ToDoListEntry.COLUMN_DEADLINE + " ASC";
/*
* A SELECTION in SQL declares which rows you'd like to return. In our case, we
* want all todolist data that is stored in our todolist table.
* We created a handy method to do that in our WeatherEntry class.
*/
String selection = ToDoListContract.ToDoListEntry.getSqlSelectDeadlineFromLastMonth();
return new CursorLoader(getActivity(),
todolistQueryUri,
MAIN_TODOLIST_PROJECTION,
selection,
null,
sortOrder);
default:
throw new RuntimeException("Loader Not Implemented: " + loaderId);
}
}
/**
* Called when a Loader has finished loading its data.
*
* NOTE: There is one small bug in this code. If no data is present in the cursor do to an
* initial load being performed with no access to internet, the loading indicator will show
* indefinitely, until data is present from the ContentProvider. This will be fixed in a
* future version of the course.
*
* @param loader The Loader that has finished.
* @param data The data generated by the Loader.
*/
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mNewToDoListAdapter.swapCursor(data);
if (mPosition == RecyclerView.NO_POSITION) mPosition = 0;
mRecyclerView.smoothScrollToPosition(mPosition);
if (data.getCount() != 0) showNewToDoListDataView();
}
/**
* Called when a previously created loader is being reset, and thus making its data unavailable.
* The application should at this point remove any references it has to the Loader's data.
*
* @param loader The Loader that is being reset.
*/
@Override
public void onLoaderReset(Loader<Cursor> loader) {
/*
* Since this Loader's data is now invalid, we need to clear the Adapter that is
* displaying the data.
*/
mNewToDoListAdapter.swapCursor(null);
}
/**
* This method is for responding to clicks from our list.
*
* @param id unique id number for the todolist item.
* @see ToDoListContract.ToDoListEntry#_ID
*/
@Override
public void onClick(long id) {
Intent tdlDetailIntent = new Intent(getActivity(), TDLDetailActivity.class);
Uri uriForIDClicked = ToDoListContract.ToDoListEntry.buildToDoListUriWithID(id);
tdlDetailIntent.setData(uriForIDClicked);
startActivity(tdlDetailIntent);
}
/**
* This method will make the View for the weather data visible and hide the error message and
* loading indicator.
* <p>
* Since it is okay to redundantly set the visibility of a View, we don't need to check whether
* each view is currently visible or invisible.
*/
private void showNewToDoListDataView() {
/* First, hide the loading indicator */
mLoadingIndicator.setVisibility(View.INVISIBLE);
/* Finally, make sure the weather data is visible */
mRecyclerView.setVisibility(View.VISIBLE);
}
/**
* This method will make the loading indicator visible and hide the todolist View and error
* message.
* <p>
* Since it is okay to redundantly set the visibility of a View, we don't need to check whether
* each view is currently visible or invisible.
*/
private void showLoading() {
/* Then, hide the weather data */
mRecyclerView.setVisibility(View.INVISIBLE);
/* Finally, show the loading indicator */
mLoadingIndicator.setVisibility(View.VISIBLE);
}
}
答案 0 :(得分:0)
我可以尝试下面的...我已经从联系人中检索了个人资料名称。
public class AllToDoListFragment extends Fragment implements android.support.v4.app.LoaderManager.LoaderCallbacks<Cursor> {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
// return super.onCreateView(inflater, container, savedInstanceState);
View rootView = inflater.inflate(R.layout.fragment_1, container, false);
getLoaderManager().initLoader(0, null, this);
return rootView;
}
@Override
public android.support.v4.content.Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new android.support.v4.content.CursorLoader(getActivity(),
// Retrieve data rows for the device user's 'profile' contact.
Uri.withAppendedPath( ContactsContract.Profile.CONTENT_URI,ContactsContract.Contacts.Data.CONTENT_DIRECTORY),
ProfileQuery.PROJECTION,
//Don't select anything here null will return all available fields
null,
null,
null);
}
@Override
public void onLoadFinished(android.support.v4.content.Loader<Cursor> loader, Cursor cursor) {
ArrayList<String> DataArray = new ArrayList<String>();
String name=null;
String photoUrl=null;
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
//here where you get your data and its type
String TypeName=cursor.getString(ProfileQuery.EMAIL);//this will give you field name
String Data=cursor.getString(ProfileQuery.FAMILY_NAME);//this will give you field data
String email = cursor.getString(ProfileQuery.EMAIL);;
String familyName = cursor.getString(ProfileQuery.FAMILY_NAME);
String url = cursor.getString(ProfileQuery.PHOTO);
if (TypeName !=null){
name = TypeName;
}
if(url !=null){
photoUrl =url;
}
cursor.moveToNext();
}
Log.e("*****name",name);
}
@Override
public void onLoaderReset(android.support.v4.content.Loader<Cursor> loader) {
}
private interface ProfileQuery {
String[] PROJECTION = {
ContactsContract.CommonDataKinds.Email.ADDRESS,
ContactsContract.CommonDataKinds.Email.IS_PRIMARY,
ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME,
ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.IS_PRIMARY,
ContactsContract.CommonDataKinds.Photo.PHOTO_URI,
ContactsContract.Contacts.Data.MIMETYPE
};
// int ADDRESS = 0;
// int NUMBER = 1;
/** Column index for the email address in the profile query results */
int EMAIL = 0;
/** Column index for the primary email address indicator in the profile query results */
int IS_PRIMARY_EMAIL = 1;
/** Column index for the family name in the profile query results */
int FAMILY_NAME = 2;
/** Column index for the given name in the profile query results */
int GIVEN_NAME = 3;
/** Column index for the phone number in the profile query results */
int PHONE_NUMBER = 4;
/** Column index for the primary phone number in the profile query results */
int IS_PRIMARY_PHONE_NUMBER = 5;
/** Column index for the photo in the profile query results */
int PHOTO = 6;
/** Column index for the MIME type in the profile query results */
int MIME_TYPE = 7;
}
答案 1 :(得分:0)
对于那些关心的人,我发布问题的方向可能有错误的方向。使用Webservice(如RESTFul)可能会更好。仍然深入研究细节,并在准备就绪后发布更准确的解决方案。