2014년 7월 17일 목요일

Getting Through the Handlers

The most flexible means of making an Android-friendly background thread is to create
an instance of a Handler subclass. You need only one Handler object per activity, and
you do not need to manually register it. Merely creating the instance is sufficient to
register it with the Android threading subsystem.

Your background thread can communicate with the Handler, which will do all of its work
on the activity’s UI thread. This is important, as UI changes, such as updating widgets,
should occur only on the activity’s UI thread.
You have two options for communicating with the Handler: messages and Runnable
objects.

Messages
To send a Message to a Handler, first invoke obtainMessage() to get the Message object
out of the pool. There are a few flavors of obtainMessage(), allowing you to create empty
Message objects or ones populated with message identifiers and arguments. The more
complicated your Handler processing needs to be, the more likely it is you will need to
put data into the Message to help the Handler distinguish different events.
Then, you send the Message to the Handler via its message queue, using one of the
sendMessage...() family of methods, such as the following:
  • sendMessage(): Puts the message on the queue immediately
  • sendMessageAtFrontOfQueue(): Puts the message on the queue immediately and places it at the front of the message queue (versus the back, which is the default), so your message takes priority over all others
  • sendMessageAtTime(): Puts the message on the queue at the stated time, expressed in the form of milliseconds based on system uptime (SystemClock.uptimeMillis())
  • sendMessageDelayed(): Puts the message on the queue after a delay, expressed in milliseconds
  • sendEmptyMessage(): Sends an empty Message object to the queue, allowing you to skip the obtainMessage() step if you were planning on leaving it empty anyway
To process these messages, your Handler needs to implement handleMessage(), which
will be called with each message that appears on the message queue. There, the
Handler can update the UI as needed. However, it should still do that work quickly, as
other UI work is suspended until the Handler is finished.
For example, let’s create a ProgressBar and update it via a Handler. Here is the layout
from the Threads/Handler sample project:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ProgressBar android:id="@+id/progress"
style="?android:attr/progressBarStyleHorizontal" android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>


package com.commonsware.android.threads;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ProgressBar;
import java.util.concurrent.atomic.AtomicBoolean;

public class HandlerDemo extends Activity {
ProgressBar bar;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
bar.incrementProgressBy(5);
}
};
AtomicBoolean isRunning = new AtomicBoolean(false);

@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
bar = (ProgressBar) findViewById(R.id.progress);
}

public void onStart() {
super.onStart();
bar.setProgress(0);
Thread background = new Thread(new Runnable() {
public void run() {
try {
for (int i = 0; i < 20 && isRunning.get(); i++) {
Thread.sleep(1000);
handler.sendMessage(handler.obtainMessage());
}
} catch (Throwable t) {
// just end the background thread
}
}
});
isRunning.set(true);
background.start();
}

public void onStop() {
super.onStop();
isRunning.set(false);
}
}

As part of constructing the Activity, we create an instance of Handler, with our
implementation of handleMessage(). Basically, for any message received, we update the
ProgressBar by 5 points, and then exit the message handler.
We then take advantage of onStart() and onStop(). In onStart(), we set up a
background thread. In a real system, this thread would do something meaningful. Here,
we just sleep 1 second, post a Message to the Handler, and repeat for a total of 20
passes. This, combined with the 5-point increase in the ProgressBar position, will march
the bar clear across the screen, as the default maximum value for ProgressBar is 100.
You can adjust that maximum via setMax(). For example, you might set the maximum to
be the number of database rows you are processing, and update once per row.
Note that we then leave onStart(). This is crucial. The onStart() method is invoked on
the activity UI thread, so it can update widgets and such. However, that means we need
to get out of onStart(), both to let the Handler get its work done and to inform Android
that our activity is not stuck.

Note, though, that while ProgressBar samples like this one show your code arranging to
update the progress on the UI thread, for this specific widget, that is not necessary. At
least as of Android 1.5, ProgressBar is now UI thread safe, in that you can update it from
any thread, and it will handle the details of performing the actual UI update on the UI
thread.

