После программного вызова мой Android-приложение зависает - PullRequest
1 голос
/ 04 мая 2010

Заголовок объясняет все ... У меня есть этот фрагмент кода в моем приложении:

String url = createTelUrl("3112007315");
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse(url));
context.startActivity(intent);

Он делает звонок, но как только звонок заканчивается, мое приложение вылетает. Я хотел бы вернуться к своему заявлению после завершения вызова, но я прочитал этот пост , и, похоже, это невозможно. Итак ... есть ли способ хотя бы приостановить мое приложение и возобновить его после завершения вызова?

EDIT:

Спасибо за два ответа, которые я получил, я чувствую, что действительно близок к своей цели ... Я уже сделал кое-что из того, что вы, ребята, предложили. Но, может быть, я не объяснил некоторые детали приложения ... Я разрабатываю игру Who Wants To A Millonarie , поэтому мне нужно реализовать вызовы (я не знаю, как это называется США или другие страны, но здесь мы называем это «звонком другу»).

В любом случае ... Я сделал слишком много изменений в этом приложении, и теперь оно не падает. Но холст, на котором я рисую пользовательский интерфейс, не отображается после завершения вызова.

У меня есть SurfaceView, который содержит пользовательский интерфейс. Для этого SurfaceView я создал поток, который предназначен для обновления пользовательского интерфейса ... это в основном то, что делает поток:

@Override
public void run() {
    Canvas c;
    while (_run) {
        c = null;
        try {
            c = _surfaceHolder.lockCanvas(null);
            // Check if should wait
            synchronized (_surfaceHolder) {
                _panel.onDraw(c);
            }
        } finally {
            // do this in a finally so that if an exception is thrown
            // during the above, we don't leave the Surface in an
            // inconsistent state
            if (c != null) {
                _surfaceHolder.unlockCanvasAndPost(c);
            }
        }
    }
}

Но, как только звонок закончился, я получил черный экран. Поверхность есть (я знаю это, потому что она все еще может получать некоторые сенсорные события), но она ничего не показывает. Еще одна вещь, которую стоит принять во внимание, это то, как я запускаю поток из класса SurfaceView:

public void surfaceCreated(SurfaceHolder holder) {
    hilo.setRunning(true);
    try{
        hilo.start();
    }catch(IllegalThreadStateException ite){
        Log.e("wwtbam", "god dammed");
    }
}

Это хорошо сработало, прежде чем я начал осуществлять телефонные звонки. Проблема здесь в том, что после завершения вызова и повторного запуска запускается метод start, который выдает IllegalThreadStateException, поскольку поток уже запущен. Я пытался использовать некоторые «техники», чтобы приостановить поток пользовательского интерфейса во время вызова, но я не смог решить эту проблему. Я пытался сделать что-то вроде:

// this in the UI thread class
if(haveToWait)
    wait();
....
// this in the surface view class
if(callEnded)
    hilo.notify();

Но это не сработало. Я также попробовал некоторые другие «приемы», такие как sleep(50); вместо wait();, но он тоже не работает.

Со всей этой информацией, которую я предоставил ... что вы могли бы мне предложить?

Ответы [ 3 ]

5 голосов
/ 09 мая 2010

Это возможно при использовании android.telephony.PhoneStateListener.

Во-первых, нам нужно позаботиться о манифесте приложения:

Нам нужно разрешение на звонки (дух!), А также разрешение на просмотр состояния телефона. Последнее необходимо, чтобы приложение также могло реагировать на завершение вызова. Итак, мы добавляем эти строки в наш манифест приложения:

<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Кроме того, мы не хотим, чтобы Android запускал другой экземпляр нашей активности после завершения вызова, поэтому мы установили атрибут launchMode действия на "singleInstance".

<activity android:name=".CallTest" android:label="Calling Test" 
        android:launchMode="singleInstance" />

Подготовив все в манифесте, теперь мы можем посмотреть на действие, выполняющее вызов:

