Best android questions in September 2011

Android: correct way of jumping between fragments

9 votes

This is a design question, rather than a technical one.

General case: I want an UI event in a Fragment to make Activity-wide changes.

Specific case: I have two fragments, hosted in the same activity. When the user clicks a button in one of those fragments, I want it to be replaced by the other.

I don't want, however, my Fragments touching my activity. I may want to change the behavior later (maybe, in a bigger screen, show both fragments instead of replacing the first), and I don't want my Fragment code to have that logic.

What I did was implement a Listener class in my fragments, that reports events back to the Activity. This way, if I want to use another Activity class with different display behavior, I can just change the listener and leave the Fragment code untouched.

Is this a good way to go about it? Is there a standard good practice, or a better design pattern?

Using listeners is the recommended way of communicating between Fragment and your activity.

See this Android documentatin section for infromation. Long story short they just implement a listener interface by the Activity class and cast getActivity() result in a fragment to a listener.

From my personal experience this is very convenient because lets you to:

  1. Easilly switch underlying activity (e.g. you host entire fragment in a wrapper activity for compatibility in pre-3.0 and host this fragment along with others in 11+)
  2. Easilly control if the wrapper activity supports callbacks or not. Just check is it does implement the listener and do your app specific actions if it doesn't.

Youtube HTML5 Video Stopped Working in Android

8 votes

Somehow Youtube HTML5 video stopped working for me about a week ago. I have no idea why. Here's the code that was working last week (well, not the real code, but the smallest example I could make):

public class VideoTestActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        WebView webView = new WebView(this);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.getSettings().setPluginState(PluginState.OFF);
        webView.setWebChromeClient(new TestWebChromeClient());

        setContentView(webView);

        // Try with http://player.vimeo.com/video/24158845 and it works.
        webView.loadUrl("http://www.youtube.com/embed/e2UIg3Ddfp0");
    }

    private class TestWebChromeClient extends WebChromeClient {
        @Override
        public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) {
            super.onShowCustomView(view, callback);
            VideoTestActivity.this.setContentView(view);
        }
    }
}

This doesn't work on my phone or the emulator. The crazy part is that Vimeo still works great. I tried setting an iPhone user agent, but that didn't work and I'm out of ideas. It really looks like Youtube has changed something...

Youtube may have changed something in their embedded page and most likely this is causing problems inside the WebView and that is why it is not working anymore.

Also are you testing your app on the same device as before?

I don't think it is a good practice to use this solution, since you can not rely that the content that you display today from Youtube and it works, will also be the same in a few days and it will still work, as you have just encountered now. I had also similar problems with videos and Youtube content, it would work on one device, and not at all on some other devices. It is also a Flash content, and a lot of Android devices don't have Flash and will not be able to play the content.

A solution would be to create an Intent for playing the video:

      Intent videoIntent=new Intent(Intent.ACTION_VIEW, 
                                     Uri.parse("http://www.youtube.com/my_url"));
      startActivity(videoIntent);

But what I would recommend is to encode the videos for Android as suggested in the Supported Media Formats and store them on your own server if you have the possibility.

