Доступ к Android UI elemnts из статического метода AsyncTask - PullRequest
0 голосов
/ 17 мая 2018

Итак, я пытаюсь создать приложение, которое синхронизирует файлы по ssh-соединению.Соединение ssh запускается как AsyncTask, и я хотел бы, чтобы он устанавливал текст элемента пользовательского интерфейса внутри метода onPostExecute, но не может объявить или использовать необходимые переменные внутри него.

public class MainActivity extends AppCompatActivity {

    public TextView infoView = (TextView) findViewById(R.id.infoView);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        new sshConnectTask().execute();
    }

    static class sshConnectTask extends AsyncTask<Void, Void, Void> {

        protected Void doInBackground(Void...params){
            /*STUFF*/
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            infoView.setText("ASD");
        }
    }
}

В основном я хотел бы вызвать infoView.setText () внутри метода onPostExecute.

ОБНОВЛЕНИЕ Кто-то из Discord помог мне исправить это:

  1. setContentView должен быть вызван перед findViewByID;в противном случае findViewById просто возвращает mull

  2. переменная infoView может быть передана в SSHConnectTask как

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView infoView = (TextView) findViewById(R.id.infoView);
        new SSHConnectTask(infoView).execute();
    }
    
  3. Затем SSHConnectTask должен быть адаптирован

    static class SSHConnectTask extends AsyncTask<Void, Void, Void> {
        private TextView display;
    
        public SSHConnectTask(TextView display){
            this.display = display;
        }
    

После этого текст infoViews может быть установлен в onPostExecute с помощью

protected void onPostExecute(Void aVoid) {
    super.onPostExecute(aVoid);
    display.setText("TEST");

Ответы [ 4 ]

0 голосов
/ 17 мая 2018

Вы можете удалить статическое ключевое слово from из AsyncTask, но тогда вы получите предупреждение, что это может привести к утечке. Утечка может произойти, если действие будет уничтожено во время выполнения задачи, так как нестатический внутренний класс содержит ссылку на включающий его класс. В качестве альтернативы, вы можете попробовать передать текстовое представление AsyncTask следующим образом:

public class MainActivity extends AppCompatActivity {

private TextView infoView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    infoView = findViewById(R.id.infoView);
    new sshConnectTask(infoView).execute();
}

static class sshConnectTask extends AsyncTask<Void, Void, Void> {
    WeakReference<TextView> weakTextView;

    sshConnectTask(TextView view){
        weakTextView = new WeakReference<>(view);
    }

    protected Void doInBackground(Void...params){
        /*STUFF*/
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
        TextView infoText = weakTextView.get();
        if(infoText != null) {
            infoText.setText("ASD");
        }
    }
}

}

0 голосов
/ 17 мая 2018

Нет никакой гарантии, что TextView будет по-прежнему живым (не будет собирать мусор), когда AsyncTask завершит выполнение своей фоновой задачи.

Я думаю, что вам следует создать интерфейс, называемый чем-то вроде ResultListener, и сделатьВаша деятельность реализует это.Затем при создании AsyncTask передайте свою активность (this) в конструктор задачи Async, но сохраните ее как WeakReference .

public interface ResultListener<T> {
    setResult(T result);
}

public class MainActivity extends AppCompatActivity implements ResultListener<String> {

    @Override
    public void setResult(String result) {
         infoView.setText(result);
    }

    public TextView infoView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        infoView = (TextView) findViewById(R.id.infoView);
        new sshConnectTask(this).execute();
    }

    static class sshConnectTask extends AsyncTask<Void, Void, String> {
        private WeakReference<ResultListener> listener;
        public sshConnectTask(ResultListener resultListener) {
            listener = new WeakReference<>(resultListener);
        }

        ...

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            ResultListener listener = this.listener.get();
            if (listener != null) {
                listener.setResult(result);
            } 
        }

    }
}
0 голосов
/ 17 мая 2018

Использование WeakReference при вызове асинхронного кода - это своего рода хак, вам следует использовать компоненты архитектуры Android, выпущенные в прошлом году (2017), которые позволяют упростить подобные вещи.

Итак, у вас естьдействие, которое наблюдает за данными в модели представления:

public class MainActivity extends AppCompatActivity {
    private TextView infoView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        infoView = findViewById(R.id.infoView);
        MainViewModel mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
        mainViewModel.infoText.observe(this, (text) -> {
            infoView.setText(text);
        });
    }
}

И вы должны создать ViewModel, где этот тип соединения обрабатывается внутри LiveData, которая хранится в ViewModel:

public class MainViewModel extends ViewModel {
    LiveData<String> infoText = new InfoTextLiveData();

    public MainViewModel() {
    }
}

Иваши LiveData должны знать, как извлечь данные:

public class InfoTextLiveData extends MutableLiveData<String> {
    @Override
    protected void onActive() {
        new SshConnectTask().execute(); // optionally, you could `cancel()` the asyncTask in `onInactive()`
    }

    class SshConnectTask extends AsyncTask<Void, Void, Void> {
        protected Void doInBackground(Void...params){
            /*STUFF*/
            postValue("ASD");
            return null;
        }
    }
}

Для этого вам нужно добавить зависимости AAC:

allprojects {
    repositories {
        jcenter()
        google()
    }
}

и

implementation "android.arch.lifecycle:extensions:1.1.1"
annotationProcessor "android.arch.lifecycle:compiler:1.1.1"

Подробнее см. В руководстве:

https://developer.android.com/jetpack/docs/guide

0 голосов
/ 17 мая 2018

сначала объявляем TextView infoView как переменную класса, а не как переменную метода.
Во-вторых, я очень сомневаюсь, что статический класс может обращаться к переменным экземпляра, поскольку может быть два экземпляра MainActivity, поэтому также будет два infoView.
Вам нужно либо сделать infoView статическим, либо удалить статическое из sshConnectTask

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