Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/195.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
泄漏的ServiceConnection android.speech.tts.TextToSpeech$Connection_Android_Android Fragments_Memory Leaks - Fatal编程技术网

泄漏的ServiceConnection android.speech.tts.TextToSpeech$Connection

泄漏的ServiceConnection android.speech.tts.TextToSpeech$Connection,android,android-fragments,memory-leaks,Android,Android Fragments,Memory Leaks,我有一段文字到语音的片段。片段由按钮组成,如果按下按钮,tts将说出给定的文本 当我试图用真正的设备HTC HTL21(API 16)运行这个片段时,我得到了“泄漏的ServiceConnection android.speech.tts.TextToSpeech$Connection” 在此泄漏错误之前,我可以看到tts停止/关闭警告。但是我不知道我的代码出了什么问题 奇怪的是,我没有在AVD(Android虚拟设备)或Genymotion上看到这个警告/错误 非常感谢您的帮助 下面是日志ca

我有一段文字到语音的片段。片段由按钮组成,如果按下按钮,tts将说出给定的文本

当我试图用真正的设备HTC HTL21(API 16)运行这个片段时,我得到了“泄漏的ServiceConnection android.speech.tts.TextToSpeech$Connection”

在此泄漏错误之前,我可以看到tts停止/关闭警告。但是我不知道我的代码出了什么问题

奇怪的是,我没有在AVD(Android虚拟设备)或Genymotion上看到这个警告/错误

非常感谢您的帮助

下面是日志cat的一部分:

10-15 18:23:45.524 14811-14811/jp.miyamura.hds_r I/TextToSpeech: Sucessfully bound to com.google.android.tts
10-15 18:23:45.574 14811-14811/jp.miyamura.hds_r W/TextToSpeech: stop failed: not bound to TTS engine
10-15 18:23:45.574 14811-14811/jp.miyamura.hds_r W/TextToSpeech: shutdown failed: not bound to TTS engine
10-15 18:23:45.654 14811-14811/jp.miyamura.hds_r I/TextToSpeech: Sucessfully bound to com.google.android.tts
10-15 18:23:45.654 14811-14811/jp.miyamura.hds_r W/TextToSpeech: shutdown failed: not bound to TTS engine
10-15 18:23:45.664 14811-14811/jp.miyamura.hds_r I/TextToSpeech: Sucessfully bound to com.google.android.tts

10-15 18:23:45.794 14811-14811/jp.miyamura.hds_r E/ActivityThread: Activity jp.miyamura.hds_r.MainActivity has leaked ServiceConnection android.speech.tts.TextToSpeech$Connection@40fd08e8 that was originally bound here
10-15 18:23:45.794 14811-14811/jp.miyamura.hds_r E/ActivityThread: android.app.ServiceConnectionLeaked: Activity jp.miyamura.hds_r.MainActivity has leaked ServiceConnection android.speech.tts.TextToSpeech$Connection@40fd08e8 that was originally bound here
下面是我的演讲片段:

package jp.miyamura.hds_r;

import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Fragment;
import android.os.Build;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

import java.util.HashMap;
import java.util.Locale;


public class SpeechFragment extends Fragment implements TextToSpeech.OnInitListener, View.OnClickListener {

    private int buttonID = 0;
    private TextToSpeech tts;
    private String queuedText;
    private String splitChar;

    // Instantiate Speech fragment itself
    public static SpeechFragment newInstance(String speechString, String buttonString, int buttonID, String splitChar) {

        // Store data to be passed to the fragment in bundle format
        Bundle args = new Bundle();
        args.putString("Speech", speechString);
        args.putString("ButtonTitle", buttonString);
        args.putInt("ButtonID", buttonID);
        args.putString("splitChar", splitChar);

        // Instantiate Speech fragment and set arguments
        SpeechFragment newFragment = new SpeechFragment();
        newFragment.setArguments(args);
        return newFragment;
    }

    // Declare interface to communicate with it's container Activity
    public interface onSpeechFragmentListener {
        void onUtteranceStatus(boolean status);
        void onClickStatus(int buttonID);
    }

    private onSpeechFragmentListener myCallback;

