Buy Me A Coffee!

GoPay
Showing posts with label Teroka Diary. Show all posts
Showing posts with label Teroka Diary. Show all posts

Sunday, June 2, 2013

Teroka ganti jadi Thread+Runnable di Android

Bener kan, banyak hal yang aneh-aneh kalau nggak pake Framework...

Awalnya

Beberapa waktu yang lalu Teroka menggunakan Asyntask. Kata Pak Yudi Asyntask gunanya untuk loading yang sebentar-sebentar, misalnya loading data dari internet, setelah itu tasknya diputus.
Saat praktikum kami diajarkan untuk menggunakan Asyntask untuk animasi sederhana, gambar android gerak dari kiri ke kanan, animasi hanya dilakukan dengan looping sebanyak 50 kali. Lain halnya dengan Teroka, animasi akan dilakukan terus-menerus sampai aplikasinya ditutup. Nah ini yang jadi masalah.

Anehnya Error

Dengan Asyntask kurang tahu kenapa kadang animasinya jalan, kadang nggak. Waktu sedang mengerjakan Teroka anehnya Asyntask juga nggak bisa di-cancel. Setiap dilakukan Asyntask.cancel(true) muncul error seperti ini

05-31 15:25:48.750: W/System.err(18305): java.lang.InterruptedException
05-31 15:25:48.800: W/System.err(18305):   at java.lang.VMThread.sleep(Native Method)
05-31 15:25:48.800: W/System.err(18305):  at java.lang.Thread.sleep(Thread.java:1031)
05-31 15:25:48.810: W/System.err(18305):  at java.lang.Thread.sleep(Thread.java:1013)
05-31 15:25:48.810: W/System.err(18305):  at com.tanyoo.teroka.AnimasiTask.doInBackground(AnimasiTask.java:27)
05-31 15:25:48.810: W/System.err(18305):  at com.tanyoo.teroka.AnimasiTask.doInBackground(AnimasiTask.java:1)
05-31 15:25:48.810: W/System.err(18305):  at android.os.AsyncTask$2.call(AsyncTask.java:264)
05-31 15:25:48.810: W/System.err(18305):  at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
05-31 15:25:48.820: W/System.err(18305):  at java.util.concurrent.FutureTask.run(FutureTask.java:137)
05-31 15:25:48.820: W/System.err(18305):  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
05-31 15:25:48.830: W/System.err(18305):  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
05-31 15:25:48.830: W/System.err(18305):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
05-31 15:25:48.830: W/System.err(18305):  at java.lang.Thread.run(Thread.java:856)

Hoh.. nggak tahu deh kenapa.

Thread + Runnable, tapi Draw lama

Setelah konsultasi dengan dosen saya, ternyata memang tidak bisa dengan AsynTask, akhirnya menggunakan primitif Thread.

Yang aneh itu drawing pada Thread ternyata agak lama, dan telat juga. Gawat kalau mau draw banyak bitmap, bisa-bisa gagal gara-gara Bitmapnya belum nyampe (akhirnya jadi NULL)

Solusinya adalah dengan menggunakan status bitmap sudah di load baru kemudian digambar.

Bitmap selama ini saya load di onWindowFocusChanged, jadi ada status yang namanya ready untuk menyatakan gambar sudah di proses dan di load dulu.

Coba lihat contoh di Help ini:



        @Override
 public void onWindowFocusChanged(boolean hasWindowFocus) {
  // TODO Auto-generated method stub
  super.onWindowFocusChanged(hasWindowFocus);
  
  // resize gambar
  elogo.resizeImage((int)getPercentWidth(65), (int)getPercentHeight(19));
  ePreviewGame.resizeImage((int)getPercentWidth(100), (int)getPercentHeight(56));
  eButtonStatistik.EbuttonStat((int)getPercentWidth(42), (int)getPercentHeight(10));
  eBackground.resizeImage((int)getPercentWidth(100),(int)getPercentHeight(100));
  
  //set posisi
  elogo.setPosition(getPercentWidth(17), getPercentHeight(2));
  ePreviewGame.setPosition(getPercentWidth(0), getPercentHeight(25));
  eButtonStatistik.setPosition(getPercentWidth(29), getPercentHeight(88));
  eBackground.setPosition(getPercentWidth(0), getPercentHeight(0));
  
  ready = true;
 }
 
Di paling akhir ada variabel ready kan? Nah itu dipanggil ketika thread berjalan. Ini yang saya lakukan ketika draw


 public void doDraw(Canvas c){
  if (c != null) {
   //clear screen
   c.drawColor(Color.WHITE);
   
   if (gameView.getReady()) {
    gameView.draw(c, cat);
   }
  }
 }

