Pull to refresh

Comments 16

пользователь сталкнётся
От слова сталкер?
Помогите плиз по поводу взаимодействия с UI из thread
На практике я сталкиваюсь с ситуацией, когда отдельный процесс, отображающий, например, прогрессдиалог в контексте вызвавшего его активити — падает с ошибкой при прерывании либо? закрытии основного активити.

По видимому сценарий такой
1. Пользователь нажал кнопку
2. Стартовала задача с прогресс диалогом
3. Пользователь переключился на другую программу либо еще что-то^^
4. Асинхронная задача «потеряла» контекст и падает
В результате я не могу отобразить например алерт диалог на потерю соединения либо закрыть корректно прогресс диалог, причем толком воспроизвести не удается, я вижу ошибки по логам багсенс, но не вижу причин

Таск выглядит так:
public class GetRequest extends AsyncTask<String, Integer, String> {

private Activity activity;
private Exception e=null;

public GetRequest(Activity _activity) {
this.activity = _activity;
}


@Override
protected String doInBackground(String... params) {
HttpGet getRequest = null;
try {
getRequest = new HttpGet(params[0]);
Log.d("URL","url:"+params[0]);
HttpResponse response = App.getClient().execute(getRequest);
final int statusCode = response.getStatusLine().getStatusCode();
Log.d("STATUS","status:"+Integer.toString(statusCode));
if (statusCode != HttpStatus.SC_OK) {
return "";
}
HttpEntity getResponseEntity = response.getEntity();
String r = EntityUtils.toString(getResponseEntity);
return r;
}
catch (Exception e) {
if (null != getRequest) getRequest.abort();
this.e=e;
return "Error:"+e;
}
}

@Override
public void onPostExecute(String result) {
if (null != e) {
Log.e("GetRequest", "Exception", e);
if (activity!=null) alert(e);
//падает вот тут, проверка на нул не помогает
//если закоментить строчку выше ошибка пропадет, но я теряю возвожность взаимодействия из асинтаска с уи
}
}

private void alert(Throwable t) {
AlertDialog.Builder builder=new AlertDialog.Builder(activity);

builder
.setTitle("Exception!")
.setMessage(t.toString())
.setPositiveButton("OK", null)
.show();
}
}

//запуск задачи
try {
result = new GetRequest(this).execute("http://something").get();
} catch (Exception e) {
e.printStackTrace();
}
Причем я вижу, что в таких приложениях, как например андроид маркет — данная проблема по-видимому решена, так как при отсутствующем соединении вылетает алерт диалог типа соединение потеряно, но я не вижу пути как реализовать это безопасно кроме диких извратов навроде своего таскменеджера проверяющего не свалилась ли по эксепшену какая либо из запущенных задач + кэнселить все активные при событии при онпауз, типа if (mTaskManager!=null) mTaskManager.cancel(true); но это ж замучаешься столько кода каждый раз в каждом активити городить!
Создайте специальный Intent и подпишитесь на него в своём Activity, в GetRequest вместо создания диалога отправляйте Intent, а в Activity уже обработайте и выведите информацию
Да, это вариант, спасибо, но хочется получить макимально отчужденный от конкретных активити класс для бесполезного перетаскивания между проектами|активити с встроенной обработкой ошибок. Мне больше понравился подход предложенный ниже
Немного могу добавить.

Мне Looper был интересен тем, что при том, что создает очередь сообщения, он еще вставляет poll метод (можно с натяжкой сказать sleep), т.е. отдает ресурсы системы, а не жрет всё процессорное время.

При этом класс Looper достаточно простой и легко читаемый в исходниках, кажется там около 300 строк.
это проблема реализации класса AsyncTask в Android — неявная связь с инстансом текущей активити, а например при повороте экрана активити создаётся заново. один из инженеров гугл пишет что AsyncTask нужно использовать только для очень коротких тасков. решают эту проблему через явную привязку к активити code.google.com/p/texteasy/source/browse/trunk/src/org/texteasy/WeakAsyncTask.java
Большое спасибо, кажется это именно то, что я искал.

Бегло просматривая сорцы соседних файлов заметил некую странность связанную с, по всей видимости, различными реализациями интерфейса для доступа к контакт листу в зависимоти от сдк?

Просто я столкнулся с похожей проблемой и не могу понять откуда растут ноги. Буду премного благодрен если подтолкнете в правильном направлении (я предположил что исходник по ссылке выше — ваш и возможно у вас возникала аналогичная проблема).

