Dnes se podíváme na to, jak dělat složitější operace ve fragmentu při které se bude volat metoda z activity. Zaměříme se na to, jak správně napsat kód aby aplikace nespadla při otočení displeje.
Jednoduchá ukázka jak to nedělat:
MainActivity.java – klasická activity, která má veřejnou metodu worker, která by v praxi vykonávala nějakou operaci. Nyní pro ukázku vypíše pouze text do logu.
package cz.vencax.mobilapp.dockstatesapplication; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void worker(String text) { Log.d("xxx", "text: " + text); } }
LoginFragment.java – jednoduchý fragment s tlačítkem. Po tapnutí na tlačítko, se spustí AsyncTask, který volá metodu worker z MainActivity
package cz.vencax.mobilapp.dockstatesapplication; import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; public class LoginFragment extends Fragment { public LoginFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment //return inflater.inflate(R.layout.fragment_login, container, false); View view = inflater.inflate(R.layout.fragment_login, container, false); Button button = (Button) view.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new LoginAndParseInspectionTask().execute(); } }); return view; } //////////////////////////////////////////////////////////////////////////////////////////////// class LoginAndParseInspectionTask extends AsyncTask<String, String, Void> { @Override protected Void doInBackground(String... strings) { for(int i = 0; i < 1000000000; i++) { ((MainActivity)getActivity()).worker("run" + i); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } return null; } } }
Pokud tento kód spustíte, zjistíte, že funguje. Bohužel po otočení displeje aplikace spadne….
Jak na to lépe?
Správná cesta je vytvoření static interface TaskCallbacks ve fragmentu, který implementujeme v activity. Metodu worker následně voláme přes mCallbacks.worker(„run“ + i);
MainActivity.java
package cz.vencax.mobilapp.dockstatesapplication; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; public class MainActivity extends AppCompatActivity implements LoginFragment.TaskCallbacks { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void worker(String text) { Log.d("xxx", "text: " + text); } }
LoginFragment.java
package cz.vencax.mobilapp.dockstatesapplication; import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; public class LoginFragment extends Fragment { static interface TaskCallbacks { void worker(String text); } private TaskCallbacks mCallbacks; public LoginFragment() { // Required empty public constructor } @Override public void onAttach(Context context) { super.onAttach(context); if (!(context instanceof TaskCallbacks)) { throw new IllegalStateException("Activity must implement the TaskCallbacks interface."); } // Hold a reference to the parent Activity so we can report back the task's // current progress and results. mCallbacks = (TaskCallbacks) context; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment //return inflater.inflate(R.layout.fragment_login, container, false); View view = inflater.inflate(R.layout.fragment_login, container, false); Button button = (Button) view.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new LoginAndParseInspectionTask().execute(); } }); return view; } class LoginAndParseInspectionTask extends AsyncTask<String, String, Void> { @Override protected Void doInBackground(String... strings) { for(int i = 0; i < 1000000000; i++) { //((MainActivity)getActivity()).worker("run" + i); mCallbacks.worker("run" + i); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } return null; } } }
Teď již při otáčení displeje není problém.