    @Override
    @SuppressWarnings("deprecation")
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // Check container Activity implements interface listener or not
        try {
            myCallback = (onSpeechFragmentListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement onSpeechFragmentListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        myCallback = null;
    }

    // Required empty public constructor
    public SpeechFragment() {}

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

    @Override
    @SuppressWarnings("deprecation")
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        // Instantiate TTS
        if (tts == null) tts = new TextToSpeech(getActivity(), this);

        // Retrieve root view of fragment
        View rootView = inflater.inflate(R.layout.fragment_speech, container, false);

        String button_title = "";
        splitChar = "";

        // Receive arguments from it's container Activity
        if (getArguments() != null) {
            queuedText = getArguments().getString("Speech");
            button_title = getArguments().getString("ButtonTitle");
            buttonID = getArguments().getInt("ButtonID");
            splitChar = getArguments().getString("splitChar");
        }

        // Retrieve button and set onClick listener
        Button button = (Button) rootView.findViewById(R.id.speech_Button);
        button.setText(button_title);
        button.setId(buttonID);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // ToDo: Should be Build.VERSION_CODES.MARSHMALLOW
            button.setTextAppearance(android.R.style.TextAppearance_Medium);
        } else {
            button.setTextAppearance(getActivity(), android.R.style.TextAppearance_Medium);
        }

        button.setOnClickListener(this);