В моем приложении тоже считывается контакт лист, для осуществления звонков, отправки смс етк.
Функция выглядит так:
  private ArrayList<Person> getContactList() {
    /*try {
      personList = new GetContacts(MActivity.this).execute().get();
    } catch (InterruptedException e) {
      e.printStackTrace();
    } catch (ExecutionException e) {
      e.printStackTrace();
    }*/
    if (startDialog == null) {
      startDialog = new ProgressDialog(MActivity.this);
      startDialog.setCancelable(true);
      startDialog.show();
      startDialog.setContentView(R.layout.emptydialog);
    }
    ArrayList<Person> contactList = new ArrayList<Person>();
    Cursor cur = null,phones = null;
    Person aContact = new Person();
    try {
      cur = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); 
      if (cur.moveToFirst()) { 
        int idColumn = cur.getColumnIndex(ContactsContract.Contacts._ID); 
  
        int displayNameColumn = cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME); 
        do
          String contactId = cur.getString(idColumn); 
          String disPlayName = cur.getString(displayNameColumn); 
          //Например сыпется тут с ошибкой java.lang.IllegalStateException: Couldn't init cursor window
          int phoneCount = cur.getInt(cur 
              .getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
         
          if(phoneCount>0){  
            phones = getContentResolver().query( 
                ContactsContract.CommonDataKinds.Phone.CONTENT_URI, 
                null
                ContactsContract.CommonDataKinds.Phone.CONTACT_ID 
                    + " = " + contactId, null, null); 
            if(phones.moveToFirst()){ 
              do
                String phoneNumber= phones.getString(phones  
                    .getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); 
                aContact = new Person();
                aContact.setPersonId(contactId);
                aContact.setPhoneNum(phoneNumber);
                aContact.setName(disPlayName.toLowerCase());
                contactList.add(aContact);
                //System.out.println(phoneNumber); 
              }while(phones.moveToNext()); 
            }
          }
      }while(cur.moveToNext());
     }
    }
    finally {
      if (cur != null) cur.close();
      if (phones != null) phones.close();
    }
    if (startDialog!=null) startDialog.dismiss();
    return contactList;
  }


* This source code was highlighted with Source Code Highlighter.


Я тестировал его на многих телефонах с различным андроид 2,3 и 4 — нигде ошибок не возникает. Однако на продакшене — мне постоянно сыпятся странные ошибки в логи. У приложения довольно 100000+ установок, в день в логах я вижу до десятка ошибок.
То ли я где то накосячил, то ли есть какие то нюансы с этими грешными контактами. Перепробовал уже все. Почему трай кэтч не ловит — ума не приложу…
Я бы рекомендовал вместо AsyncTask управлять потоками в ручную и разрабатывать приложение так-же как и под другие платформы — в частности вручную контролировать все созданные потоки и при закрытии приложения, останавливать также и потоки. Если по каким-либо причинам остановить поток нету возможности (а такое бывает например если он висит на чтении из сокета — в Андроид есть связанный с этим баг), то освобождать все ссылки от потока к активити, переводя его в состояние «orphaned».
Пересоздание активити при повороте экрана можно отключить установив атрибут android:configChanges="keyboardHidden|orientation" элемента activity в файле манифеста. В этом случае интерфейс все таки будет переворачиваться, но со стороны контролов все будет выглядеть как будто просто изменились размеры.
Странно почему не сделали такое поведение по умолчанию.
даже при залоченом (android:screenOrientation=«portrait») — возникает иногда
вот обвязка в активити для WeakAsyncTask

public class TestActivity extends ListActivity {
	/** State held between configuration changes. */
	private State state;
	private TestTask testTask;

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

		state = (State) getLastNonConfigurationInstance();
		final boolean previousState = state != null;
		if (previousState) {
			testTask = state.testTask;
			if (testTask != null) {
				testTask.setTarget(this);
			}
		} else {
			state = new State();
			testTask = new TestTask(this);
			state.testTask = testTask;
		}
	}

	@Override
	protected void onDestroy() {
		if (testTask != null) {
			testTask.cancel(true);
		}
		super.onDestroy();
	}

	@Override
	public Object onRetainNonConfigurationInstance() {
		state.testTask = testTask;
		return state;
	}

	private void runTestTask() {
		if (testTask != null && testTask.getStatus() == AsyncTask.Status.RUNNING) {
			return;
		}
		if (testTask == null || testTask.getStatus() == AsyncTask.Status.FINISHED) {
			testTask = new TestTask(this);
		}
		testTask.execute();
	}

	private static class TestTask extends WeakAsyncTask<Void, Void, Void, TestActivity> {

		public TestTask(TestActivity target) {
			super(target);
		}

		@Override
		protected Void doInBackground(TestActivity target, Void... params) {
			return null;
		}

		@Override
		protected void onPostExecute(TestActivity target, Void result) {
			super.onPostExecute(target, result);
		}
	}

	private static class State {
		TestTask testTask;
	}

}
Какова цель поста? Все есть в оф.блоге, документации и примерах…
Поставил минус, потому что не видел этого в документации, оф. блоге и примерах…
Sign up to leave a comment.

Articles