[android] Async search via loader.
This commit is contained in:
parent
4654442ef2
commit
7c15605c1f
4 changed files with 194 additions and 32 deletions
|
@ -3,21 +3,44 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
|
||||
<EditText
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="0"
|
||||
android:hint="Enter Search Term"
|
||||
/>
|
||||
|
||||
|
||||
<include
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="1"
|
||||
layout="@android:layout/list_content"/>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/searchBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/searchIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="0"
|
||||
android:src="@android:drawable/ic_menu_search" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/searchText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:hint="Enter Search Term"
|
||||
android:inputType="textCapWords"
|
||||
android:singleLine="true"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/clearSearch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="0"
|
||||
android:src="@android:drawable/ic_delete"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
layout="@android:layout/list_content" />
|
||||
|
||||
</LinearLayout>
|
|
@ -1,23 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="100dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
style="@android:style/TextAppearance.Medium"
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:text="Hello World!" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/thumbnail"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_weight="0"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@drawable/ic_launcher" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
style="@android:style/TextAppearance.Medium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:text="Hello World!"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
|
@ -3,16 +3,26 @@ package com.example.travelguide;
|
|||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v4.text.TextUtilsCompat;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.example.travelguide.async.QueryResultLoader;
|
||||
import com.example.travelguide.cpp.Storage;
|
||||
import com.example.travelguide.dummy.DummyContent;
|
||||
import com.example.travelguide.widget.StorageArticleInfoAdapter;
|
||||
|
||||
import static com.example.travelguide.util.Utils.*;
|
||||
|
||||
/**
|
||||
* A list fragment representing a list of ArticleInfos. This fragment also
|
||||
* supports tablet devices by allowing list items to be given an 'activated'
|
||||
|
@ -22,9 +32,14 @@ import com.example.travelguide.widget.StorageArticleInfoAdapter;
|
|||
* Activities containing this fragment MUST implement the {@link Callbacks}
|
||||
* interface.
|
||||
*/
|
||||
public class ArticleInfoListFragment extends ListFragment
|
||||
public class ArticleInfoListFragment extends ListFragment implements LoaderCallbacks<Storage>, TextWatcher,
|
||||
OnClickListener
|
||||
{
|
||||
private View mRootView;
|
||||
private TextView mSearchText;
|
||||
private View mCross;
|
||||
private View mSearchIcon;
|
||||
|
||||
private Storage mStorage;
|
||||
|
||||
/**
|
||||
|
@ -80,9 +95,6 @@ public class ArticleInfoListFragment extends ListFragment
|
|||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
mStorage = new Storage();
|
||||
// TODO: remove it
|
||||
mStorage.query("", false, 0, 0);
|
||||
setListAdapter(new StorageArticleInfoAdapter(mStorage, getActivity()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,6 +121,11 @@ public class ArticleInfoListFragment extends ListFragment
|
|||
}
|
||||
|
||||
mCallbacks = (Callbacks) activity;
|
||||
|
||||
// Load initial data
|
||||
final Bundle args = new Bundle(1);
|
||||
args.putString(KEY_QUERY, "");
|
||||
getLoaderManager().initLoader(SEARCH_LOADER, args, this).forceLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -118,6 +135,8 @@ public class ArticleInfoListFragment extends ListFragment
|
|||
|
||||
// Reset the active callbacks interface to the dummy implementation.
|
||||
mCallbacks = sDummyCallbacks;
|
||||
|
||||
getLoaderManager().destroyLoader(SEARCH_LOADER);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -165,11 +184,89 @@ public class ArticleInfoListFragment extends ListFragment
|
|||
|
||||
mActivatedPosition = position;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
mRootView = inflater.inflate(R.layout.fragment_articleinfo_list, null, false);
|
||||
mSearchText = (TextView) mRootView.findViewById(R.id.searchText);
|
||||
mSearchIcon = mRootView.findViewById(R.id.searchIcon);
|
||||
mCross = mRootView.findViewById(R.id.clearSearch);
|
||||
|
||||
// setup listeners
|
||||
mSearchText.addTextChangedListener(this);
|
||||
mCross.setOnClickListener(this);
|
||||
|
||||
return mRootView;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* LOADER
|
||||
*
|
||||
*/
|
||||
|
||||
private static int SEARCH_LOADER = 0x1;
|
||||
private String KEY_QUERY = "key_query";
|
||||
|
||||
@Override
|
||||
public Loader<Storage> onCreateLoader(int id, Bundle args)
|
||||
{
|
||||
if (id == SEARCH_LOADER)
|
||||
{
|
||||
final String query = args.getString(KEY_QUERY);
|
||||
// TODO: add location check
|
||||
// TODO: add progress
|
||||
return new QueryResultLoader(getActivity(), query);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Storage> loader, Storage result)
|
||||
{
|
||||
setListAdapter(new StorageArticleInfoAdapter(result, getActivity()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Storage> loader)
|
||||
{}
|
||||
|
||||
/**
|
||||
*
|
||||
* TEXT WATCHER
|
||||
*
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count)
|
||||
{
|
||||
final Bundle args = new Bundle(1);
|
||||
args.putString(KEY_QUERY, s.toString());
|
||||
getLoaderManager().restartLoader(SEARCH_LOADER, args, this).forceLoad();
|
||||
|
||||
hideIf(TextUtils.isEmpty(s), mCross);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s)
|
||||
{}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after)
|
||||
{}
|
||||
|
||||
/**
|
||||
*
|
||||
* CLICK
|
||||
*
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
if (v.getId() == mCross.getId())
|
||||
mSearchText.setText(""); // clean up text field
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package com.example.travelguide.async;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
|
||||
import com.example.travelguide.cpp.Storage;
|
||||
|
||||
public class QueryResultLoader extends AsyncTaskLoader<Storage>
|
||||
{
|
||||
private final String mQuery;
|
||||
private final double mLat;
|
||||
private final double mLon;
|
||||
private final boolean mUseLocation;
|
||||
|
||||
public QueryResultLoader(Context context, String query)
|
||||
{
|
||||
super(context);
|
||||
mQuery = query;
|
||||
mUseLocation = false;
|
||||
mLat = mLon = 0;
|
||||
}
|
||||
|
||||
public QueryResultLoader(Context context, String query, double lat, double lon)
|
||||
{
|
||||
super(context);
|
||||
mQuery = query;
|
||||
mUseLocation = true;
|
||||
mLat = lat;
|
||||
mLon = lon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Storage loadInBackground()
|
||||
{
|
||||
final Storage storage = new Storage();
|
||||
storage.query(mQuery, mUseLocation, mLat, mLon);
|
||||
return storage;
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue