Можно ли передать фрагмент в конструкторе?
Я пытаюсь передать свой фрагмент в класс ASyncTask, чтобы я мог обновить один или два виджета во фрагменте после завершения задачи. Вот с чем я имею дело:
public class LoginFragment extends Fragment {
Button loginButton;
TextView loginErrorMsg;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.loginfragment, container, false);
}
public OnClickListener loginListener = new OnClickListener() {
@Override
public void onClick(View v) {
Log.v("LoginF", "onclick");
ProgressDialog progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage("Logging in...");
LoginTask loginTask = new LoginTask((Polling) getActivity(), progressDialog);
loginTask.execute();
}
};
И LoginTask:
public class LoginTask extends AsyncTask<String, Void, Integer> {
private ProgressDialog progressDialog;
private Polling activity;
private int id = -1;
private JSONParser jsonParser;
private static String loginURL = "http://davidjkelley.net/android_api/";
private static String registerURL = "http://davidjkelley.net/android_api/";
private static String KEY_SUCCESS = "success";
private static String KEY_ERROR = "error";
private static String KEY_ERROR_MSG = "error_msg";
private static String KEY_UID = "uid";
private static String KEY_NAME = "name";
private static String KEY_EMAIL = "email";
private static String KEY_CREATED_AT = "created_at";
TextView loginErrorMsg = (EditText)activity.findViewById(R.id.loginErrorMsg);
EditText userName = (EditText)activity.findViewById(R.id.emailEditText);
EditText passwordEdit = (EditText)activity.findViewById(R.id.passEditText);
public LoginTask(Polling activity, ProgressDialog progressDialog)
{
this.activity = activity;
this.progressDialog = progressDialog;
}
Поэтому я хотел бы добавить третий параметр в конструктор LoginTask, по сути, экземпляр моего LoginFragment. Моя цель состоит в том, чтобы обновить либо TextView, либо поставить Toast на экране, чтобы уточнить, будет ли вход успешным или неудачным: как сейчас, у пользователя нет возможности рассказать, как проходил вход в систему. Идеи?
2 ответа
Как любопытно, вы не хотите передавать фрагменты (у них есть "связь" с действием, которое является контекстом, а передача контекстов - бааадом)
Вы хотите передать небольшой объект, который может помочь вам перезвонить от вашей Задачи к вашему Фрагменту.
Я бы тоже использовал интерфейс. Вот мой пример:
Фрагмент:
public class LoginFragment extends Fragment implements OnClickListener, OnLoginListener{
Button loginButton;
TextView loginErrorMsg;
private ProgressDialog progressDialog;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
progressDialog = new ProgressDialog(activity);
progressDialog.setMessage("Logging in...");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_login, container, false);
loginButton = v.findViewById(R.id.button);
loginButton.setOnClickListener(this);
return v;
}
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.button:
Log.v("LoginF", "onclick");
progressDialog.show();
LoginTask loginTask = new LoginTask(this);
loginTask.execute();
break;
default:
break;
}
}
@Override
public void onLoginSuccess() {
progressDialog.dismiss();
// Yayy
}
@Override
public void onLoginFailure() {
progressDialog.dismiss();
// Boo
}
}
ASyncTask:
public class LoginTask extends AsyncTask<String, Void, Integer> {
private final OnLoginListener listener;
public interface OnLoginListener{
public void onLoginSuccess();
public void onLoginFailure();
}
public LoginTask(OnLoginListener listener) {
this.listener = listener;
}
@Override
protected Integer doInBackground(String... params) {
try{
// Something
} catch (SomeException e){
listener.onLoginFailure();
}
return null;
}
@Override
protected void onPostExecute(Integer result) {
super.onPostExecute(result);
listener.onLoginSuccess();
}
}
Если вы разберетесь с интерфейсами, ваш мир откроется, и ваш код будет выглядеть не так, как джунгли амазонки, а скорее как хорошо организованный сад;-)
Я предлагаю вам использовать интерфейс обратного вызова для этой цели. Как правило, не рекомендуется передавать объекты, специфичные для пользовательского интерфейса (на самом деле, для конкретного контекста), в AsyncTask.
Вот что я предлагаю. При таком подходе вам даже не нужно передавать Fragment
вокруг.
Отказ от ответственности: я на самом деле не пробовал запускать этот код - просто набрал его у меня на голове. Так что он может даже не скомпилироваться - он просто предназначен для руководства.
interface LoginCallback{
void onLoginSuccess();
void onLoginFailure();
}
//onCreate code
TextView loginErrorMsg = (EditText)activity.findViewById(R.id.loginErrorMsg);
EditText userName = (EditText)activity.findViewById(R.id.emailEditText);
EditText passwordEdit = (EditText)activity.findViewById(R.id.passEditText);
LoginTask loginTask = new LoginTask(new LoginCallback(){
@Override
protected void onLoginSuccess(){
//Update UI
}
@Override
protected void onLoginFailure(){
//Update UI
}
});
loginTask.execute();
//LoginTask code.
public class LoginTask extends AsyncTask<String, Void, Integer> {
LoginCallback callback;
ProgressDialog progressDialog;
public LoginTask(LoginCallback callback){
this.callback = callback;
@Override protected void onPreExecute(){
progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage("Logging in...");
}
@Override
protected Integer doInBackground(String... params){
//Do you login logic here.
}
@Override
protected void onPostExecute(Integer result) {
progressDialog.dismiss();
if(loginSuccess){
callback.onLoginSuccess();
} else {
callback.onLoginFailure();
}
}
}
}