9 Nisan 2018 Pazartesi

AsyncTask Sınıfı

Giriş
Şu satırı dahil ederiz.
import android.os.AsyncTask;
Açıklaması şöyle
AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.
AsyncTask bazı sıkıntılara sahip. Açıklaması şöyle
Long running tasks,
Having poorly being tied to Activity life cycle,
Device orientation problems, and
Memory leaks and so on.
Long Running Task Problemi
Açıklaması şöyle.
In most scenarios AsyncTask should suffice the requirement. However there are scenarios where AsyncTask can't be used. ie AsyncTask manages a thread pool, from which it pulls the threads to be used by task instances. Now the thread pools assume that they'll get their threads back after a reasonable period of time. So in a scenario where you do not know how long you'll need the thread you can't use an AsyncTask. And as of Android 4.4 , the size of thread pool can grow only to : (no of CPU cores * 2) + 1. So on a dual core processor, the maximum number of threads you can create is limited to 5.
Memory Leak Problemi
Açıklaması şöyle.
Normally when the orientation changes, Android framework destroys the activity (garbage collects the memory allocated) and creates a new one.

Now say you are running an AsyncTask which holds a reference to an Activity class object and the orientation changes. Here, Android framework would not be able to destroy the activity (as it is still referenced by your AsyncTask) while a new one will be created in its place. This is one of the ways how memory leaks happen.
Diğer Seçenekler
AsyncTask yerine şunlar kullanılabilir.
Handler
Runnable
Loader

Tanımlama
AsyncTask sınıfı şöyle bir iskelete sahiptir.
public abstract class AsyncTask<Params, Progress, Result> 
1. İlk generic parametre Params'tır. Task'ı çalıştırmak için gereken parametreyi belirtir.
2. İkinci generic parametre Progress'tir. onProgressUpdate() metoduna geçilecek parametre tipini belirtir.
3. Üçüncü generic parametre Result tipidir. doInBackground'un döndüreceği nesne tipini belirtir. Bu nesne tipi onPostExecute() metoduna sonuç olarak verilen nesnedir.
public class MyTask extends AsyncTask<String, String, String> {
  @Override
  protected void onPreExecute() {
    super.onPreExecute();
    ...
  }
  @Override
  protected String doInBackground(String... strings) {
    return ...;
  }
  @Override
  protected void onPostExecute(String Result) {
    super.onPostExecute(Result);
      ...
    }
}
cancel metodu
Activity içinde durdurmak için şöyle yaparız.
public void onPause() {
  super.onPause();
  myTask.cancel(true);
}
doInBackGround metodu
Metodun imzası şöyle
@Override
protected Void doInBackground(String... arg) {...}
Arka planda yapılması istenen iş burada kodlanır. Örneğin ağdan bir şeyler yüklemek için kullanılabilir.

execute metodu
Task'ı başlatır.
Örnek
Şöyle yaparız.
movieTask.execute("");
Örnek
doInBackGround metoduna paretre geçmek için şöyle yaparız.
myTask.execute("abc", "10", "Hello world");
Örnek
Activity içinde devam etmek için şöyle yaparız.
public void onResume() {
  super.onResume();
  myTask.execute(null);
}
executeOnExecutor metodu
Şöyle yaparız.
if (Build.VERSION.SDK_INT >= 11)
  task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
get metodu
Açıklaması şöyle.
Waits if necessary for the computation to complete, and then retrieves its result.
Task bitinceye kadar çağıran kod bloke olur.
Örnek
Şöyle yaparız.
String serverResponse = myTask.execute(...).get();
Örnek
Sınıfımızın String döndüğünü varsayarsak ve exceptionları da dikkate alırsak şöyle yaparız.
MyTask task = new MyTask();
String result = null;

try {
  result = task.execute("...").get();

  Log.i("Contents of the url:", result);

}
catch (InterruptedException e) {
  ...
}
catch (ExecutionException e) {
  ...
}
isCancelled metodu
doInBackGround içinde şöyle yaparız.
while (!isCancelled()) {
  ...
}
onPreExecute -  GUI güncellenebilir
İmzası şöyle
@Override
protected void onPreExecute() {...}
onProgressUpdate metodu - GUI güncellenebilir
onProgressUpdate () için doInBackGround() içinde publishProgress() çağrılır. Şöyle yaparız.
public class MyTask extends AsyncTask<String, Void, String> {

