Комментарии 16
пользователь сталкнётся
От слова сталкер?
От слова сталкер?
-9
Помогите плиз по поводу взаимодействия с UI из thread
На практике я сталкиваюсь с ситуацией, когда отдельный процесс, отображающий, например, прогрессдиалог в контексте вызвавшего его активити — падает с ошибкой при прерывании либо? закрытии основного активити.
По видимому сценарий такой
1. Пользователь нажал кнопку
2. Стартовала задача с прогресс диалогом
3. Пользователь переключился на другую программу либо еще что-то^^
4. Асинхронная задача «потеряла» контекст и падает
В результате я не могу отобразить например алерт диалог на потерю соединения либо закрыть корректно прогресс диалог, причем толком воспроизвести не удается, я вижу ошибки по логам багсенс, но не вижу причин
Таск выглядит так:
На практике я сталкиваюсь с ситуацией, когда отдельный процесс, отображающий, например, прогрессдиалог в контексте вызвавшего его активити — падает с ошибкой при прерывании либо? закрытии основного активити.
По видимому сценарий такой
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();
}
0
Причем я вижу, что в таких приложениях, как например андроид маркет — данная проблема по-видимому решена, так как при отсутствующем соединении вылетает алерт диалог типа соединение потеряно, но я не вижу пути как реализовать это безопасно кроме диких извратов навроде своего таскменеджера проверяющего не свалилась ли по эксепшену какая либо из запущенных задач + кэнселить все активные при событии при онпауз, типа if (mTaskManager!=null) mTaskManager.cancel(true); но это ж замучаешься столько кода каждый раз в каждом активити городить!
0
Создайте специальный Intent и подпишитесь на него в своём Activity, в GetRequest вместо создания диалога отправляйте Intent, а в Activity уже обработайте и выведите информацию
+1
Немного могу добавить.
Мне Looper был интересен тем, что при том, что создает очередь сообщения, он еще вставляет poll метод (можно с натяжкой сказать sleep), т.е. отдает ресурсы системы, а не жрет всё процессорное время.
При этом класс Looper достаточно простой и легко читаемый в исходниках, кажется там около 300 строк.
Мне Looper был интересен тем, что при том, что создает очередь сообщения, он еще вставляет poll метод (можно с натяжкой сказать sleep), т.е. отдает ресурсы системы, а не жрет всё процессорное время.
При этом класс Looper достаточно простой и легко читаемый в исходниках, кажется там около 300 строк.
+1
это проблема реализации класса AsyncTask в Android — неявная связь с инстансом текущей активити, а например при повороте экрана активити создаётся заново. один из инженеров гугл пишет что AsyncTask нужно использовать только для очень коротких тасков. решают эту проблему через явную привязку к активити code.google.com/p/texteasy/source/browse/trunk/src/org/texteasy/WeakAsyncTask.java
+3
Большое спасибо, кажется это именно то, что я искал.
Бегло просматривая сорцы соседних файлов заметил некую странность связанную с, по всей видимости, различными реализациями интерфейса для доступа к контакт листу в зависимоти от сдк?
Просто я столкнулся с похожей проблемой и не могу понять откуда растут ноги. Буду премного благодрен если подтолкнете в правильном направлении (я предположил что исходник по ссылке выше — ваш и возможно у вас возникала аналогичная проблема).
В моем приложении тоже считывается контакт лист, для осуществления звонков, отправки смс етк.
Функция выглядит так:
Я тестировал его на многих телефонах с различным андроид 2,3 и 4 — нигде ошибок не возникает. Однако на продакшене — мне постоянно сыпятся странные ошибки в логи. У приложения довольно 100000+ установок, в день в логах я вижу до десятка ошибок.
То ли я где то накосячил, то ли есть какие то нюансы с этими грешными контактами. Перепробовал уже все. Почему трай кэтч не ловит — ума не приложу…
Бегло просматривая сорцы соседних файлов заметил некую странность связанную с, по всей видимости, различными реализациями интерфейса для доступа к контакт листу в зависимоти от сдк?
Просто я столкнулся с похожей проблемой и не могу понять откуда растут ноги. Буду премного благодрен если подтолкнете в правильном направлении (я предположил что исходник по ссылке выше — ваш и возможно у вас возникала аналогичная проблема).
В моем приложении тоже считывается контакт лист, для осуществления звонков, отправки смс етк.
Функция выглядит так:
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+ установок, в день в логах я вижу до десятка ошибок.
То ли я где то накосячил, то ли есть какие то нюансы с этими грешными контактами. Перепробовал уже все. Почему трай кэтч не ловит — ума не приложу…
0
Я бы рекомендовал вместо AsyncTask управлять потоками в ручную и разрабатывать приложение так-же как и под другие платформы — в частности вручную контролировать все созданные потоки и при закрытии приложения, останавливать также и потоки. Если по каким-либо причинам остановить поток нету возможности (а такое бывает например если он висит на чтении из сокета — в Андроид есть связанный с этим баг), то освобождать все ссылки от потока к активити, переводя его в состояние «orphaned».
0
Пересоздание активити при повороте экрана можно отключить установив атрибут
Странно почему не сделали такое поведение по умолчанию.
android:configChanges="keyboardHidden|orientation"
элемента activity в файле манифеста. В этом случае интерфейс все таки будет переворачиваться, но со стороны контролов все будет выглядеть как будто просто изменились размеры.Странно почему не сделали такое поведение по умолчанию.
+1
вот обвязка в активити для 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;
}
}
0
Какова цель поста? Все есть в оф.блоге, документации и примерах…
-4
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Android UI thread