Runnables
If you would rather not fuss with Message objects, you can also pass Runnable objects to
the Handler, which will run those Runnable objects on the activity UI thread. Handler
offers a set of post...() methods for passing Runnable objects in for eventual
processing.
Just as Handler supports post() and postDelayed() to add Runnable objects to the
event queue, you can use those same methods on any View (i.e., any widget or
container). This slightly simplifies your code, in that you can then skip the Handler
object.

Source From “Beginning Android 4”

2014년 7월 8일 화요일

Android Holder Pattern

Using the Holder Pattern
Another somewhat expensive operation commonly done with fancy views is calling findViewById(). This dives into our inflated row and pulls out widgets by their assigned identifiers, so we can customize the widget contents (e.g., to change the text of a TextView or change the icon in an ImageView). Since findViewById() can find widgets anywhere in the tree of children of the row’s root View, this could take a fair number of instructions to execute, particularly if we need to find the same widgets repeatedly.
In some GUI toolkits, this problem is avoided by having the composite View objects, like rows, be declared totally in program code (in this case, Java). Then, accessing individual widgets is merely a matter of calling a getter or accessing a field. And we can certainly do that with Android, but the code gets rather verbose. What would be nice is a way that enables us still to use the layout XML, yet cache our row’s key child widgets so that we need to find them only once. That’s where the holder pattern comes into play, in a class we’ll call ViewHolder.
All View objects have getTag() and setTag() methods. These allow us to associate an arbitrary object with the widget. The holder pattern uses that “tag” to hold an object that, in turn, holds each of the child widgets of interest. By attaching that holder to the row View, every time we use the row, we already have access to the child widgets we care about, without having to call findViewById() again.
So, let’s take a look at one of these holder classes

package com.commonsware.android.fancylists.five;
import android.view.View;
import android.widget.ImageView;
class ViewHolder {
 ImageView icon=null;
 ViewHolder(View base) {
   this.icon=(ImageView)base.findViewById(R.id.icon);
 }
}

ViewHolder holds onto the child widgets, initialized via findViewById() in its constructor.
The widgets are simply package-protected data members, accessible from other classes in this project, such as a ViewHolderDemo activity. In this case, we are holding onto only one widget—the icon—since we will let ArrayAdapter handle our label for us.
Using ViewHolder is a matter of creating an instance whenever we inflate a row and attaching said instance to the row View via setTag(), as shown in this rewrite of getView(), found in ViewHolderDemo:

public View getView(int position, View convertView, ViewGroup parent) {
 View row=super.getView(position, convertView, parent);
 ViewHolder holder=(ViewHolder)row.getTag();
 if (holder==null) {
   holder=new ViewHolder(row);
   row.setTag(holder);
 }
 if (getModel(position).length()>4) {
   holder.icon.setImageResource(R.drawable.delete);
 }
 else {
   holder.icon.setImageResource(R.drawable.ok);
 }
 return(row);
}

Here, we go back to allowing ArrayAdapter to handle our row inflation and recycling for us. If the call to getTag() on the row returns null, we know we need to create a new ViewHolder, which we then attach to the row via setTag() for later reuse. Then, accessing the child widgets is merely a matter of accessing the data members on the holder. The first time the ListView is displayed, all new rows need to be inflated, and we wind up creating a ViewHolder for each. As the user scrolls, rows get recycled, and we can reuse their corresponding ViewHolder widget caches.
Using a holder helps performance, but the effect is not as dramatic. Whereas recycling can give you a 150 percent performance improvement, adding in a holder increases the improvement to 175 percent. Hence, while you may wish to implement recycling up front when you create your adapter, adding in a holder might be something you deal with later, when you are working specifically on performance tuning.
In this particular case, we certainly could simplify all of this by skipping ViewHolder and using getTag() and setTag() with the ImageView directly. This example is written as it is to demonstrate how to handle a more complex scenario, where you might have several widgets that would need to be cached via the holder pattern.

Source From “Beginning Android 4”

ETL 솔루션 환경

ETL 솔루션 환경 하둡은 대용량 데이터를 값싸고 빠르게 분석할 수 있는 길을 만들어줬다. 통계분석 엔진인 “R”역시 하둡 못지 않게 관심을 받고 있다. 빅데이터 역시 데이터라는 점을 볼때 분산처리와 분석 그 이전에 데이터 품질 등 데이...