0

After searching a lot on the web, including stackoverflow, I still cannot resolve my problem : an activity cannot start because it does not find the required information for the intent.

Context

While searching for songs information in an xml file loaded in a list of Song objects, I am using the google suggestions engine and thus a ContentProvider class to deal with the logic.

Questions

1) Do I need to add mimeType information in the manifest and the ContentProvider ? When I try, the suggestion fail. 2) What do I need to put exactly in the URI variable given I do no use a database but a MatrixCursor instead ?

Code

1) Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="songs4heaven_p2.com.hfad.songs4heaven_p2">


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainSongs4Heaven_p2"
            android:launchMode="singleTop">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <!-- Points to searchable activity so the whole app can invoke search. -->
            <meta-data
                android:name="android.app.default_searchable"
                android:value=".SearchAndroidActivity" />

        </activity>

        <!-- Ancien système de recherche : Le Main appelle SearchActivity via l icone de recherche
            puis SearcActivity appelle SearchListActivity au clic dans SearchActivity -->

        <!-- Nouveau système de recherche par le mécanisme natif Android
            L'icône de recherche est dans la barre d icone en haut à droite
            et appelle une searchable activity décrite dans le AndroidManifest.xml -->
        <activity android:name=".SearchAndroidActivity"

            android:launchMode="singleTop" >
            <intent-filter tools:ignore="AppLinkUrlError">
                <action android:name="android.intent.action.SEARCH" />
                <action android:name="android.intent.action.VIEW" />
                <!--<data android:mimeType="vnd.android.cursor.item/vnd.songs4heaven.search.songs" />-->
            </intent-filter>


        <meta-data
                android:name="android.app.searchable"
                android:resource="@xml/searchable" />

        </activity>

        <!-- Points to searchable activity so the whole app can invoke search. -->
        <meta-data
            android:name="android.app.defaul_searchable"
            android:value="songs4heaven_p2.com.hfad.songs4heaven_p2.SearchAndroidActivity" />



        <provider
            android:name="songs4heaven_p2.com.hfad.songs4heaven_p2.SearchContentProvider"
            android:authorities="songs4heaven_p2.com.hfad.songs4heaven_p2.SearchContentProvider"
            android:multiprocess="true">
        </provider>
    </application>

</manifest>

2) ContenProvider

package songs4heaven_p2.com.hfad.songs4heaven_p2;


import android.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.util.Log;

import java.util.List;

public class SearchContentProvider extends ContentProvider{

    public List<Song> songs = null;


    public static final String BASE_DATA_NAME = "song";
    private static final String AUTHORITY = "songs4heaven_p2.com.hfad.songs4heaven_p2.SearchContentProvider";

