Android keyboard not appearing, even when explicitly requested

笑着哭i 提交于 2020-02-25 04:27:06

问题


I have an app with two activities, and sometimes, I need to switch activity and at the same time open up the search input in the actionbar of the activity that's just been resumed. Everything works fine, except that I can't get the keyboard to come up. The relevant bits of my code are below (NB: the boolean startsearch is set true as a result of switching activities if the search input is required):

public class MyActivity extends Activity {

    private InputMethodManager imm;
    public  boolean startsearch;
    private MenuItem DestinationTxt;
    private SearchView mySearchView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // various initialisation, and then:
        startsearch = false;
        imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.action_menu, menu);     
        DestinationTxt = menu.findItem(R.id.actionbar_search);
        mySearchView = (SearchView)DestinationTxt.getActionView();
        // more menu create stuff appears here      
    }

    @Override
    public void onResume() {
        super.onResume();
        if (startsearch) {
            DestinationTxt.expandActionView();
            imm.showSoftInput(mySearchView, 0);
        }
    }
}

and the relevant bit of the action_menu.xml is

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item android:id="@+id/actionbar_search"
        android:orderInCategory="1"
        android:showAsAction="always|withText|collapseActionView"
        android:actionViewClass="android.widget.SearchView"
        android:icon="@drawable/earth_2508858_search_en"
        android:inputType="textPostalAddress"
        android:voiceSearchMode="showVoiceSearchButton|launchRecognizer"></item>
</menu>

As I said, this mostly works, because the action bar search does get the focus when the activity resumes. But the keyboard doesn't appear, even though (as you can see from the code), I've explicitly requested it. Can anyone tell me what I'm doing wrong, and what I need to do to get the keyboard to come up?


回答1:


I've now been able to figure this out. By looking at the code for InputMethodManager.showSoftInput(View, int), I worked out that my request to bring up the keyboard was being ignored because the view I was passing wasn't the InputMethodManager's active view.

To solve my problem, I added two new fields to the MyActivity class, namely:

private EditText search_edit_text;
private boolean mySearchView_editflag;

The search_edit_text variable will be the view inside the SearchView mySearchView which is the view that actually gets the focus and receives the input from the keyboard. The mySearchView_editflag will normally be false, but it will be true when the app is waiting for the right time to bring up the keyboard.

To get hold of the search_edit_text EditText object I used the following function

public static EditText GetEditText(ViewGroup vg) {
    for(int i=0; i< vg.getChildCount(); i++) {
        View v = vg.getChildAt(i);
        if (v instanceof EditText) {
            return (EditText)v;
        } else if (v instanceof ViewGroup) {
            EditText et = GetEditText((ViewGroup)v);
            if (et != null) return et;
        }
    }       
    return null;
}

and altered my onCreateOptionsMenu(Menu) function to include the following

DestinationTxt = menu.findItem(R.id.actionbar_search);
mySearchView = (SearchView)DestinationTxt.getActionView();
search_edit_text = GetEditText(mySearchView);
mySearchView_editflag = false;

This initializes the search_edit_text and mySearchView_editflag variables. My onResume() method was altered to

@Override
public void onResume() {
    super.onResume();
    if (startsearch) {
        DestinationTxt.expandActionView();
        mySearchView_editflag = true;
    }
}

and I included code which calls the following method at high frequency:

public void CheckStatus() {
    if (mySearchView_editflag && imm.isActive(search_edit_text)) {
        imm.showSoftInput(search_edit_text, 0);
        mySearchView_editflag=false;
    }
}

This app now works as I want it to, because following the activity switch when search input in the actionbar is required, the app now waits until imm.isActive(search_edit_text) is true (which means the EditText object is receiving input) before calling imm.showSoftInput(search_edit_text, 0) to make sure that the keyboard is visible.

To help me work all this out, I used InputMethodManager.showSoftInput(View, int, ResultReceiver) instead of InputMethodManager.showSoftInput(View, int), so instead of

imm.showSoftInput(search_edit_text, 0);

I had

ImmResultsReceiver irr = new ImmResultsReceiver();
imm.showSoftInput(search_edit_text, 0, irr);

where ImmResultsReceiver is the class

public class ImmResultsReceiver extends ResultReceiver {        
    public ImmResultsReceiver() { super(null); }        
    @Override
    protected void onReceiveResult (int resultCode, Bundle resultData) {
        String descrip;
        switch(resultCode) {
            case InputMethodManager.RESULT_UNCHANGED_SHOWN: descrip = "RESULT_UNCHANGED_SHOWN"; break;
            case InputMethodManager.RESULT_UNCHANGED_HIDDEN: descrip = "RESULT_UNCHANGED_HIDDEN"; break;
            case InputMethodManager.RESULT_SHOWN: descrip = "RESULT_SHOWN"; break;
            case InputMethodManager.RESULT_HIDDEN: descrip = "RESULT_HIDDEN"; break;
            default:descrip="InputMethodManager("+resultCode+")"; break;
        }
        Log.d("MyLog", "ImmResultsReceiver,"+descrip+","+(resultData == null?"":"resultData.size()="+resultData.size()));
    }               
}

