Android键盘即使在明确请求时也不会出现

时间:2013-06-01 14:04:05

标签: android android-actionbar android-keypad android-search

我有一个有两个活动的应用程序,有时候,我需要切换活动,同时在刚刚恢复的活动的操作栏中打开搜索输入。一切都很好,除了我不能让键盘出现。我的代码的相关位在下面(注意:如果需要搜索输入,则作为切换活动的结果,布尔startsearch设置为true):

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);
        }
    }
}

并且action_menu.xml的相关位是

<?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>

正如我所说,这主要起作用,因为动作栏搜索确实在活动恢复时获得焦点。但键盘没有出现,即使(从代码中可以看到),我已明确要求它。任何人都可以告诉我我做错了什么,以及我需要做些什么才能让键盘出现?

5 个答案:

答案 0 :(得分:4)

我现在能够弄清楚这一点。通过查看InputMethodManager.showSoftInput(View, int)的代码,我发现我的键盘调用请求被忽略了,因为我传递的视图不是InputMethodManager的活动视图。

为了解决我的问题,我在MyActivity类中添加了两个新字段,即:

private EditText search_edit_text;
private boolean mySearchView_editflag;

search_edit_text变量将是SearchView mySearchView内的视图,它是实际获得焦点并从键盘接收输入的视图。 mySearchView_editflag通常为false,但当应用等待正确的时间调出键盘时,true将为search_edit_text

为了掌握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; } EditText对象,我使用了以下函数

onCreateOptionsMenu(Menu)

并修改了我的DestinationTxt = menu.findItem(R.id.actionbar_search); mySearchView = (SearchView)DestinationTxt.getActionView(); search_edit_text = GetEditText(mySearchView); mySearchView_editflag = false; 功能以包含以下内容

search_edit_text

这会初始化mySearchView_editflagonResume()变量。我的@Override public void onResume() { super.onResume(); if (startsearch) { DestinationTxt.expandActionView(); mySearchView_editflag = true; } } 方法已更改为

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

我包含了以高频率调用以下方法的代码:

imm.isActive(search_edit_text)

此应用程序现在可以按照我的意愿运行,因为在需要操作栏中的搜索输入后执行活动切换,应用程序现在等待EditText为真(这意味着imm.showSoftInput(search_edit_text, 0)对象是在调用InputMethodManager.showSoftInput(View, int, ResultReceiver)之前接收输入,以确保键盘可见。

为了帮助我解决所有问题,我使用InputMethodManager.showSoftInput(View, int)代替imm.showSoftInput(search_edit_text, 0); ,而不是

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

我有

ImmResultsReceiver

其中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())); } } 是类

ImmResultsReceiver.onReceiveResult(...)

如果从未调用InputMethodManager.showSoftInput(...)方法,则表示已忽略对InputMethodManager.showSoftInput(...)的调用,因为传递给{{1}}的视图不是InputMethodManager的活动视图。

答案 1 :(得分:2)

在清单文件中,尝试将以下内容添加到 MyActivity 活动部分,以便在活动开始时显示键盘:

android:windowSoftInputMode="stateVisible"

这会导致键盘在活动开始时变得可见。

修改

然后在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;
}

答案 2 :(得分:0)

我上一次输入的后记。在我发布延迟切换之前,我检查了InputMethodManager.isActive()是否为false。一切都很好,除了在350毫秒后它不再适用。所以在postDelayed中,当你的延迟代码运行时,再次检查InputMethodManager.isActive(),如果是,则不切换showSoftInput,否则新显示的键盘将消失,这根本不是人们想要的。

答案 3 :(得分:0)

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);
    }

答案 4 :(得分:0)

这是一个古老的问题,但是我遇到了一个类似的问题,该视图具有焦点,但在InputMethodManager中未激活。通过在requestFocus()之后添加一个延迟,我从上面的一些答案中获取了一个队列。由于我使用的是Kotlin,因此我使用了协程来实现延迟。这样我们就不会阻塞主线程。相关代码如下所示。

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)
                }
            }
        }
    }

}