    // Dans le manifeste :
    //      data android:mimeType="vnd.android.cursor.item/vnd.songs4heaven.search.songs"
    //public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/vnd.songs4heaven.search." + BASE_DATA_NAME;
    //public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/vnd.songs4heaven.search." + BASE_DATA_NAME;


    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_DATA_NAME);
    public static final Uri SEARCH_SUGGEST_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_DATA_NAME + "/" + SearchManager.SUGGEST_URI_PATH_QUERY);

    private static final int TYPE_ALL_SUGGESTIONS = 1;
    private static final int TYPE_SINGLE_SUGGESTION = 2;

    private UriMatcher mUriMatcher;
    public List<Song> mSongs = null;

    private static String[] matrixCursorColumns = {"_ID",
            SearchManager.SUGGEST_COLUMN_TEXT_1,
            SearchManager.SUGGEST_COLUMN_INTENT_DATA };

    @Override
    public boolean onCreate() {
        Log.i("DEBUG", "Entree SearchContentProvider / onCreate ");
        //Log.i("DEBUG", "onCreate / CONTENT_ITEM_TYPE:"+CONTENT_ITEM_TYPE);
        //Log.i("DEBUG", "onCreate / CONTENT_TYPE:"+CONTENT_TYPE);
        Log.i("DEBUG", "onCreate / CONTENT_ITEM_BASE_TYPE:"+ContentResolver.CURSOR_ITEM_BASE_TYPE);
        Log.i("DEBUG", "onCreate / CONTENT_DIR_BASE_TYPE:"+ContentResolver.CURSOR_DIR_BASE_TYPE);


        mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        //mUriMatcher.addURI(AUTHORITY, "/#", TYPE_SINGLE_SUGGESTION);
        mUriMatcher.addURI(AUTHORITY, "search_suggest_query/*", TYPE_ALL_SUGGESTIONS);
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                        String sortOrder) {

        //https://developer.android.com/guide/topics/providers/content-provider-creating#ContentProvider
        //For example, the MatrixCursor class implements a cursor in which each row is an array of Object. With this class, use addRow() to add a new row.

        Log.i("DEBUG", "Entree Cursor / uri:"+uri);
        String queryType = "";
        switch(mUriMatcher.match(uri)){
            case 1 :
                Log.i("DEBUG", "Cursor / case : 1");
                String query = uri.getLastPathSegment().toLowerCase();
                return getSearchResultsCursor(query);
            default:
                Log.i("DEBUG", "Cursor / case : null");
                return null;
        }
    }

    private MatrixCursor getSearchResultsCursor(String searchString){
        MatrixCursor searchResults =  new MatrixCursor(matrixCursorColumns);
        Object[] mRow = new Object[3];
        int counterId = 0;
        if(searchString != null){
            searchString = searchString.toLowerCase();

            //String v_titre = "";

            //for (int i = 0; i < songs.size(); i++) {
            //v_titre = songs.get( i )._title;
            //}

            mSongs = SingleLoadXml.getSongs( getContext());
            for (int i = 0; i < mSongs.size(); i++) {
                int id = mSongs.get( i )._ID;
                String title = mSongs.get( i )._title;
                String words = mSongs.get( i )._words;
                Log.i("DEBUG", "Boucle MatrixCursor avec title:"+title);

                if (title.toLowerCase().contains( searchString )) {
                    mRow[0] = "" + counterId++;
                    mRow[1] = title;
                    mRow[2] = "" + counterId++;
                    Log.i("DEBUG", "Boucle MatrixCursor contains avec mRow:"+mRow+":title:"+title);
                    searchResults.addRow( mRow );
                }
            }
        }
        Log.i("DEBUG", "Boucle MatrixCursor avant return: mRow:"+searchResults);
        return searchResults;    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public String getType(Uri uri) {
        switch (mUriMatcher.match( uri )) {
            case TYPE_ALL_SUGGESTIONS:
                return SearchManager.SUGGEST_MIME_TYPE;
            default:
                throw new IllegalArgumentException( "Unknown URL " + uri );
        }
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

3) searchable.xml

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:hint="@string/search_hint"
    android:label="@string/app_name"
    android:searchSuggestAuthority="songs4heaven_p2.com.hfad.songs4heaven_p2.SearchContentProvider"
    android:searchSuggestIntentAction="android.intent.action.VIEW"
    android:searchSuggestIntentData="content://songs4heaven_p2.com.hfad.songs4heaven_p2.SearchContentProvider/songs"
    android:searchSuggestThreshold="2"
    android:voiceSearchMode="showVoiceSearchButton|launchRecognizer">
</searchable>

4) SearchAndroidActivity for the Intent managing

package songs4heaven_p2.com.hfad.songs4heaven_p2;

