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.