If the ImmResultsReceiver.onReceiveResult(...) method is never called, it means that the call to InputMethodManager.showSoftInput(...) has been ignored because the view that's passed to InputMethodManager.showSoftInput(...) isn't the InputMethodManager's active view.




回答2:


Inside your manifest file, try adding the following to the MyActivity activity section to show the keyboard when the activity starts:

android:windowSoftInputMode="stateVisible"

This should cause the keyboard to become visible when the activity starts.

edit

then try this inside onCreateOptionsMenu ..

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.action_menu, menu);
    MenuItem menu_search = menu.findItem(actionbar_search);


    menu_search.setOnActionExpandListener(new OnActionExpandListener() {
        @Override
        public boolean onMenuItemActionCollapse(MenuItem item) {
            // Do something when collapsed
            return true;  // Return true to collapse action view
        }

        @Override
        public boolean onMenuItemActionExpand(MenuItem item) {
            //get focus
            item.getActionView().requestFocus();
            //get input method
            InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
            return true;  // Return true to expand action view
        }
    });
    return true;
}



回答3:


A postscript to my last input. Before I postDelayed the toggle I checked InputMethodManager.isActive() for false. All well and good except that after 350 ms it no longer applied. So in your postDelayed, when your delayed code runs, check again for InputMethodManager.isActive() and if true do not toggle just showSoftInput otherwise the newly visible keyboard will go away, which is not what one wants at all.




回答4:


Oops, I think I posted my postscript to a related thread, not the original, however what I am talking about comes when one's app has been forced into the background by a phone call for instance and when it comes back EVEN if you explicitly find the EditText that had the focus and try and bring up the soft keyboard it simply won't come up. So here is the snippet of code that I employed after reading about posting the Toggle...

Note that the "O" referenced here is simply a class of static objects that I use in my app and the imeListener is a callback I use to tell the Fragments stuff about what's happening...

    if (O.mInputMethodManager.isActive()) {
        if (imeListener != null) {
            O.mInputMethodManager.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT,
                    new ResultReceiver(handler) {
                        protected void onReceiveResult(int resultCode, Bundle resultData) {
                            if (resultCode == InputMethodManager.RESULT_SHOWN || resultCode == InputMethodManager.RESULT_UNCHANGED_SHOWN) {
                                imeListener.onSoftKeyboardShown(filenameEditText);
                            }
                        }
                    }
            );
        }
        else {
            O.mInputMethodManager.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT);
        }
    }
    else { // there will be a slight delay...
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (!O.mInputMethodManager.isActive()) { // come right?
                    O.mInputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
                }
                if (imeListener != null) {
                    O.mInputMethodManager.showSoftInput(filenameEditText, InputMethodManager.SHOW_IMPLICIT,
                            new ResultReceiver(handler) {
                                protected void onReceiveResult(int resultCode, Bundle resultData) {
                                    if (resultCode == InputMethodManager.RESULT_SHOWN || resultCode == InputMethodManager.RESULT_UNCHANGED_SHOWN) {
                                        imeListener.onSoftKeyboardShown(filenameEditText);
                                    }
                                }
                            }
                    );
                } else {
                    O.mInputMethodManager.showSoftInput(filenameEditText, InputMethodManager.SHOW_IMPLICIT);
                }
            }
        }, 350);
    }



回答5:


This is an old question, but I ran into a similar problem where the view has focus, but is not active in the InputMethodManager. I took a queue from some of the answers above by simply adding a delay after requestFocus(). Since I'm using Kotlin, I used a coroutine to implement the delay. That way we are not blocking the main thread. Relevant code is shown below.

Class SomeActivity : AppCompatActivity(), CoroutineScope {

    // Create a coroutine job
    private val job = Job()

    // Implement CoroutineScope
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + job

    // Cancel the job when the activity is destroyed
    override fun onDestroy() {
        super.onDestroy()
        job.cancel()
    }

    // Shows the keyboard when view has focus
    private fun showKeyboard(view: View) {
        // start a coroutine
        launch {
            withContext(Dispatchers.Main) {
                // add delay of 300ms
                delay(300)
                if (currentFocus == view) {
                    // show the keyboard if view still has focus
                    (getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)
                        .showSoftInput(view, InputMethodManager.SHOW_IMPLICIT)
                }
            }
        }
    }

}


来源:https://stackoverflow.com/questions/16873517/android-keyboard-not-appearing-even-when-explicitly-requested

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!