import android.app.SearchManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public  class SearchAndroidActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {

    private static final String TAG = SearchAndroidActivity.class.getSimpleName();

    private ListView listView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        setContentView(R.layout.activity_searchable);

        // 20180802 :   cast obligatoire sinon il voit du View alors que c'est bien du ListView ...
        listView = (ListView) findViewById( R.id.search_listview );

        listView.setOnItemClickListener(this);
        Log.i(TAG, "DEBUG: onCreate avant handleIntent");
        Log.i(TAG, "DEBUG: getAction:" + getIntent().getAction());
        handleIntent(getIntent());

    }

    @Override
    protected void onNewIntent(Intent newIntent) {
        // update the activity launch intent
        setIntent(newIntent);
        // handle it
        Log.i(TAG, "DEBUG: onNewIntent");
        handleIntent(newIntent);
    }

    private void handleIntent(Intent intent) {

        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
            // The user has initiated a search.

            Log.i(TAG, "handleIntent: Intent.ACTION_SEARCH");

            String query = intent.getStringExtra(SearchManager.QUERY);
            Log.i(TAG, "DEBUG: handleIntent: query:"+query+":");
            doSearch(query);

        } else if (Intent.ACTION_VIEW.equals(intent.getAction())) {

            // The user has selected a suggestion.
            // Handles clicking on the search results drop down...

            Log.i(TAG, "DEBUG : handleIntent: Intent.ACTION_VIEW");

            Uri details = intent.getData();
            String details2 = intent.getDataString();
            ComponentName details3 = intent.getComponent();
            String id = intent.getStringExtra("id");
            String name = intent.getStringExtra("name");
            ComponentName resolve = intent.resolveActivity( getPackageManager() );

            Log.i(TAG, "DEBUG : URI:details:"+details.getLastPathSegment());
            Log.i(TAG, "DEBUG : URI:details2:"+details2);
            Log.i(TAG, "DEBUG : URI:details3:"+details3);
            Log.i(TAG, "DEBUG : URI:details full:"+details);
            Log.i(TAG, "DEBUG : URI:id:"+id);
            Log.i(TAG, "DEBUG : URI:name:"+name);
            Log.i(TAG, "DEBUG : resolve:"+resolve);

            Intent detailsIntent = new Intent(Intent.ACTION_VIEW, details);
            //Intent detailsIntent = new Intent(Intent.ACTION_VIEW, Uri.parse( details2 ) );
            try {
                startActivity(detailsIntent);

            } catch ( ActivityNotFoundException e) {
                e.printStackTrace();
                Log.e(TAG,"DEBUG : Can't find activity to handle intent; ignoring",e);
            }

            //startActivity(Intent.createChooser(detailsIntent, "dialogTitle"));


            //finish();

        }

    }

    private void doSearch(String query) {

        Log.i(TAG, "DEBUG : Entree - doSearch");
        new SearchTask().execute(query);

    }

    private class SearchTask extends AsyncTask<String, Void, Cursor> {

        @Override
        protected Cursor doInBackground(String... params) {

            Log.i(TAG, "DEBUG : Entree - doInBackground");
            String wildcardQuery = "%" + params[0] + "%";
            Uri uri =  Uri.parse("content://" + "AUTHORITY" + "/" + "BASE_DATA_NAME" + "/" + SearchManager.SUGGEST_URI_PATH_QUERY);
            String[] projection = {"SELECT", "UPDATE"};
            String selection = "SELECT FROM";
                    String[] selectionArgs = {wildcardQuery, wildcardQuery};
            String sortOrder = "ASC";

            Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);
            return cursor;
        }

        @Override
        protected void onPostExecute(Cursor cursor) {



         Log.i(TAG, "DEBUG : Entree - onPostExecute");

            String[] dataColumns = {
                    "COLUMN_ID",
                    "COLUMN_FIRSTNAME"};

            int[] viewIDs = {
                    R.id.list_item_emp_id,
                    R.id.list_item_name};


            String[] items = { "Milk", "Butter", "Yogurt", "Toothpaste", "Ice Cream" };

            ArrayAdapter<String> adapter = new ArrayAdapter<String>(getApplication(),
                    android.R.layout.simple_list_item_1, items);

            listView.setAdapter(adapter);

        }

    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
            case R.id.action_search:
                onSearchRequested();
                // break;
                return true;
            case android.R.id.home:
                // This is called when the Home (Up) button is pressed
                // in the Action Bar.
                Intent parentActivityIntent = new Intent(this, MainSongs4Heaven_p2.class);
                parentActivityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(parentActivityIntent);
                finish();
                // break;
                return true;
            default:
                return false;
        }

        // return super.onOptionsItemSelected(item);

    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

        Log.i(TAG, "onItemClick");


        finish();

    }
}

5) Song class

package songs4heaven_p2.com.hfad.songs4heaven_p2;

public class Song {
    Integer _ID;
    String _title;
    String _words;
    String _chords;
    String _author;

    // constructor
    public Song() {

    }

    // constructor with parameters
    public Song(Integer ID, String title, String words, String chord, String author) {
        this._ID = ID;
        this._title = title;
        this._words = words;
        this._title = title;
    }

    // All get methods

    public Integer getId() {
        return this._ID;
    }

    public String getTitle() {
        return this._title;
    }

    public String getWords() {
        return this._words;
    }

    public String getChords() {
        return this._chords;
    }

    public String getAuthor() {
        return this._author;
    }

    // All set methods

    public void setId(Integer ID) {
        this._ID = ID;
    }

    public void setTitle(String title) {
        this._title = title;
    }

