Android Code Puzzles (DroidCon Amsterdam 2012)

  • 1,419 views
Uploaded on

android code puzzles presented at DroidCon Amsterdam droidcon.nl

android code puzzles presented at DroidCon Amsterdam droidcon.nl

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,419
On Slideshare
0
From Embeds
0
Number of Embeds
8

Actions

Shares
Downloads
0
Comments
0
Likes
6

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Android CodePuzzlesdroidcon.nl
  • 2. ● Danny Preussler:● Lead Engineer Androidebay Kleinanzeigen, Germany● Path to the green side:C++ -> Java SE -> JME -> BlackBerry -> Android● My current Droids:Galaxy Nexus, Nexus 7, Logitech Revue, Im watch● My 1st Droid was a:Motorola Droid/Milestone● Johannes Orgis:● Software Development ManagerCortado Mobile ClientsCortado AG, Germany● Path to the green side:Java EE -> Java SE -> BlackBerry -> Android● My current Droids:Galaxy Nexus, Nexus 7● My 1st Droid was a:HTC Magic
  • 3. ● We show code snippets that does something or maybe not● Look out for hidden pitfalls● All Puzzles are run with Android 4.1 Jelly BeansThere should be no platform depended puzzles● Test yourself!● Raise your hands when we ask you!● Guess if youre unsure!● Learn something if you were wrong!● Have fun! :D
  • 4. public class DroidConPuzzle extends Activity {@Overrideprotected void onCreate(Bundle saved) {FragmentTransaction trans = getFragmentManager().beginTransaction();trans.add(android.R.id.content, new Fragment() {@Overridepublic View onCreateView(LayoutInflater inf,ViewGroup view, Bundle saved){View v = inf.inflate(R.layout.fragment_default, null);return null;}});trans.commit();super.onCreate(saved);}}For your eyes only...a) NullPointerException in Inflater.inflate()b) NullPointerException after onCreateView()c) llegalStateException in super.onCreate()d) llegalStateException in Transaction.commit()e) shows an empty screen
  • 5. public class DroidConPuzzle extends Activity {@Overrideprotected void onCreate(Bundle saved) {FragmentTransaction trans = getFragmentManager().beginTransaction();trans.add(android.R.id.content, new Fragment() {@Overridepublic View onCreateView(LayoutInflater inf,ViewGroup view, Bundle saved){View v = inf.inflate(R.layout.fragment_default, null);return null;}});trans.commit();super.onCreate(saved);}}For your eyes only...a) NullPointerException in Inflater.inflate()b) NullPointerException after onCreateView()c) llegalStateException in super.onCreate()d) llegalStateException in Transaction.commit()e) shows an empty screen
  • 6. public class DroidConPuzzle extends Activity {@Overrideprotected void onCreate(Bundle saved) {FragmentTransaction trans = getFragmentManager().beginTransaction();trans.add(android.R.id.content, new Fragment() {@Overridepublic View onCreateView(LayoutInflater inf,ViewGroup view, Bundle saved){View v = inf.inflate(R.layout.fragment_default, null);return null;}});trans.commit();super.onCreate(saved);}}For your eyes only...e) shows an empty screen BUT after rotation it will crash:
  • 7. ● Fragments need to be public:not possible as inner or anonymous class● Fragments must have a public emptyconstructor● RTFW: read the fucking warnings:●
  • 8. <Button ... android:onClick="clicked" />public class OnClickToastFragment extends Fragment {...public void clicked(View v){Toast.makeText(getActivity(),getClass().getName(),Toast.LENGTH_SHORT).show();}}public class OnClickToastFragmentActivity extends FragmentActivity{public void clicked(View v){Toast.makeText(this,getClass().getName(),Toast.LENGTH_SHORT).show();}}public class MyMainActivity extends Activity{public void clicked(View v){Toast.makeText(this,getClass().getName(),Toast.LENGTH_SHORT).show();}}Licence to clickWhat happens when I click the Button?a) Toast : MyMainActivityb) Toast : OnClickToastFragmentActivityc) Toast : OnClickToastFragmentd) Nothinge) IllegalStateException - Could not find a method ...
  • 9. <Button ... android:onClick="clicked" />public class OnClickToastFragment extends Fragment {...public void clicked(View v){Toast.makeText(getActivity(),getClass().getName(),Toast.LENGTH_SHORT).show();}}public class OnClickToastFragmentActivity extends FragmentActivity{public void clicked(View v){Toast.makeText(this,getClass().getName(),Toast.LENGTH_SHORT).show();}}public class MyMainActivity extends Activity{public void clicked(View v){Toast.makeText(this,getClass().getName(),Toast.LENGTH_SHORT).show();}}Licence to clickWhat happens when I click the Button?a) Toast : MyMainActivityb) Toast : OnClickToastFragmentActivityc) Toast : OnClickToastFragmentd) Nothinge) IllegalStateException - Could not find a method ...
  • 10. android:onClick is an easy way to trigger "click" events in xmlbut remember: the calling Activity MUST implement the xxx(Viev v) method otherwise aIllegalStateException will be thrown at runtimebe careful if you are using Fragments in multiple Activities
  • 11. Every 2.2. Device has the "unique" ANDROID_ID9774d56d682e549c ?Be aware of platform dependent puzzles....or did you know that?
  • 12. public class GetViewFragment extends Fragment {public View onCreateView(LayoutInflater inf, ViewGroup view, Bundle saved) {super.onCreateView(inf, view, saved);return inf.inflate(R.layout.fragment_get_view, view);}public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getView().setOnClickListener(new View.OnClickListener() {public void onClick(View v) {Toast.makeText(getActivity(),"My name is droid, android",Toast.LENGTH_SHORT);}});}}A View to (a) Killa) shows a Toast "my name is droid, android"b) does nothing but showing a viewc) Exception in Inflater.inflate()d) Exception in GetViewFragment.onCreate()e) Exception in Fragment.onCreateView()
  • 13. public class GetViewFragment extends Fragment {public View onCreateView(LayoutInflater inf, ViewGroup view, Bundle saved) {super.onCreateView(inf, view, saved);return inf.inflate(R.layout.fragment_get_view, view);}public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getView().setOnClickListener(new View.OnClickListener() {public void onClick(View v) {Toast.makeText(getActivity(),"My name is droid, android",Toast.LENGTH_SHORT);}});}}A View to (a) Killa) shows a Toast "my name is droid, android"b) does nothing but showing a viewc) Exception in Inflater.inflate()d) Exception in GetViewFragment.onCreate()e) Exception in Fragment.onCreateView()
  • 14. public class GetViewFragment extends Fragment {public View onCreateView(LayoutInflater inf, ViewGroup view, Bundle saved) {super.onCreateView(inf, view, saved);return inf.inflate(R.layout.fragment_get_view, view);}public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getView().setOnClickListener(new View.OnClickListener() {public void onClick(View v) {Toast.makeText(getActivity(),"My name is droid, android",Toast.LENGTH_SHORT);}});}}A View to (a) Killa) shows a Toast "my name is droid, android"b) does nothing but showing a viewc) Exception in Inflater.inflate() (2nd winner)d) Exception in GetViewFragment.onCreateView()e) Exception in Fragment.onCreateView()
  • 15. ● Know about the life cycle of Activities,Fragments, Services!● Example: methods asgetView() or getActivity() can return null incertain points of their life cycle!
  • 16. public class ToastFragment extends Fragment {...public void onDestroy() {super.onDestroy();new ToastingAsyncTask().execute(null,null,null);}class ToastingAsyncTask extends AsyncTask<String, Integer, Long>{protected void onPostExecute(Long result) {if (getActivity() == null){System.out.println(getString(R.string.no_activity));}else{System.out.println(getString(R.string.activity_leak));}}protected Long doInBackground(String... params) {try {Thread.sleep(500);} catch (InterruptedException e) {}return null;}...Live and let die ...what happens when I change the orientation of my Galaxy Nexus?a) Sysout: no_activityb) Sysout: activity_leakc) Sysout: nulld) Exception in getActivitye) Exception in getString
  • 17. public class ToastFragment extends Fragment {...public void onDestroy() {super.onDestroy();new ToastingAsyncTask().execute(null,null,null);}class ToastingAsyncTask extends AsyncTask<String, Integer, Long>{protected void onPostExecute(Long result) {if (getActivity() == null){System.out.println(getString(R.string.no_activity));}else{System.out.println(getString(R.string.activity_leak));}}protected Long doInBackground(String... params) {try {Thread.sleep(500);} catch (InterruptedException e) {}return null;}...Live and let die ...what happens when I change the orientation of my Galaxy Nexus?a) Sysout: no_activityb) Sysout: activity_leakc) Sysout: nulld) Exception in getActivitye) Exception in getString
  • 18. LogCat shows:java.lang.IllegalStateException: Fragment ToastFragment not attached to ActivityA Context holds your Resources!Know about the life cycle of Activities, Fragments,Services!!
  • 19. Until Android 4 (possible 3.x) android.app.DownloadManager only supports httpconnections:if (scheme == null || !scheme.equals("http")) {throw new IllegalArgumentException("Can only download HTTP URIs: " + uri);}Because of that the stock browser (and Chrome)could not handle https downloads.Be aware of platform dependent puzzles....or did you know that?
  • 20. public class MyListActivity extends ListActivity {public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getFromServer(getApplicationContext());}void getFromServer(Context context) {final ProgressDialog dlg = new ProgressDialog(context);dlg.show();new AsyncTask<Context, Void, ArrayAdapter>() {protected ArrayAdapter doInBackground(Context... params) {return new ArrayAdapter<String>(params[0],android.R.layout.simple_list_item_1,Arrays.asList(new String[] { "0", "0", "7" }));}protected void onPostExecute(ArrayAdapter result) {setListAdapter(result);dlg.dismiss();}}.execute(context);}...a) shows list with entries 0,0,7b) shows list with entries 0,7c) Exception in getFromServerd) Exception in doInBackgrounde) Exception in onPostExecuteTomorrow never dies...
  • 21. public class MyListActivity extends ListActivity {public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getFromServer(getApplicationContext());}void getFromServer(Context context) {final ProgressDialog dlg = new ProgressDialog(context);dlg.show();new AsyncTask<Context, Void, ArrayAdapter>() {protected ArrayAdapter doInBackground(Context... params) {return new ArrayAdapter<String>(params[0],android.R.layout.simple_list_item_1,Arrays.asList(new String[] { "0", "0", "7" }));}protected void onPostExecute(ArrayAdapter result) {setListAdapter(result);dlg.dismiss();}}.execute(context);}...a) shows list with entries 0,0,7b) shows list with entries 0,7c) Exception in getFromServerd) Exception in doInBackgrounde) Exception in onPostExecuteTomorrow never dies...
  • 22. ● Know your Context!● Never use Application Context for UI!Prefer Application Context for Non-UI!● Be aware of Context Leaks!
  • 23. public class ActionbarFragment extends Fragment {...public View onCreateView(LayoutInflater inf, ViewGroup view, Bundle saved) {setHasOptionsMenu(true);return inf.inflate(R.layout.fragment_get_view, null);}public boolean onOptionsItemSelected(MenuItem item) {Toast.makeText(getActivity(), "from Fragment", Toast.LENGTH_SHORT).show();return true;}}public class ActionbarActivity extends Activity {...public boolean onOptionsItemSelected(MenuItem item) {Toast.makeText(this, "from Activity", Toast.LENGTH_SHORT).show();return true;}}From Fragment with Love...When clicking an item from actionbar:a) shows toast: "from Activity"b) shows toast: "from Fragment"c) shows both toastsd) shows toast depending on who the creator of the menu item
  • 24. public class ActionbarFragment extends Fragment {...public View onCreateView(LayoutInflater inf, ViewGroup view, Bundle saved) {setHasOptionsMenu(true);return inf.inflate(R.layout.fragment_get_view, null);}public boolean onOptionsItemSelected(MenuItem item) {Toast.makeText(getActivity(), "from Fragment", Toast.LENGTH_SHORT).show();return true;}}public class ActionbarActivity extends Activity {...public boolean onOptionsItemSelected(MenuItem item) {Toast.makeText(this, "from Activity", Toast.LENGTH_SHORT).show();return true;}}From Fragment with Love...When clicking an item from actionbar:a) shows toast: "from Activity"b) shows toast: "from Fragment"c) shows both toastsd) shows toast depending on who the creator of the menu item
  • 25. "If you added the menu item from a fragment, then therespective onOptionsItemSelected() method is called for thatfragment.However the activity gets a chance to handle it first, so thesystem calls onOptionsItemSelected() on the activity beforecalling the fragment."● RTFJD: read the fucking java doc:
  • 26. On pre 2.3.6 Androids HttpUrlConnection is brokenas soon as the server supports more than Basic authentication ?Youll get IndexOutOfBoundsExceptionBe aware of platform dependent puzzles....or did you know that?int realm = challenge.indexOf("realm="") + 7;WWW-Authenticate: Basic realm="RealmName"WWW-Authenticate: NTLM
  • 27. protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);String[] longList = new String[1000000];Intent intent = new Intent(Intent.ACTION_SEND);intent.setType("text/plain");intent.putExtra("droidcon", longList);startActivityForResult(intent, 100);}protected void onActivityResult(int request, int result, Intent data) {super.onActivityResult(request, result, data);Log.e("droidcon", "result" + request + " " + result);}a) OutOfMemoryException in onCreate()b) IllegalArgumentException in onCreate()c) Nothing happens, direct invocation of onActivityResult (with cancel code)d) Nothing happens, no invocation of onActivityResulte) System-Intent-Picker for "sent" action will be shown normallyThe world is not enough ...
  • 28. protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);String[] longList = new String[1000000];Intent intent = new Intent(Intent.ACTION_SEND);intent.setType("text/plain");intent.putExtra("droidcon", longList);startActivityForResult(intent, 100);}protected void onActivityResult(int request, int result, Intent data) {super.onActivityResult(request, result, data);Log.e("droidcon", "result" + request + " " + result);}a) OutOfMemoryException in onCreate()b) IllegalArgumentException in onCreate()c) Nothing happens, direct invocation of onActivityResult (with cancel code)d) Nothing happens, no invocation of onActivityResulte) System-Intent-Picker for "sent" action will be shown normallyThe world is not enough ...
  • 29. Logcat shows:11-12 16:25:53.391: E/JavaBinder(6247): !!! FAILED BINDER TRANSACTION !!!Some devices show TransactionTooLargeException:The Binder transaction failed because it was too large.During a remote procedure call, the arguments and the return value of the call are transferred asParcel objects stored in the Binder transaction buffer. If the arguments or the return value are toolarge to fit in the transaction buffer, then the call will fail and TransactionTooLargeException will bethrown.The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by alltransactions in progress for the process. Consequently this exception can be thrown when there aremany transactions in progress even when most of the individual transactions are of moderate size.
  • 30. Be aware of platform dependent puzzles....or did you know that?Starting with 2.3 HTTPUrlConnection handles and sets gzip as Content-Encoding.This leads to errors if you get a response where there is no content but a Content-Length (=0) or a Content-Encoding(=gzip).getResponceCode leads to EOFException
  • 31. public class AsyncTaskActivity extends Activity{...protected void onResume() {super.onResume();TextView testV = (TextView) findViewById(R.id.async_text_1);new WritingAsyncTask(testV,2000).execute(" Bob");new WritingAsyncTask(testV,100).execute("Alice");new WritingAsyncTask(testV,500).execute("loves");}...public class WritingAsyncTask extends AsyncTask<String, Void, String>{...private final TextView view;//set in Constructorprivate final int timeout;//set in Constructorprotected String doInBackground(String... params) {try {Thread.sleep(timeout);} catch (InterruptedException e) {}return params[0];}protected void onPostExecute(String result) {view.setText(view.getText()+" "+result);}Casino RoyalWhat is shown in the TextView when I start the Activity on my Galaxy Nexus:a) Alice loves Bobb) Bob Alice lovesc) Bob loves Aliced) There is not enough information to decide
  • 32. public class AsyncTaskActivity extends Activity{...protected void onResume() {super.onResume();TextView testV = (TextView) findViewById(R.id.async_text_1);new WritingAsyncTask(testV,2000).execute(" Bob");new WritingAsyncTask(testV,100).execute("Alice");new WritingAsyncTask(testV,500).execute("loves");}...public class WritingAsyncTask extends AsyncTask<String, Void, String>{...private final TextView view;//set in Constructorprivate final int timeout;//set in Constructorprotected String doInBackground(String... params) {try {Thread.sleep(timeout);} catch (InterruptedException e) {}return params[0];}protected void onPostExecute(String result) {view.setText(view.getText()+" "+result);}Casino RoyalWhat is shown in the TextView when I start the Activity on my Galaxy Nexus:a) Alice loves Bobb) Bob Alice lovesc) Bob loves Aliced) There is not enough information to decide
  • 33. public class AsyncTaskActivity extends Activity{...protected void onResume() {super.onResume();TextView testV = (TextView) findViewById(R.id.async_text_1);new WritingAsyncTask(testV,2000).execute(" Bob");new WritingAsyncTask(testV,100).execute("Alice");new WritingAsyncTask(testV,500).execute("loves");}...public class WritingAsyncTask extends AsyncTask<String, Void, String>{...private final TextView view;//set in Constructorprivate final int timeout;//set in Constructorprotected String doInBackground(String... params) {try {Thread.sleep(timeout);} catch (InterruptedException e) {}return params[0];}protected void onPostExecute(String result) {view.setText(view.getText()+" "+result);}Casino RoyalWhat is shown in the TextView when I start the Activity on my Galaxy Nexus:a) Alice loves Bobb) Bob Alice loves .... usuallyc) Bob loves Aliced) There is not enough information to decide
  • 34. public class AsyncTaskActivity extends Activity{...protected void onResume() {super.onResume();TextView testV = (TextView) findViewById(R.id.async_text_1);new WritingAsyncTask(testV,2000).execute(" Bob");new WritingAsyncTask(testV,100).execute("Alice");new WritingAsyncTask(testV,500).execute("loves");}...public class WritingAsyncTask extends AsyncTask<String, Void, String>{...private final TextView view;//set in Constructorprivate final int timeout;//set in Constructorprotected String doInBackground(String... params) {try {Thread.sleep(timeout);} catch (InterruptedException e) {}return params[0];}protected void onPostExecute(String result) {view.setText(view.getText()+" "+result);}Casino RoyalWhat is shown in the TextView when I start the Activity on my Galaxy Nexus:a) Alice loves Bobb) Bob Alice lovesc) Bob loves Aliced) There is not enough information to decide
  • 35. You need to know the android:targetSdkVersion (and the Device Version of the Target Device)android:targetSdkVersion < 13:AsyncTask is executed parallelandroid:targetSdkVersion >= 13 && Device OS >= 14:AsyncTask is executed serialfrom AsyncTask.Java:...public static final Executor SERIAL_EXECUTOR = new SerialExecutor();private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;...You can enforce parallel execution in SDK >= 11executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,...);
  • 36. public class ManyAsyncTasksActivity extends Activity{...protected void onResume() {super.onResume();TextView testV = (TextView) findViewById(R.id.async_text_1);for (int i = 0; i < 200; i++) {new WritingAsyncTask(testV,100).execute(i+",");}}...public class WritingAsyncTask extends AsyncTask<String, Void, String>{...private final TextView view;//set in Constructorprivate final int timeout;//set in Constructorprotected String doInBackground(String... params) {try {Thread.sleep(timeout);} catch (InterruptedException e) {}return params[0];}protected void onPostExecute(String result) {view.setText(view.getText()+" "+result);}MoonrakerWhat is shown when I start the Activity on my G. Nexus (target SDK is 11, A: 4.1.2) :a) Numbers from 0 to 199 in random orderb) Application Error (App has stopped)c) Numbers from 0 to 199 in serial orderd) Numbers from 0 to 127 in random ordere) Numbers from 0 to 137 in random order
  • 37. public class ManyAsyncTasksActivity extends Activity{...protected void onResume() {super.onResume();TextView testV = (TextView) findViewById(R.id.async_text_1);for (int i = 0; i < 200; i++) {new WritingAsyncTask(testV,100).execute(i+",");}}...public class WritingAsyncTask extends AsyncTask<String, Void, String>{...private final TextView view;//set in Constructorprivate final int timeout;//set in Constructorprotected String doInBackground(String... params) {try {Thread.sleep(timeout);} catch (InterruptedException e) {}return params[0];}protected void onPostExecute(String result) {view.setText(view.getText()+" "+result);}MoonrakerWhat is shown when I start the Activity on my G. Nexus (target SDK is 11, A: 4.1.2) :a) Numbers from 0 to 199 in random orderb) Application Error (App has stopped)c) Numbers from 0 to 199 in serial orderd) Numbers from 0 to 127 in random ordere) Numbers from 0 to 137 in random order
  • 38. LogCat shows:java.lang.RuntimeException: Unable to resume activity {...}: java.util.concurrent.RejectedExecutionException: Task android.os.AsyncTask ... rejected from java.util.concurrent.ThreadPoolExecutor ... [Running, pool size = 128, active threads = 128, queued tasks = 10,completed tasks = 0]ThreadPoolExecutor currently only accepts a given number of Tasks, default value is a pool size of128.private static final int MAXIMUM_POOL_SIZE = 128;...private static final BlockingQueue<Runnable> sPoolWorkQueue =new LinkedBlockingQueue<Runnable>(10);
  • 39. Thank you!dpreussler@ebay.comjohannes.orgis@team.cortado.com