Refactored SearchView into Activity + ListFragment (Fixes #11)
This allowed for the use of LoaderCallbacks which seem like a better way at managing the lifecycle of the cursors which our ContentProviders return.
This commit is contained in:
parent
3345a81077
commit
d287dca854
@ -18,56 +18,22 @@
|
|||||||
|
|
||||||
package org.fdroid.fdroid;
|
package org.fdroid.fdroid;
|
||||||
|
|
||||||
import android.app.ListActivity;
|
|
||||||
import android.app.SearchManager;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.support.v4.app.FragmentActivity;
|
||||||
import android.view.Menu;
|
import android.support.v4.app.FragmentManager;
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.ListView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import android.support.v4.app.NavUtils;
|
import android.support.v4.app.NavUtils;
|
||||||
import android.support.v4.view.MenuItemCompat;
|
import android.support.v4.view.MenuItemCompat;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
import org.fdroid.fdroid.compat.ActionBarCompat;
|
import org.fdroid.fdroid.compat.ActionBarCompat;
|
||||||
import org.fdroid.fdroid.data.App;
|
import org.fdroid.fdroid.views.fragments.SearchResultsFragment;
|
||||||
import org.fdroid.fdroid.data.AppProvider;
|
|
||||||
import org.fdroid.fdroid.views.AppListAdapter;
|
|
||||||
import org.fdroid.fdroid.views.AvailableAppListAdapter;
|
|
||||||
import org.fdroid.fdroid.views.fragments.AppListFragment;
|
|
||||||
|
|
||||||
public class SearchResults extends ListActivity {
|
public class SearchResults extends FragmentActivity {
|
||||||
|
|
||||||
private static final int REQUEST_APPDETAILS = 0;
|
|
||||||
|
|
||||||
private static final int SEARCH = Menu.FIRST;
|
private static final int SEARCH = Menu.FIRST;
|
||||||
|
|
||||||
private Cursor cursor;
|
|
||||||
private AppListAdapter adapter;
|
|
||||||
|
|
||||||
protected String getQuery() {
|
|
||||||
Intent intent = getIntent();
|
|
||||||
String query;
|
|
||||||
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
|
||||||
query = intent.getStringExtra(SearchManager.QUERY);
|
|
||||||
} else {
|
|
||||||
Uri data = intent.getData();
|
|
||||||
if (data != null && data.isHierarchical()) {
|
|
||||||
query = data.getQueryParameter("q");
|
|
||||||
if (query != null && query.startsWith("pname:"))
|
|
||||||
query = query.substring(6);
|
|
||||||
} else {
|
|
||||||
query = data.getEncodedSchemeSpecificPart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return query;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
|
||||||
@ -75,21 +41,28 @@ public class SearchResults extends ListActivity {
|
|||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
setContentView(R.layout.searchresults);
|
// Start a search by just typing
|
||||||
|
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
|
||||||
|
|
||||||
|
FragmentManager fm = getSupportFragmentManager();
|
||||||
|
if (fm.findFragmentById(android.R.id.content) == null) {
|
||||||
|
|
||||||
|
// Need to set a dummy view (which will get overridden by the fragment manager
|
||||||
|
// below) so that we can call setContentView(). This is a work around for
|
||||||
|
// a (bug?) thing in 3.0, 3.1 which requires setContentView to be invoked before
|
||||||
|
// the actionbar is played with:
|
||||||
|
// http://blog.perpetumdesign.com/2011/08/strange-case-of-dr-action-and-mr-bar.html
|
||||||
|
setContentView( new LinearLayout(this) );
|
||||||
|
|
||||||
|
SearchResultsFragment fragment = new SearchResultsFragment();
|
||||||
|
fm.beginTransaction().add(android.R.id.content, fragment).commit();
|
||||||
|
}
|
||||||
|
|
||||||
// Actionbar cannot be accessed until after setContentView (on 3.0 and 3.1 devices)
|
// Actionbar cannot be accessed until after setContentView (on 3.0 and 3.1 devices)
|
||||||
// see: http://blog.perpetumdesign.com/2011/08/strange-case-of-dr-action-and-mr-bar.html
|
// see: http://blog.perpetumdesign.com/2011/08/strange-case-of-dr-action-and-mr-bar.html
|
||||||
// for reason why.
|
// for reason why.
|
||||||
ActionBarCompat.create(this).setDisplayHomeAsUpEnabled(true);
|
ActionBarCompat.create(this).setDisplayHomeAsUpEnabled(true);
|
||||||
|
|
||||||
// Start a search by just typing
|
|
||||||
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
updateView();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -98,51 +71,6 @@ public class SearchResults extends ListActivity {
|
|||||||
setIntent(intent);
|
setIntent(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateView() {
|
|
||||||
|
|
||||||
String query = getQuery();
|
|
||||||
|
|
||||||
if (query != null)
|
|
||||||
query = query.trim();
|
|
||||||
|
|
||||||
if (query == null || query.length() == 0)
|
|
||||||
finish();
|
|
||||||
|
|
||||||
if (cursor != null) cursor.close();
|
|
||||||
cursor = managedQuery(
|
|
||||||
AppProvider.getSearchUri(query), AppListFragment.APP_PROJECTION,
|
|
||||||
null, null, AppListFragment.APP_SORT);
|
|
||||||
|
|
||||||
|
|
||||||
TextView tv = (TextView) findViewById(R.id.description);
|
|
||||||
String headertext;
|
|
||||||
int count = cursor != null ? cursor.getCount() : 0;
|
|
||||||
if (count == 0) {
|
|
||||||
headertext = getString(R.string.searchres_noapps, query);
|
|
||||||
} else if (count == 1) {
|
|
||||||
headertext = getString(R.string.searchres_oneapp, query);
|
|
||||||
} else {
|
|
||||||
headertext = getString(R.string.searchres_napps, count, query);
|
|
||||||
}
|
|
||||||
tv.setText(headertext);
|
|
||||||
Log.d("FDroid", "Search for '" + query + "' returned " + count + " results");
|
|
||||||
|
|
||||||
adapter = new AvailableAppListAdapter(this, cursor);
|
|
||||||
getListView().setFastScrollEnabled(true);
|
|
||||||
setListAdapter(adapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onListItemClick(ListView l, View v, int position, long id) {
|
|
||||||
final App app;
|
|
||||||
app = new App((Cursor) adapter.getItem(position));
|
|
||||||
|
|
||||||
Intent intent = new Intent(this, AppDetails.class);
|
|
||||||
intent.putExtra(AppDetails.EXTRA_APPID, app.id);
|
|
||||||
startActivityForResult(intent, REQUEST_APPDETAILS);
|
|
||||||
super.onListItemClick(l, v, position, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
|
||||||
|
133
src/org/fdroid/fdroid/views/fragments/SearchResultsFragment.java
Normal file
133
src/org/fdroid/fdroid/views/fragments/SearchResultsFragment.java
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
package org.fdroid.fdroid.views.fragments;
|
||||||
|
|
||||||
|
import android.app.SearchManager;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.ListFragment;
|
||||||
|
import android.support.v4.app.LoaderManager;
|
||||||
|
import android.support.v4.content.CursorLoader;
|
||||||
|
import android.support.v4.content.Loader;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import org.fdroid.fdroid.AppDetails;
|
||||||
|
import org.fdroid.fdroid.R;
|
||||||
|
import org.fdroid.fdroid.data.App;
|
||||||
|
import org.fdroid.fdroid.data.AppProvider;
|
||||||
|
import org.fdroid.fdroid.views.AppListAdapter;
|
||||||
|
import org.fdroid.fdroid.views.AvailableAppListAdapter;
|
||||||
|
|
||||||
|
public class SearchResultsFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> {
|
||||||
|
|
||||||
|
private static final String TAG = "org.fdroid.fdroid.views.fragments.SearchResultsFragment";
|
||||||
|
|
||||||
|
private static final int REQUEST_APPDETAILS = 0;
|
||||||
|
|
||||||
|
private AppListAdapter adapter;
|
||||||
|
|
||||||
|
protected String getQuery() {
|
||||||
|
Intent intent = getActivity().getIntent();
|
||||||
|
String query = null;
|
||||||
|
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
||||||
|
query = intent.getStringExtra(SearchManager.QUERY);
|
||||||
|
} else {
|
||||||
|
Uri data = intent.getData();
|
||||||
|
if (data != null && data.isHierarchical()) {
|
||||||
|
query = data.getQueryParameter("q");
|
||||||
|
if (query != null && query.startsWith("pname:"))
|
||||||
|
query = query.substring(6);
|
||||||
|
} else if (data!= null ) {
|
||||||
|
query = data.getEncodedSchemeSpecificPart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return query == null ? "" : query;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
//Starts a new or restarts an existing Loader in this manager
|
||||||
|
getLoaderManager().restartLoader(0, null, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup root, Bundle data) {
|
||||||
|
|
||||||
|
adapter = new AvailableAppListAdapter(getActivity(), null);
|
||||||
|
setListAdapter(adapter);
|
||||||
|
|
||||||
|
View view = inflater.inflate(R.layout.searchresults, null);
|
||||||
|
updateSummary(view);
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||||
|
Uri uri = AppProvider.getSearchUri(getQuery());
|
||||||
|
return new CursorLoader(
|
||||||
|
getActivity(),
|
||||||
|
uri,
|
||||||
|
AppListFragment.APP_PROJECTION,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
AppListFragment.APP_SORT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSummary() {
|
||||||
|
updateSummary(getView());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSummary(View view) {
|
||||||
|
|
||||||
|
String query = getQuery();
|
||||||
|
|
||||||
|
if (query != null)
|
||||||
|
query = query.trim();
|
||||||
|
|
||||||
|
if (query == null || query.length() == 0)
|
||||||
|
getActivity().finish();
|
||||||
|
|
||||||
|
TextView tv = (TextView) view.findViewById(R.id.description);
|
||||||
|
String headerText;
|
||||||
|
int count = adapter.getCount();
|
||||||
|
if (count == 0) {
|
||||||
|
headerText = getString(R.string.searchres_noapps, query);
|
||||||
|
} else if (count == 1) {
|
||||||
|
headerText = getString(R.string.searchres_oneapp, query);
|
||||||
|
} else {
|
||||||
|
headerText = getString(R.string.searchres_napps, count, query);
|
||||||
|
}
|
||||||
|
tv.setText(headerText);
|
||||||
|
Log.d(TAG, "Search for '" + query + "' returned " + count + " results");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onListItemClick(ListView l, View v, int position, long id) {
|
||||||
|
final App app;
|
||||||
|
app = new App((Cursor) adapter.getItem(position));
|
||||||
|
|
||||||
|
Intent intent = new Intent(getActivity(), AppDetails.class);
|
||||||
|
intent.putExtra(AppDetails.EXTRA_APPID, app.id);
|
||||||
|
startActivityForResult(intent, REQUEST_APPDETAILS);
|
||||||
|
super.onListItemClick(l, v, position, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
||||||
|
adapter.swapCursor(data);
|
||||||
|
updateSummary();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoaderReset(Loader<Cursor> loader) {
|
||||||
|
adapter.swapCursor(null);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user