2012-03-30 5 views
0

Я пытаюсь передать свой фрагмент в класс 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 на экране, чтобы уточнить, будет ли логин успешным или неудачным: как сейчас, у пользователя нет способа сообщить, как логин прошел. Идеи?

ответ

4

Как любопытно говорит, что вы не хотите, чтобы прохождение фрагментов вокруг (у них есть «связь» к деятельности, которая является контекстом и контекстами прохождения является baaad)

Вы хотите пройти небольшой объект, который может помочь вам перезвонить из вашей задачи в ваш фрагмент.

Я бы также использовал интерфейс. Вот мой пример:

Фрагмент:

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(); 
    } 

} 

Если вы получите ваши головы вокруг интерфейсов ваш мир будет открыть и ваш код будет выглядеть менее, как джунгли Амазонки и больше похоже на хорошо организованный сад ;-)

+0

Мне нравится это лучше, так как он «ближе» к Android-вещам (в частности, к шаблону Listener). На практике я использовал абстрактные базовые классы вместо интерфейса, поскольку методы обратного вызова часто имеют некоторые реализации по умолчанию. – curioustechizen

1

Я предлагаю вам использовать интерфейс обратного вызова для этой цели. Как правило, не рекомендуется передавать объекты, специфичные для UI (фактически, контекстно-зависимые), для 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(); 
      } 
     } 
    } 
} 
+0

О, боже, я никогда не делал интерфейс раньше. Я не буду пытаться сделать это сегодня вечером (это 3 часа!), Но когда я приступлю завтра, я рассмотрю это решение и проголосую/отметю как ответ, если он работает по мере необходимости. Благодаря! – Davek804

+0

Я бы определил интерфейс внутри ASyncTask и либо проверил его для null, либо объявил его окончательным, чтобы убедиться, что он создан. – Blundell

+0

@Blundell Конечно. Как я уже сказал, этот код не на 100% - просто directio :). Есть много других вещей, которые нужно позаботиться - например, показать этот диалог, только если он еще не запущен и т. Д. И т. Д. – curioustechizen

Смежные вопросы