  @Override
  protected String doInBackground(String... params) {
    while(...){
      publishProgress();
    }
    return "done";
  }

  @Override
  protected void onProgressUpdate(Void... values) {
    super.onProgressUpdate(values);

    textView.setText("...");    
  }
}
onPostExecute metodu - GUI güncellenebilir
İmzası şöyle
@Override
protected void onPostExecute(String s) {...}
Mesela iş bitince başka bir iş başlatılabilir.


4 Nisan 2018 Çarşamba

Service Sınıfı

Giriş
İki çeşit servis var. İlki bound service. Bu servis tipi tüm bağlanan istemciler sonlanınca işletim sistemi tarafından yok edilir. İkincisi ise istemciye bağlı olmayan klasik servis tipi.

Servis Başlatmak ve Durdurma
Kendi servisimi başlatmak için şöyle yaparız.
Context context = ...
Intent startServiceIntent = new Intent(context, MyService.class);
context.startService(startServiceIntent);
Durdurmak için şöyle yaparız.
context.stopService(new Intent(mContext,MyService.class));
Bir başka servisi başlatmak için şöyle yaparız
Intent intent = new Intent();
String pkg = currentService.service.getPackageName();
String cls = pkg + "." + currentService.service.getClassName();
intent.setComponent(new ComponentName(pkg, cls));
context.startService(intent);
IntentFilter ile Servis Başlatmak ve Durdurma
Service sınıfını içine şöyle bir değişken tanımlarız.
public static final String ServiceIntent = "custom.MY_SERVICE"
Servisi şöyle tanımlarız.
<service android:name=".services.MyService" android:enabled="true">
  <intent-filter android:label="@string/myService" >
    <action   android:name="custom.MY_SERVICE"/>
  </intent-filter>
</service>
Daha sonra servisi şöyle başlatıp durdurabiliriz.
startService(new Intent(MyService.ServiceIntent));
stopService(new Intent((MyService.ServiceIntent));
Manifest XML
name tag için şöyle yaparız.
<service
  android:name=".MyService"
  android:enabled="true"
  android:exported="true" />
process tag için şöyle yaparız. Böylece service başka bir process içinde çalışır.
<service
  android:name=".MyService"
  android:enabled="true"
  android:process=":my_process" />
stopWithTask tag için şöyle yaparız.
<service
  android:name=".ServiceTest"
  android:stopWithTask="true" />
Şöyle yaparız.
<service android:name=".MyService"
        android:label="MyService"
        android:stopWithTask="false"
        android:enabled="true"
        android:exported="true"
        />
Servis iskeleti
Şuna benzer
public class MyService extends Service {

  @Override
  public IBinder onBind(Intent intent) {
    return null;
  }

  @Override
  public void onCreate() {
    super.onCreate();
  }

  @Override
  public void onDestroy() {
    super.onDestroy();
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {

    return START_STICKY;
  }
}
OnBind metodu
Şöyle yaparız.
@Nullable
@Override
public IBinder onBind(Intent intent) {
  return null;
}
OnCreate metodu
Servis içinde yaratılması gereken kaynak yaratılır. Şöyle yaparız.
public class MyService extends Service {

  Handler mHandler;

  @Override
  public void onCreate() {
    super.onCreate();
    mHandler = new Handler();
  }
  ...
}
OnStart metodu
API 5'ten itibaren OnStartCommand kullanılmalı. Şöyle yaparız.
@Override
public void onStart(Intent intent, int startId) {
  super.onStart(intent, startId);
  ...
}
OnStart metodu - Sticky Servis
Normalde servisler işletim sistemi tarafından askıya alınırlar (suspend). Hiç askıya alınmayan servis şöyle başlatılır
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
  handleCommand(intent);
  // We want this service to continue running until it is explicitly
  // stopped, so return sticky.
  return START_STICKY;
}
OnStart metodu - Sticky Olmaya Servis
Şöyle yaparız.
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
  return START_NOT_STICKY;
}
OnTaskRemoved metodu
Açıklaması şöyle. Servis'in ait olduğu uygulama arka plandayken kullanıcı tarafından öldürülürse çağrılır.
This is called if the service is currently running and the user has removed a task that comes from the service's application.
İmzası şöyle.
@Override
public void onTaskRemoved(Intent rootIntent);