I have an activity
with a TabLayout
that's hooked up to a FragmentPagerAdapter
. Whenever the user changes tabs, another fragment is loaded, but the Activity
stays the same.
The activity
also contains a search function, i.e. autocomplete suggestions are fetched from a web server. I want to perform a different search action - basically, query another URL - depending on which fragment is currently loaded in the FragmentPager
/TabLayout
.
So far, I haven't found any way to do this. Here's what I have tried:
Here's a quick sketch of the situation: Sketch
Here are the relevant code fragments:
MainActivity.class
public class MainActivity extends AppCompatActivity {
private ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.viewpager);
mViewPager.setAdapter(new MainFragmentPagerAdapter(getSupportFragmentManager(),
MainActivity.this));
TabLayout tabs = (TabLayout) findViewById(R.id.sliding_tabs);
tabs.setupWithViewPager(mViewPager);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.action_search, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
searchView.setOnQueryTextListener(this);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
searchView.setSearchableInfo(searchManager.getSearchableInfo(new ComponentName(this, MainActivity.class)));
searchView.setIconifiedByDefault(false);
return true;
}
/* ... */
}
menu/action_search.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_search"
android:title="Search"
android:icon="@android:drawable/ic_menu_search"
app:showAsAction="always"
app:actionViewClass="android.support.v7.widget.SearchView" />
</menu>
xml/searchable.xml
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:hint="hint"
android:label="@string/app_name"
android:voiceSearchMode="showVoiceSearchButton|launchRecognizer"
android:searchSuggestAuthority="xyz.demo.search.datasuggestion"
android:searchSuggestIntentAction="android.intent.action.VIEW"
android:searchSuggestIntentData="content://xyz.demo.search.data"/>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="xyz.demo.app">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="android.app.default_searchable"
android:value=".MainActivity" />
<activity android:name=".MainActivity" android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.SEARCH" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
<provider
android:name=".SuggestionProvider"
android:authorities="xyz.demo.search.datasuggestion"
android:enabled="true"
android:exported="true"/>
</application>
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
SuggestionProvider.java
public class SuggestionProvider extends ContentProvider {
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(".../suggestions")
.build();
try {
Response response = client.newCall(request).execute();
String jsonString = response.body().string();
JSONArray jsonArray = new JSONArray(jsonString);
/* ... */
} catch (Exception e) {
e.printStackTrace();
}
/* ... eventually returns a MatrixCursor */
}
/* ... */
}
Ah okay I see this is one of those things where Android is calling your provider and you can't control how it's going to call it.
I don't see a way to do this cleanly either. The searchable is linked to the activity. You either base your screens on the activity not the fragment (changing your design), or do something terrible like set a preference when your fragment resumes so the content provider knows which fragment is "active".