    public void setWords(String words) {
        this._words = words;
    }

    public void setChords(String chords) {
        this._chords = chords;
    }

    public void setAuthor(String author) {
        this._author = author;
    }

    //
    @Override
    public String toString() {
        return _ID + "\n" + _title + " " + _words + "\n" + _chords + "\n" + _author;
    }

}

6) Singleton to load my xml file in a list of song objects

package songs4heaven_p2.com.hfad.songs4heaven_p2;

import android.content.Context;

import java.util.List;

public class SingleLoadXml {
    private  static List<Song> mSong = null;

    public static List<Song> getSongs(Context context) {
        if ( mSong == null ) {
            // je récupère les données XML
            SongXmlParser parser = new SongXmlParser();

            mSong = parser.parse(context);

        }
        return mSong;
    }


}

7) Main class for the search call

import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class MainSongs4Heaven_p2 extends AppCompatActivity {

    TextView tv1;
    public List<Song> songs = null;

    // pour distinguer le démarrage (affichage du chant n°1) et ensuite (chant selon valeur Spinner)

    boolean Demarrage = true;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_songs4_heaven_p2);
        tv1=(TextView)findViewById(R.id.paroles_chant);
        Log.d("DEBUG", "Avant try");

        // 20180717 :   Appelle XMLPULLPARSER & RETURN A LIST
        //              SongXmlParser.parse => retourne un songList soit un ArrayList<Song>
        //              Inspiré de http://innovativenetsolutions.com/2013/02/android-xml-parsing/

        // Ce 20180719 : je remplace ces 2 lignes par un Singleton : SingleLoadXml
        //SongXmlParser parser = new SongXmlParser();
        //songs = parser.parse(getBaseContext());
        songs=SingleLoadXml.getSongs( getBaseContext() );

        //  201780716   :   je change la technique qui allait systématiquement boucler sur le xml
        //                  en utilisant désormais le résultat du parse de SongXmlParser

        initSpinnerWithXml();

        Log.d("DEBUG", "Juste après initParoles");

    }

    //  20180729
    //      https://developer.android.com/training/search/setup

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        Log.d("DEBUG", "Entrée dans onCreateOptionsMenu");
        //MenuInflater inflater = getMenuInflater();
        //inflater.inflate(R.menu.options_menu, menu);
        getMenuInflater().inflate(R.menu.options_menu, menu);

        // Get the SearchView and set the searchable configuration
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        android.support.v7.widget.SearchView searchView = (android.support.v7.widget.SearchView) menu.findItem(R.id.action_search).getActionView();
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        searchView.setIconifiedByDefault(false);
        Log.i("DEBUG", "before onQueryText*: ");

        searchView.setOnQueryTextListener(new android.support.v7.widget.SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                Log.i("DEBUG", "onQueryTextSubmit: ");
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                Log.i("DEBUG", "onQueryTextChange: ");
                return false;
            }
        });

        Log.i("DEBUG", "before return true in onCreateOptionsMenu ");
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_search:
                onSearchRequested();
                return true;
            default:
                return false;
        }
    }

Sum up

To sum it up, it seems that I lack something in the URI contents. Here is the result of the debug in the SearchAndroidActivity

 Log.i(TAG, "DEBUG : URI:details:"+details.getLastPathSegment());
        Log.i(TAG, "DEBUG : URI:details2:"+details2);
        Log.i(TAG, "DEBUG : URI:details3:"+details3);
        Log.i(TAG, "DEBUG : URI:details full:"+details);
        Log.i(TAG, "DEBUG : URI:id:"+id);
        Log.i(TAG, "DEBUG : URI:name:"+name);
        Log.i(TAG, "DEBUG : resolve:"+resolve);
DEBUG: getAction:android.intent.action.VIEW
DEBUG : handleIntent: Intent.ACTION_VIEW
DEBUG : URI:details:1
DEBUG : URI:details2:1
DEBUG : URI:details3:ComponentInfo{songs4heaven_p2.com.hfad.songs4heaven_p2/songs4heaven_p2.com.hfad.songs4heaven_p2.SearchAndroidActivity}
DEBUG : URI:details full:1
DEBUG : URI:id:null
DEBUG : URI:name:null
DEBUG : resolve:ComponentInfo{songs4heaven_p2.com.hfad.songs4heaven_p2/songs4heaven_p2.com.hfad.songs4heaven_p2.SearchAndroidActivity}