Lihat, pertama-tama dicek dulu apakah ready == true (saya lakukan dengan methode getReady), baru digambar.

Tapi ini masih ngelag

Lucu juga ketika tombol dipencet dia loading beberapa saat dulu baru keload gambarnya. Tapi lumayan lah, dan saat-saat menunggu tadi bisa diganti jadi loading, tapi yang penting sekarang itu fungsional dulu lah ya.

Masih ada error yang saya temui sekarang, kalau dari satu activity, ke activity lain, kemudian orientasi berubah, dan kembali ke activity sebelumnya  kadang jadi error. Sepertinya letak untuk ready ada di salah satu state activity yang harus di handle.

Bagi kamu yang mau ngikutin kode yang saya, @ratihvuzy, @ndaindana, @yolahoshi, dan @rewingw buat bisa lihat di http://github.com/igrir/teroka :D

Oh tidak! Sudah tanggal 2! Sudah molor ini, harus bikin gamenya! Aaak!!

Wish us luck!

p.s: Tablet saya nggak mau ngecas kalo lagi jalan aplikasi dan dicoloknya di komputer. Kurang voltase kayaknya.

Saturday, June 1, 2013

Foto dulu ah~

Development di Galaxy Tab lebih cepat pas deploying ternyata. Nggak tahu kenapa, mungkin Xperia Tipo saya sudah terlalu banyak memory... atau prosesornya lebih rendah daripada Tab.


Android Out Of Memory Setelah Memanggil Bitmap

Akhirnya kami bisa juga bikin tampilannya dengan klik tombol dan berpindah layar. Layouting juga bisa dipakai, dan yang lebih maknyusnya, layoutnya responsif berdasarkan besar layar. Pertanyaan intermezzo, kenapa nggak pake framework/engine game? Aih, sudah terlanjur terkerjakan. Maybe later... heheh.. Tapi karena nggak pake engine game yang sudah ada, pastinya harus main-main di cara ngerender gambarnya. Ini merepotkan.
Tadaaaa~~ Layoutnya. Warnanya merah nyeremin kata @ndaindana. Hehe, ini cuman buat nyobain ngetest "jalan" aja sebenarnya, kalo warnanya putih pas ngetest suka disangka nge-hang

Masalah

Setelah mengerti cara membuat view dengan framework-framework-an yang kami bikin, kemudian kami membagi tugas untuk membuat tampilan (view) masing-masing. Hasilnya jadi dan sesuai yang diharapkan. Tapi ternyata ketika saya menekan tombol game dan kembali, berulang-ulang, dapatnya Out Of Memory!

Ah~ Menyebalkan deh kalau hubungannya sama memory. Berarti harus optimasi.

Setelah membaca beberapa artikel dan diskusi stackoverflow, ternyata bitmap dalam Android memang ribet dan bermasalah.

Beberapa link artikel setelah beberapa waktu di-Googling:
http://stackoverflow.com/questions/11201502/clean-memory-in-android/11201652#11201652
http://ttlnews.blogspot.com/2010/01/attacking-memory-problems-on-android.html
http://blog.pseudoblue.com/2010/08/15/android-bitmaps-and-memory-leaks/

Katanya Bitmap dalam Android berada di bagian dari aplikasi yang tidak disentuh oleh Garbage Collector (GC), akhirnya memori bertambah terus karena saya panggil di onCreate.

Solusi

Untuk itu solusinya pada proyek ini adalah dengan melakukan bmp.recycle() DI SETIAP bitmap yang digunakan agar bisa "disentuh" oleh GC. Karena repot jika harus melakukan blablabla.recycle() di setiap Entity yang dibuat, maka saya sudah membuatkan method khusus di dalam GameView, jadi tinggal pakai. Sekalian aja supaya kegiatan yang selama ini dilakukan berulang terhadap Entity digabungkan. Jadi bersiaplah dengan.... jreng jeng jeng... EntityCollection!

Cara Pakai Method Baru

1. addEntity
Method ini menambahkan entity apa saja yang ada dalam view. Jadi semua entity yang dipakai HARUS DIMASUKKAN ke dalam addEntity ini.