EDIT: They definetly changed something since there is an js error there. You can track them by using the WebChromeClient:

  mWebView.setWebChromeClient(new WebChromeClient(){
        @Override
        public void onConsoleMessage(String message, int lineNumber,
                String sourceID) {
            super.onConsoleMessage(message, lineNumber, sourceID);
            Log.i("VIDEO VIEW",message);
        }
 }

This is the message error I got:

TypeError: Result of expression 'a' [undefined] is not an object.line 78sourcehttp://www.youtube.com/embed/e2UIg3Ddfp0

I don't know if it helps you, I'll have another look later and see what I can find.

How to pass the email id that to be synchronized into create event calendar in android?

8 votes

How to pass the mail id of the calendar that to be synchronized into the create event through email? I have a spinner that shows the list of accounts to be synchronized as below picture. Now, as usual passing title,description to create event in calendar application, i use following code.

ContentValues values = new ContentValues();
    values.put("calendar_id", 1);
    values.put("title", title1);
    values.put("allDay", 0);
    values.put("dtstart", settime);
    values.put("dtend", cal.getTimeInMillis()+60*60*1000); 
    values.put("description", desc1);
    values.put("???????", mail_id);
    values.put("???????", participant_mail_id);
    values.put("visibility", 0);
    values.put("hasAlarm", 1);
    event = cr.insert(EVENTS_URI, values);

What should i use to pass the key to insert email id and participant id? Any Help is really appreciated. My screen shot goes below.

enter image description here

How to pass the mail id of the calendar that to be synchronized

The event is linked to a calendar by the "calendar_id". To get the "calendar_id" you should query for all the user's calendars and then search results for name in which you are interested. Here is a tutorial which should help: Working with the Android Calendar

Alternatively, you can create an event and then let the user choose to which Calendar the event should be added: Adding Calendar event through Intent

Global death of AudioTrack

8 votes

I have an application where there several threads each pumping into a separate AudioTrack set to MODE_STREAM. Switching between apps works fine, and when the application shuts down normally it seems to shut everything down correctly.

However, if the application is terminated externally, such as from the debugger or because I've just installed a new version while the old version was running, it seems that some state in the global AudioMixer gets messed up, and I get logcat output like:

09-16 14:50:38.965   298  7150 W AudioTrack: obtainBuffer timed out (is the CPU pegged?) 0x83c2348 user=00000eb3, server=00000000
09-16 14:50:39.025  7066  7132 W AudioTrack: obtainBuffer timed out (is the CPU pegged?) 0x8249d40 user=00002000, server=00000000
09-16 14:50:40.277   298  7156 W AudioTrack: obtainBuffer timed out (is the CPU pegged?) 0x84cb810 user=00000eb3, server=00000000

and no application that uses AudioTrack is able to play audio ever again, until I reboot my device. In this particular log fragment, PID 298 is system_server and 7066 is the new instance of the application.

What I think is happening is that the AudioTrack is disappearing before the writer thread has a chance to clean up. This makes me think that there is something else I should be doing to clean up. I'm already trapping my Activity's onStop and onDestroy and having those shut down my audio threads, but is there another place that this needs to happen?

Also, is there a better way to clean up AudioTrack? It seems like this part of Android is especially fragile, but I can't imagine that everyone uses SoundPool and MediaPlayer for everything, as those APIs are very limited and fiddly (and both seem to just wrap AudioTrack in different ways anyway).

Unfortunately your app gets no warning before it is killed by the OS and replaced with a new version. You can test this with a very simple Activity where the onPause() onStart() onStop() and onDestroy() methods produce log messages. If you install a new version of the app the messages in the onStop() and onDestroy() methods never get produced.

With regards to the AudioTrack problem, that is probably a bug your device's audio drivers. Some people trying to port Android get similar problems due to bad drivers. Additionally, one of the other answers to this question leads me to believe this as well. If this problem is restricted to a subset of phones from a few manufactures and not all phones then this that suggests the manufacturer's sound drivers are bad.

Have you considered using the MediaPlayer API instead of AudioTrack. It doesn't have the same flexibility but it could be a viable workaround. Here is a nice comparison of the three different audio apis.

One possible work around is to actually split the app into two a separate apks for debugging. One does nothing but plays the audio and is controlled by the second app. This way whenever you install an updated controller the binary playing the audio is unaffected and doesn't experience the abrupt kill and re-install. Then when you are ready to distribute the app simply combine the two into a single apk and then distribute that.

Japanese characters looking like Chinese on Android

8 votes

I have an application on Android that displays Japanese text in a WebView. There are some Chinese characters (kanji) that look, by convention, differently in China and in Japan, but share the same Unicode codepoint. Normally, the browser would rely upon the lang tag to choose the correct glyph. On Android, they all default to their Chinese shapes, and I want Japanese shapes.

The problem is well explained in this article. This article also serves as a perfect illustration of the problem - when watched on Android (up to 2.2), the characters in the "Examples of language-dependent characters" all look the same, and Chinese.

Using the lang="ja" attribute does not help. Switching the whole system locale to Japanese does not help either.

I'm wondering about Android phones that are sold in Japan. Do characters like 直, 今, 化 look Chinese-style on those, too? I'm assuming not.

So the questions are: are there official localized images of Android out there? Can I get one to run on the emulator? Is the DroidSansFallback font still the only CJK-enabled font on those? And if it is, is it the same as on the vanilla USA Android?

I'm kinda hoping that the Japanese glyphs are hidden somewhere deep in the font (Unicode private area or something). If so, I could leverage them...

There are fonts with full Japanese support. I've heard some people talking about DroidSansJapanese.tff and TakaoPGothic.

Should i resize the bitmap before adding to a ImageView or let the ImageView resize the Bitmap?

7 votes

i have a simple question: Should i resize a bigger bitmap before adding to a ImageView or let the ImageView resize the Bitmap? What's the right way, regarding performance?

Thanks

Consider using scale for ImageView, and don't bother about resizing. You can scale an image like this, for example:

image.setAdjustViewBounds(true);
image.setMaxHeight(50);
image.setMaxWidth(50);
image.setScaleType(ImageView.ScaleType.CENTER_INSIDE);

Why are annotations under Android such a performance problem?

6 votes

I'm the lead author of ORMLite which uses Java annotations on classes to build database schemas. A big startup performance problem for our package turns out to be the calling of annotation methods under Android 1.6. I see the same behavior if not worse up through 3.0.

We are seeing that the following simple annotation code is incredibly GC intensive and a real performance problem. 1000 calls to an annotation method takes almost a second on a fast box. The same code under Java can do 28 million (sic) calls in the same time. We have an annotation that has 25 methods in it and we'd like to do more than 50 of these a second.

Does anyone know why this is happening and if there is any work around? There are certainly things that ORMLite can do in terms of caching this information but is there anything that we can do to "fix" annotations under Android? Thanks.

public void testAndroidAnnotations() throws Exception {
    Field field = Foo.class.getDeclaredField("field");
    MyAnnotation myAnnotation = field.getAnnotation(MyAnnotation.class);
    long before = System.currentTimeMillis();
    for (int i = 0; i < 1000; i++)
        myAnnotation.foo();
    Log.i("test", "in " + (System.currentTimeMillis() - before) + "ms");
}
@Target(FIELD) @Retention(RUNTIME)
private static @interface MyAnnotation {
    String foo();
}
private static class Foo {
    @MyAnnotation(foo = "bar")
    String field;
}

This results in the following log output:

I/TestRunner(  895): started: testAndroidAnnotations
D/dalvikvm(  895): GC freed 6567 objects / 476320 bytes in 85ms
D/dalvikvm(  895): GC freed 8951 objects / 599944 bytes in 71ms
D/dalvikvm(  895): GC freed 7721 objects / 524576 bytes in 68ms
D/dalvikvm(  895): GC freed 7709 objects / 523448 bytes in 73ms
I/test    (  895): in 854ms

EDIT:

After @candrews pointed me in the right direction, I did some poking around the code. The performance problem looks to be caused by some terrible, gross code in Method.equals(). It is calling the toString() of both methods and then comparing them. Each toString() use StringBuilder with a bunch of append methods without a good initializing size. Actually doing the .equals by comparing fields would be 100+ times faster.

Google has acknowledged the issue and fixed it "post-Honeycomb"

https://code.google.com/p/android/issues/detail?id=7811

So at least they know about it and have supposedly fixed it for some future version.

Buying Android Device for Development

6 votes

So I am thinking of getting Sprint Nexus S from ebay to do android development. I am wondering whether getting a locked phone will hinder me from doing any kind of development work on the phone (pushing to app market, connecting to internet(i don't care about 3/4G as long as I can use wifi I am good)). What are some things that I should be worried about when getting a locked phone for development? Will the locked phone even run without SIM?

Or is it really necessary for me to get an unlocked phone for development? I currently use iPhone ATT and I am not planning to switch to Sprint.

There is nothing wrong with getting a locked phone. As long as you make sure the phone doest require a sim. If it does. Make sure the sim is in. If that isnt a issue i dont see anything wrong with it. Its perfectly fine using it over wifi. As i have 3 locked phones i use for development ive purchased from ebay. 2 Tablets, Nexus s. Works great for me. You should be fine. =)

What exactly is a monkey doing messing with my Android phone?

6 votes

Looking through the Android apis I found a method call isUserAMonkey(), says it returns true if the phone is being messed with by a monkey.

Is this a joke, or what is it used for?

Look at monkeyrunner, it will give you the answer.

Quote from the document:

The monkeyrunner tool provides an API for writing programs that control an Android device or emulator from outside of Android code. With monkeyrunner, you can write a Python program that installs an Android application or test package, runs it, sends keystrokes to it, takes screenshots of its user interface, and stores screenshots on the workstation. The monkeyrunner tool is primarily designed to test applications and devices at the functional/framework level and for running unit test suites, but you are free to use it for other purposes.

So if you are running a package using Monkeyrunner, then this function will return true.

Storing large data locally or online for Android app?

5 votes

First time posting and first time working on Android, so go easy if I am breaking any rules :)

Anyways, I just got into making an Android app and I'm trying to create a simple trivia game. I plan to have many questions (hopefully about 5000+ questions) made. No data manipulation made, just straight up reading the questions and presenting it to the user. I am now faced with the dilema in how to store the questions.

I have two choices:

1.) Bundle the questions with the app: Possibly store the information in SQLite. Originally, for demo purposes, I placed the questions in an XML file, but I quickly realized how inefficient it will be once the questions start piling up. First, I am concerned if opening up such a huge XML file would suck up Android's memory. Secondly, I am worried how large the app would be if it contains 5000+ questions. I read here about the pros of XML vs SQLite. In that example, the user has 70,000 entries so maybe my 5,000 questions would be enough?

OR

2.) Host the questions on a server: I believe the upside is the app wouldn't need to be bundled with a vast amount of questions and wouldn't need to worry about the logic of opening and assembling the questions. It would just hit a PHP page and depending on the parameters sent, the PHP page would return the questions in XML format. The downside is the user would need to be online (to retrieve the questions) in order to play the game and my server would need to be up and running 24/7.

Has anyone encountered this design issue of how and where to store vast amount of data in an Android app?

Thanks, any help would be much appreciated!

From a marketing perspective, I think the right approach is #1. Just looking at the top app list, it's filled with apps that work offline. I don't know why most people fail to mention this one important criteria when they talk about marketing apps... especially in Android, where lots of people don't have a data plan. Plus, a trivia app sounds like something someone would probably use during a commute in a train as opposed to something like Facebook Chat that they'd use when they're online.

From a technical perspective, storing 5000+ questions really won't take a huge amount of space. There's this app called "MyFitnessPal". It stores maybe over 30,000 foods in a SQlite database, with nutritional information. So don't overestimate how much space it will take.

The advantage of going with #2 is if the questions or answers change often, you might want to go with that approach.