public class CallTest extends Activity {
    PhoneStateListener mListener;
    TelephonyManager mTelMgr;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mListener = new CallEndedListener();
        mTelMgr = (TelephonyManager) this.getSystemService(TELEPHONY_SERVICE);
    }

    public void makecall(View v) {
        // Register our listener to be notified of the beginning
        // and ending of calls
        mTelMgr.listen(mListener, PhoneStateListener.LISTEN_CALL_STATE);

        // Start the call
        Intent call = new Intent(Intent.ACTION_CALL);
        call.setData(Uri.parse("tel:12345"));
        startActivity(call);
    }

    class CallEndedListener extends PhoneStateListener {
        boolean called = false;

        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            super.onCallStateChanged(state, incomingNumber);

            // Don't fire before the call was made
            if (state == TelephonyManager.CALL_STATE_OFFHOOK)
                called = true;

            // Call has ended -- now bring the activity back to front
            if (called && state == TelephonyManager.CALL_STATE_IDLE) {
                called = false;
                mTelMgr.listen(this, PhoneStateListener.LISTEN_NONE);
                startActivity(new Intent(CallTest.this, CallTest.class));
            }
        }
    }
}

Единственная новая вещь в методе makecall, по сравнению с фрагментом кода в вопросе, - это реализация PhoneStateListener, добавленная непосредственно перед фактическим выполнением вызова. Затем этот прослушиватель получает уведомление от Android при наборе исходящего вызова, звонке входящего вызова или завершении активного вызова.

Наша реализация ожидает последнего события CALL_STATE_IDLE и снова начинает нашу деятельность, чтобы после завершения вызова мы вернулись в наше приложение, где мы его оставили. Затем он отменяет свою регистрацию, поэтому наша деятельность не возобновляется каждый раз, когда пользователь завершает вызов, не инициированный нашей собственной деятельностью.

Однако при регистрации событий CALL_STATE с помощью TelephonyManager Android мгновенно запускает уведомление с текущим состоянием - поэтому наш слушатель будет вызван еще до того, как вызов начнется. Поэтому наша реализация слушателя сначала ждет, пока не будет запущен исходящий вызов (CALL_STATE_OFFHOOK), и только после того, как это произошло, реагирует на уведомление CALL_STATE_IDLE.

НТН!

5 голосов
/ 11 мая 2010

Проблема здесь в том месте, которое вы используете для запуска темы. Как только вы начнете новый вызов, ваша основная деятельность будет приостановлена, а вид поверхности будет уничтожен. Тем не менее, поток будет продолжать работать. Итак, как только ваше приложение вернет элемент управления, поверхность будет создана снова, и будет запущен метод start. Это вызывает исключение IllegalThreadStateException.

Путь здесь заключается в манипулировании потоком из класса SurfaceView. Это даст вам контроль над потоком из основного действия, и вы сможете решить, когда начинать или приостанавливать поток.

Посмотрите на этот пример: http://code.google.com/p/apps-for-android/source/browse/trunk/SpriteMethodTest/src/com/android/spritemethodtest/

1 голос
/ 08 мая 2010

Что касается сбоя - пожалуйста, опубликуйте журнал и включите отладчик onStart / onResume, чтобы выяснить причину сбоя. Возможно, что-то инициализировано не в том месте, и вы можете сделать что-то такое же простое, как nullpointer.

Что касается завершения вызова - я никогда не пробовал это, но я бы попытался зарегистрировать получателя, поймать http://developer.android.com/reference/android/telephony/TelephonyManager.html#ACTION_PHONE_STATE_CHANGED Оцените состояние телефона и сделайте то, что вам нужно.

Также здесь есть больше информации http://developer.android.com/reference/android/telephony/ http://developer.android.com/reference/android/telephony/PhoneStateListener.html

И, наконец, вы найдете примеры того, как использовать это в приложениях, которые используют эту функциональность в source.android.com

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...