        return rootView;
    }

    @Override
    public void onStop() {

        if(tts !=null) {

            tts.stop();
        }
        super.onStop();
    }

    @Override
    public void onDestroyView() {

        if(tts !=null) {

            tts.shutdown();
        }
        super.onDestroyView();
    }

    @Override
    public void onInit(int status) {

        if (status == TextToSpeech.SUCCESS && tts != null) {

            // Set TTS Locale
            tts.setLanguage(Locale.getDefault());
        }
    }

    @Override
    public void onClick(View v) {

        // tts must not be null
        if (tts != null) {

            String utteranceId = this.hashCode() + "";

            // TTS Branch with Android OS Version
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                ttsGreater21(queuedText, utteranceId);
            } else {
                ttsUnder20(queuedText, utteranceId);
            }
        }

        myCallback.onClickStatus(buttonID);
    }

    // Speech method before LOLLIPOP
    @SuppressWarnings("deprecation")
    private void ttsUnder20(String text, String utteranceId) {

        HashMap<String, String> map = new HashMap<>();
        map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, utteranceId);

        // Split speech text with new line character and speak silence for each separation
        String[] splitSpeech = text.split(splitChar);
        for (int i = 0; i < splitSpeech.length; i++) {

            if (i == 0) { // Use for the first split text to flush on audio stream
                tts.speak(splitSpeech[i].trim(),TextToSpeech.QUEUE_FLUSH, map);
            } else { // add the new text on previous then play the TTS
                tts.speak(splitSpeech[i].trim(), TextToSpeech.QUEUE_ADD,map);
            }
            // Play Silence between text split
            tts.playSilence(750, TextToSpeech.QUEUE_ADD, null); // ToDo Length of silence should be optimized
        }

        setTTSListener();
    }

    // Speech method for LOLLIPOP and after
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void ttsGreater21(String text, String utteranceId) {

        // Split speech text with new line character and speak with silence
        String[] splitSpeech = text.split(splitChar);
        for (int i = 0; i < splitSpeech.length; i++) {

            if (i == 0) { // Use for the first split text to flush on audio stream
                tts.speak(splitSpeech[i].trim(), TextToSpeech.QUEUE_FLUSH, null, utteranceId);
            } else { // add the new text on previous then play the TTS
                tts.speak(splitSpeech[i].trim(), TextToSpeech.QUEUE_ADD, null, utteranceId);
            }
            // Play Silence between text split
            tts.playSilentUtterance(750, TextToSpeech.QUEUE_ADD, null); // ToDo Length of silence should be optimized
        }

        setTTSListener();
    }

    // TTS Status listener method
    private void setTTSListener(){
        tts.setOnUtteranceProgressListener(new UtteranceProgressListener() {
            @Override
            public void onStart(String utteranceId) {
            }

            @Override
            public void onDone(String utteranceId) {
                myCallback.onUtteranceStatus(true);
            }

            @Override
            public void onError(String utteranceId) {
                myCallback.onUtteranceStatus(false);
            }
        });
    }
}
包jp.miyamura.hds\r;
导入android.annotation.TargetApi;
导入android.app.Activity;
导入android.app.Fragment;
导入android.os.Build;
导入android.os.Bundle;
导入android.speech.tts.TextToSpeech;
导入android.speech.tts.utranceProgressListener;
导入android.view.LayoutInflater;
导入android.view.view;
导入android.view.ViewGroup;
导入android.widget.Button;
导入java.util.HashMap;
导入java.util.Locale;
公共类SpeechFragment扩展片段实现TextToSpeech.OnInitListener、View.OnClickListener{
私有int buttonID=0;
私密文本语音tts;
私有字符串队列文本;
私有字符串splitChar;
//实例化语音片段本身
公共静态SpeechFragment newInstance(String speechString、String buttonString、int buttonID、String splitChar){
//以捆绑格式存储要传递给片段的数据
Bundle args=新Bundle();
args.putString(“Speech”,speechString);
参数putString(“buttontile”,buttonString);
参数putInt(“ButtonID”,ButtonID);
args.putString(“splitChar”,splitChar);
//实例化语音片段并设置参数
SpeechFragment newFragment=新SpeechFragment();
setArguments(args);
返回新片段;
}
//声明接口以与其容器活动通信
公共接口onSpeechFragmentListener{
void onutternancestatus(布尔状态);
void onclick状态(int buttonID);
}
私有onSpeechFragmentListener myCallback;
@凌驾
@抑制警告(“弃用”)
公共事务主任(活动){
超级转速计(活动);
//检查容器活动是否实现接口侦听器
试一试{
myCallback=(onSpeechFragmentListener)活动;
}catch(ClassCastException e){
抛出新的ClassCastException(activity.toString()
+“必须实现onSpeechFragmentListener”);
}
}
@凌驾
公共无效连接(){
super.onDetach();
myCallback=null;
}
//必需的空公共构造函数
公共演讲片段(){}
@凌驾
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
}
@凌驾
@抑制警告(“弃用”)
CreateView上的公共视图(布局、充气机、视图组容器、捆绑包保存状态){
//实例化TTS
如果(tts==null)tts=newtexttospeech(getActivity(),则为该值);
//检索片段的根视图
视图根视图=充气机。充气(R.layout.fragment\u语音,容器,false);
字符串按钮_title=“”;
splitChar=“”;
//从其容器活动接收参数
如果(getArguments()!=null){
queuedText=getArguments().getString(“语音”);
button_title=getArguments().getString(“Buttontile”);
buttonID=getArguments().getInt(“buttonID”);
splitChar=getArguments().getString(“splitChar”);
}
//检索按钮并设置onClick侦听器
Button Button=(Button)rootView.findViewById(R.id.speech_按钮);
按钮.setText(按钮标题);
button.setId(buttonID);
如果(Build.VERSION.SDK\u INT>=Build.VERSION\u CODES.M){//ToDo:应该是Build.VERSION\u CODES.MARSHMALLOW
button.setTextAppearance(android.R.style.TextAppearance_-Medium);
}否则{
setExtAppearance(getActivity(),android.R.style.TextAppearance_-Medium);
}
setOnClickListener(此);
返回rootView;
}
@凌驾
公共void onStop(){
如果(tts!=null){
tts.stop();
}
super.onStop();
}
@凌驾
公共无效onDestroyView(){
如果(tts!=null){
tts.shutdown();
}
super.onDestroyView();
}
@凌驾
公共无效onInit(int状态){
if(status==TextToSpeech.SUCCESS&&tts!=null){
//设置TTS区域设置
setLanguage(Locale.getDefault());
}
}
@凌驾
公共void onClick(视图v){
//tts不能为空
如果(tts!=null){
字符串outtanceId=this.hashCode()+“”;
//使用安卓操作系统版本的TTS分支
if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.LOLLIPOP){
ttsGreater21(queuedText,outtanceid);
}否则{
ttsUnder20(队列文本,话语ID);
}
}
myCallback.onClickStatus(buttonID);
}
//棒棒糖前的语音方法
@抑制警告(“弃用”)
私有void ttsUnder20(字符串文本、字符串语句ID){
HashMap=newHashMap();
map.put(TextToSpeech.Engine.KEY_PARAM_outrance_ID,outranceid);
//使用新行字符拆分语音文本,并在每次分离时保持沉默
String[]splitSpeech=text.split(splitChar);
for(int i=0;i@Override
public void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);  // Add this line

    savedInstanceState.putString("inputWords", tv_input_word.getText().toString());
}
if (savedInstanceState == null) {  // Add this line

    // Setup Fragment
    transaction = getFragmentManager().beginTransaction();
    transaction.replace(R.id.fragment_container1,
                SpeechFragment.newInstance(speechString, buttonString, buttonID1, splitChar));
    transaction.commit();
}  // Add this line