intent.getDataString() does not return anything else than a numeric. When comparing to another app, I should have something like an URI :

like

content://com.himebaugh.employeedirectory.EmployeeProvider/employees/3

Could you help me ?

Thank you very much.

Jean-michel, Nemours, France

JMA
  • 83
  • 7
  • Hi, Only for my app. Thx. Jmichel – JMA Aug 23 '18 at 08:28
  • It is unclear about which activity you are talking. And about which intent. And the exact error message on which statement? And then you did not tell the scenario used. And why posting so much code? Should we dig through that all? – greenapps Aug 23 '18 at 08:46
  • Further you are not showing us how you start SearchAndroidActivity. So how could we know what the intent contains? – greenapps Aug 23 '18 at 08:52
  • Sorry for the trouble. I am going to be clearer. My problem occurs when I select a suggestion. The suggestion appears normally (the song title when I suggest the first 2 characters in the google search area). But then, when the intent (VIEW afaik) is tested in the SearchAndroidActivity class, it does not work. – JMA Aug 23 '18 at 09:14
  • Here is the search management in the main class : – JMA Aug 23 '18 at 09:20
  • I do not know how to add the code of the main class. It is too big. I managed to edit the original post and the main class is now number 7. – JMA Aug 23 '18 at 09:30
  • I want to rely upon the google search manager and, given I use the suggestions, I need to use a Content Provider. But the Provider management is difficult for me to understand. When I select a suggestion, it always fails. – JMA Aug 23 '18 at 09:32
  • 1) Once characters are entered in the search area at the top, through the google search bar, the main calls onSearchRequested() then onQueryTextChange. 2) Cursor is then called in the SearchContentProvider, then MatrixCursor. 3) At last, SearchAndroidActivity is called. Its onCreate calls handleIntent with getIntent. (Intent.ACTION_VIEW) 4) The app fails. Is it clearer ? Thx. – JMA Aug 23 '18 at 09:49
  • If that intent does not contain the right info, not the right content scheme, then that is your problem. So concentrate on that. Why post all that irrelevant code? – greenapps Aug 23 '18 at 10:03
  • I understand. In fact, I have built my app using another activity (EmployeeDirectory from Langdon Himebaugh : http://innovativenetsolutions.com/2013/07/android-tutorial-search-interface-search-dialog/) which works and it seems to come from the search configuration in the manifest and the searchable xml file which involves the uri and sometimes the mime type. All the codes are calling one another. I thought it would be easier to get all the pieces together. – JMA Aug 23 '18 at 10:20
  • if your search functionality is for your app only - then all you have to do is to call `SearchView#setSuggestionsAdapter` - also your adapter has to call `setFilterQueryProvider()` or override `runQueryOnBackgroundThread()` method – pskink Aug 24 '18 at 05:21
  • Sorry. Had no time yet to test it. I'll get in touch asap. – JMA Aug 24 '18 at 09:33
  • In fact, I do know not how to do it ... Do I have to implement the setFilterQueryProvide in the main or in the ContentProvider class ? Is it compatible with a MatrixCursor or only with a database cursor ? – JMA Aug 24 '18 at 13:29
  • So sorry. I do not see where and how to use it given an adapter is presently only used only when the "Go to" key is used, not after a suggestion has been chosen. 2) the app I used (EmployeeDirectory Step from L. Himebaugh) as a template works this way, without any adapter for the suggestion part. That's why I believe something must be wrong with my URI/mimeType configuration. Even though L. Himebaugh is using a database cursor, I wonder why I could not use his code with a MatricCursor instead. – JMA Aug 24 '18 at 14:17
  • Please excuse me if I am wrong. In fact, I began coding a few months ago a search without suggestion and it worked fine. But now the suggestion search mecanism, through a provider, is a bit hard for me to understand in its entirety. – JMA Aug 24 '18 at 14:17
  • I still do not know how to code it. In which class ? – JMA Aug 24 '18 at 15:47
  • After some search, I have found another way to prevent the exception : Intent i = new Intent(this, songs4heaven_p2.com.hfad.songs4heaven_p2.SearchAndroidActivity.class); startActivity(i); I now have to found how to display, on the SearchAndroidActivity, the data linked to the title selected as a suggestion. – JMA Aug 28 '18 at 18:05

0 Answers0