ini contoh yang digunakan dalam view Petualangan
 
  einfo = new EInfobar(getResources());
  ebardistance = new EBarDistance(getResources());
  edistance = new EDistance(getResources());
  ehealthpoint = new EHealthPoint(getResources());
  ebarhealth = new EBarHealth(getResources());
  egameview = new EGameView(getResources());
  estars = new EStars(getResources());
  esteps = new ESteps(getResources());
  eshop = new EShop(getResources());
  epotion = new EPotion(getResources());
  elevel = new ELevel(getResources());
  ecalore = new ECalore(getResources());
  
  addEntity(einfo, ebardistance, edistance,
     ehealthpoint, ebarhealth, egameview,
     estars, esteps, eshop, epotion, elevel, ecalore);

Nah perhatikan, setiap Entity dideklarasikan satu-persatu, kemudian akhirnya dimasukkan di dalam addEntity dan setiap variabelnya dipisahkan dengan koma.


2. drawEntityCollection
Method ini menggambarkan entity-entity yang sudah dimasukkan ke dalam  EntityCollection dari method addEntity di atas. Perhatikan contoh berikut. Kode ini berada dalam method onDraw yang ada dalam view:
  //  einfo.draw(c, cat);
  //  egameview.draw(c, cat);
  //  edistance.draw(c, cat);
  //  ehealthpoint.draw(c, cat);
  //  ebardistance.draw(c, cat);
  //  ebarhealth.draw(c, cat);
  //  estars.draw(c, cat);
  //  esteps.draw(c, cat);
  //  eshop.draw(c, cat);
  //  ecalore.draw(c, cat);
  //  epotion.draw(c, cat);
  //  elevel.draw(c, cat);
  drawEntityCollection(c, cat);

lihat, awalnya kita menggunakan einfo.draw(c,cat) dsb dsb dsb (yang diberi komentar). Sekarang cukup panggil drawEntityCollection(c,cat);

ingat, kamu harus memasukkan ke dalam EntityCollection apa saja entity yang akan didraw

3. RecycleEntityCollection
Nah, method ini yang mengembalikan agar memori bisa dipakai.
Method ini ditaruh di dalam kelas Activity dan ditaruh dalam method onStop. Perhatikan contoh berikut:

 @Override
 protected void onStop() {
  // TODO Auto-generated method stub
  super.onStop();
  
//  mu.ebardistance.recycle();  
//  mu.einfo.recycle();
//  mu.ebardistance.recycle();
//  mu.edistance.recycle();
//  mu.ehealthpoint.recycle();
//  mu.ebarhealth.recycle();
//  mu.egameview.recycle();
//  mu.estars.recycle();
//  mu.esteps.recycle();
//  mu.eshop.recycle();
//  mu.epotion.recycle();
//  mu.elevel.recycle();
//  mu.ecalore.recycle();
  //membebaskan memori
  mu.recycleEntityCollection();
 }
 
awalnya untuk melakukan recycle harus memanggil entity-entity yang ada di dalam view dan dipanggil recycle. Sekarang tinggal panggil mu.recycleEntityCollection(). mu adalah nama view yang digunakan oleh activity ini.

Kesimpulan

Jadi jangan lupa kalau mau bikin view yang ada entity-nya harus:
  1. Buat kelas entitynya
  2. Pastikan entity sudah memanggil resource
  3. Instansiasi entitynya di dalam View
  4. Masukkan entity-entity yang digunakan ke dalam EntityCollection di konstruktor menggunakan addEntity
  5. Draw dengan drawEntityCollection pada method onDraw
  6. Pada Activity, buat method yang Override onStop, panggil viewnya.recycleEntityCollection() agar tidak OutOfMemory
Sekian! Merepotkan juga ya? But it was a great fun coding journey though, hehe :D.

p.s: sekarang masih bermasalah dengan Thread nih, hm... selesaikan tampilan dulu lah ya~ Sudah deadline soalnya

Thursday, May 30, 2013

Teroka Diary: Struktur Kelas Teroka

Dalam development Teroka, package nya dibagi sebagai berikut

Packagenya terdiri dari:

  1. teroka
  2. activities
  3. entities
  4. lib
  5. view


AnimasiTask
Adalah kelas Task, gunanya untuk menjalankan thread, misalnya untuk game loop

AboutActivity dan MainActivity adalah activity apa saja yang ada dalam aplikasi, intinya adalah menu-menu apa saja yang ditampilkan dalam activity ini.

Activity-activity tadi semacam controller, sedangkan View nya ada di package view, yaitu About  dan MenuUtama.

Entities adalah package yang berisi benda-benda/objek yang dimasukkan dalam game, misalnya tombol, gambar karakter, dan sebagainya

Package Lib berisi library yang digunakan dalam game. Misalnya GameView merupakan superclass dari view-view yang ada, Entity merupakan superclass dari objek-objek yang ada dalam Entities