출처 : http://www.journaldev.com/13792/android-gridlayoutmanager-example

Android GridLayoutManager

We’ve implemented a RecyclerView using a LinearLayoutManager here. Now let’s use a GridLayoutManagerto layout the RecyclerView as a grid.

Following is the constructor for a GridLayoutManager.

GridLayoutManager (Context context, 
                int spanCount, 
                int orientation, 
                boolean reverseLayout)

reverseLayout if set true then layout items from end to start.

To set the span size for each item, we invoke the method setSpanSizeLookup on the GridLayoutManager

Let’s implement RecyclerView using a GridLayoutManager in a new Android Studio project.

Android GridLayoutManager Example Project Structure

Android GridLayoutManager example

The project consists of a single Activity : MainActivity.java, an adapter class : RecyclerViewAdapter.java, a DataModel.java class and a custom GridLayoutManager class AutoFitGridLayoutManager.java.

The xml layout of the MainActivity.java class is defined in the file activity_main.xml as

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scrollbars="vertical"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    </RelativeLayout>

</android.support.design.widget.CoordinatorLayout>

Note: Don’t forget to add the following dependencies for Material Design widgets and CardView in the build.gradle file.

compile 'com.android.support:cardview-v7:25.1.1'
compile 'com.android.support:design:25.1.1'

The DataModel.java class is given below:
package com.journaldev.recyclerviewgridlayoutmanager;

public class DataModel {

    public String text;
    public int drawable;
    public String color;

    public DataModel(String t, int d, String c )
    {
        text=t;
        drawable=d;
        color=c;
    }
}

The DataModel class will hold the text, drawable icon and background colour of each item cell.

The RecyclerViewAdapter.java class is given below:

package com.journaldev.recyclerviewgridlayoutmanager;

import android.content.Context;
import android.graphics.Color;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import java.util.ArrayList;


public class RecyclerViewAdapter extends RecyclerView.Adapter {

    ArrayList mValues;
    Context mContext;
    protected ItemListener mListener;

    public RecyclerViewAdapter(Context context, ArrayList values, ItemListener itemListener) {

        mValues = values;
        mContext = context;
        mListener=itemListener;
    }

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        public TextView textView;
        public ImageView imageView;
        public RelativeLayout relativeLayout;
        DataModel item;

        public ViewHolder(View v) {

            super(v);

            v.setOnClickListener(this);
            textView = (TextView) v.findViewById(R.id.textView);
            imageView = (ImageView) v.findViewById(R.id.imageView);
            relativeLayout = (RelativeLayout) v.findViewById(R.id.relativeLayout);

        }

        public void setData(DataModel item) {
            this.item = item;

            textView.setText(item.text);
            imageView.setImageResource(item.drawable);
            relativeLayout.setBackgroundColor(Color.parseColor(item.color));

        }


        @Override
        public void onClick(View view) {
            if (mListener != null) {
                mListener.onItemClick(item);
            }
        }
    }

    @Override
    public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(mContext).inflate(R.layout.recycler_view_item, parent, false);

        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder Vholder, int position) {
        Vholder.setData(mValues.get(position));

    }

    @Override
    public int getItemCount() {

        return mValues.size();
    }

    public interface ItemListener {
        void onItemClick(DataModel item);
    }
}

In the above code we’ve defined an ItemListener interface that’ll be implemented in the MainActivity.java class.

The xml layout for each RecyclerView item is given below.
recycler_view_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <android.support.v7.widget.CardView
        android:id="@+id/cardView"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        card_view:cardCornerRadius="0dp"
        card_view:cardElevation="@dimen/margin10"
        card_view:cardMaxElevation="@dimen/margin10"
        card_view:contentPadding="@dimen/margin10">


        <RelativeLayout
            android:id="@+id/relativeLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:layout_gravity="center">

            <ImageView
                android:id="@+id/imageView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:tint="@android:color/white"
                android:padding="5dp" />


            <TextView
                android:id="@+id/textView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:textColor="@android:color/white"
                android:layout_below="@+id/imageView" />


        </RelativeLayout>

    </android.support.v7.widget.CardView>

</LinearLayout>

The AutoFitGridLayoutManager.java class is given below:

package com.journaldev.recyclerviewgridlayoutmanager;

import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;

public class AutoFitGridLayoutManager extends GridLayoutManager {

    private int columnWidth;
    private boolean columnWidthChanged = true;

    public AutoFitGridLayoutManager(Context context, int columnWidth) {
        super(context, 1);

        setColumnWidth(columnWidth);
    }

    public void setColumnWidth(int newColumnWidth) {
        if (newColumnWidth > 0 && newColumnWidth != columnWidth) {
            columnWidth = newColumnWidth;
            columnWidthChanged = true;
        }
    }

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        if (columnWidthChanged && columnWidth > 0) {
            int totalSpace;
            if (getOrientation() == VERTICAL) {
                totalSpace = getWidth() - getPaddingRight() - getPaddingLeft();
            } else {
                totalSpace = getHeight() - getPaddingTop() - getPaddingBottom();
            }
            int spanCount = Math.max(1, totalSpace / columnWidth);
            setSpanCount(spanCount);
            columnWidthChanged = false;
        }
        super.onLayoutChildren(recycler, state);
    }
}

The span count is dynamically calculated based on the orientation, width and height available.

The MainActivity.java class is given below:

package com.journaldev.recyclerviewgridlayoutmanager;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity implements RecyclerViewAdapter.ItemListener {

    RecyclerView recyclerView;
    ArrayList arrayList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        arrayList = new ArrayList();
        arrayList.add(new DataModel("Item 1", R.drawable.battle, "#09A9FF"));
        arrayList.add(new DataModel("Item 2", R.drawable.beer, "#3E51B1"));
        arrayList.add(new DataModel("Item 3", R.drawable.ferrari, "#673BB7"));
        arrayList.add(new DataModel("Item 4", R.drawable.jetpack_joyride, "#4BAA50"));
        arrayList.add(new DataModel("Item 5", R.drawable.three_d, "#F94336"));
        arrayList.add(new DataModel("Item 6", R.drawable.terraria, "#0A9B88"));

        RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, arrayList, this);
        recyclerView.setAdapter(adapter);


        /**
         AutoFitGridLayoutManager that auto fits the cells by the column width defined.
         **/

        /*AutoFitGridLayoutManager layoutManager = new AutoFitGridLayoutManager(this, 500);
        recyclerView.setLayoutManager(layoutManager);*/


        /**
         Simple GridLayoutManager that spans two columns
         **/
        GridLayoutManager manager = new GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false);
        recyclerView.setLayoutManager(manager);
    }

    @Override
    public void onItemClick(DataModel item) {

        Toast.makeText(getApplicationContext(), item.text + " is clicked", Toast.LENGTH_SHORT).show();

    }
}
  1. The above class implements the interface RecyclerViewAdapter.ItemListener and overrides the method onItemClick that’s defined in the adapter class. By doing this, we’ve implemented the RecyclerView Click Listener within our Activity instead of the Adapter class(similar to the standard onItemClickListener defined for a ListView)
  2. DataModel class holds the details for each RecyclerView item
  3. The LayoutManager of the RecyclerView can be defined by either instantiating the AutoFitGridLayoutManager class with the column width set as 500 or by invoking the GridLayoutManager class object and setting the number of columns as 2

Let’s see the output of the application with the standard GridLayoutManager code.

android GridLayoutManager grid layout output

As you can see, each row has two items that span the column width in both orientations.

Now comment out the code for simple GridLayoutManager and run the code for AutoFitGridLayoutManager

AutoFitGridLayoutManager layoutManager = new AutoFitGridLayoutManager(this, 500);
recyclerView.setLayoutManager(layoutManager);

The output of the application in action is given below.
android GridLayoutManager auto fit grid layout

As you can see in the above output, when the orientation changes to landscape, each row has three items, thereby dynamically sizing the items to auto-fit the column width.

This brings an end to this tutorial. You can download the final android GridLayoutManager project from the link given below.

public class TileBitmapProvider implements BitmapProvider {

    private final TileProvider provider;
    private final Bitmap.Config bitmapConfig;
    private final int backgroundColor;
    private final BitmapPool bitmapPool;
    private final Rect frameRect = new Rect();

    public TileBitmapProvider(final TileProvider provider,
                              final BitmapPool bitmapPool,
                              final Bitmap.Config bitmapConfig,
                              final int backgroundColor) {
        this.provider = provider;
        this.bitmapConfig = bitmapConfig;
        this.backgroundColor = backgroundColor;
        this.bitmapPool = bitmapPool;
    }

    @Override public Bitmap getBitmap(final Tile tile, final Context context) {
        try {
            Bitmap bmp = tile.getBitmap();

            if (bmp == null || bmp.isRecycled()) {
                bmp = bitmapPool.poll();
                bmp = bmp != null ? bmp : Bitmap.createBitmap(tile.getWidth(), tile.getHeight(), bitmapConfig);
                // tiles at edges need to be padded so that they fit correctly
                bmp.eraseColor(backgroundColor);

                final BitmapFactory.Options ops = new BitmapFactory.Options();
                ops.inPreferredConfig = bitmapConfig;
                ops.inBitmap = bmp;
                ops.inMutable = true;

                frameRect.set(0, 0, tile.getWidth(), tile.getHeight());
                bmp = BitmapRegionDecoder.newInstance(provider.readTile(tile), false).decodeRegion(frameRect, ops);
            }

            return bmp;
        } catch (final IOException e) {
            Logger.getInstance().critical(getClass().getSimpleName(), e, "Error loading tile:");
        }
        return null;
    }
}

다음은 경고를 트리거하는 코드입니다.

public class TileBitmapProvider implements BitmapProvider {

    private final TileProvider provider;
    private final Bitmap.Config bitmapConfig;
    private final int backgroundColor;
    private final BitmapPool bitmapPool;

    public TileBitmapProvider(final TileProvider provider,
                              final BitmapPool bitmapPool,
                              final Bitmap.Config bitmapConfig,
                              final int backgroundColor) {
        this.provider = provider;
        this.bitmapConfig = bitmapConfig;
        this.backgroundColor = backgroundColor;
        this.bitmapPool = bitmapPool;
    }

    @Override public Bitmap getBitmap(final Tile tile, final Context context) {
        try {
            Bitmap bmp = tile.getBitmap();

            if (bmp == null || bmp.isRecycled()) {
                bmp = bitmapPool.poll();
                bmp = bmp != null ? bmp : Bitmap.createBitmap(tile.getWidth(), tile.getHeight(), bitmapConfig);
                // tiles at edges need to be padded so that they fit correctly
                bmp.eraseColor(backgroundColor);

                final BitmapFactory.Options ops = new BitmapFactory.Options();
                ops.inPreferredConfig = bitmapConfig;
                ops.inBitmap = bmp;
                ops.inMutable = true;

                bmp = BitmapFactory.decodeStream(provider.readTile(tile), null, ops);
            }

            return bmp;
        } catch (final IOException e) {
            Logger.getInstance().critical(getClass().getSimpleName(), e, "Error loading tile:");
        }
        return null;
    }
}


List of Android Top 1000 Libraries

A curated list of awesome Android Top 1000 libraries.

Mantainers

iamdaiyuan iamdaiyuan

Top 1000

NameDemo
nostra13/Android-Universal-Image-Loader
jfeinstein10/SlidingMenu
google/iosched
JakeWharton/ActionBarSherlock
forkhubs/android
libgdx/libgdx
loopj/android-async-http
square/picasso
square/retrofit
JakeWharton/ViewPagerIndicator
excilys/androidannotations
chrisbanes/Android-PullToRefresh
greenrobot/EventBus
square/okhttp
facebook/fresco
Bearded-Hen/Android-Bootstrap
navasmdc/MaterialDesignLibrary
WhisperSystems/TextSecure
PhilJay/MPAndroidChart
futurice/android-best-practices
JakeWharton/butterknife
square/leakcanary
nhaarman/ListViewAnimations
AndroidBootstrap/android-bootstrap
chrisbanes/PhotoView
square/dagger
gabrielemariotti/cardslib
etsy/AndroidStaggeredGrid
ksoichiro/Android-ObservableScrollView
aporter/coursera-android
koush/ion
facebook/facebook-android-sdk
googlesamples/android-UniversalMusicPlayer
bumptech/glide
umano/AndroidSlidingUpPanel
daimajia/AndroidSwipeLayout
roboguice/roboguice
daimajia/AndroidViewAnimations
47deg/android-swipelistview
emilsjolander/StickyListHeaders
square/otto
facebook/stetho
nicolasgramlich/AndEngine
keyboardsurfer/Crouton
greenrobot/greenDAO
JakeWharton/NineOldAndroids
cyrilmottier/GreenDroid
pardom/ActiveAndroid
koush/AndroidAsync
wyouflf/xUtils
stephanenicolas/robospice
SimonVT/android-menudrawer
makovkastar/FloatingActionButton
ManuelPeinado/FadingActionBar
castorflex/SmoothProgressBar
johannilsson/android-pulltorefresh
bauerca/drag-sort-listview
dmytrodanylyk/circular-progress-button
futuresimple/android-floating-action-button
liaohuqiu/android-Ultra-Pull-To-Refresh
chrisjenx/Calligraphy
square/android-times-square
ACRA/acra
Trinea/android-common
chrisbanes/cheesesquare
traex/RippleEffect
yangfuhai/afinal
Comcast/FreeFlow
k9mail/k-9
theDazzler/droidicon
mcxiaoke/android-volley
openaphid/android-flip
JakeWharton/u2020
Yalantis/Side-Menu.Android
JakeWharton/DiskLruCache
romannurik/muzei
qii/weiciyuan
androidquery/androidquery
BoltsFramework/Bolts-Android
jgilfelt/android-viewbadger
hdodenhof/CircleImageView
daimajia/NumberProgressBar
avast/android-styled-dialogs
pakerfeldt/android-viewflow
daimajia/AndroidImageSlider
path/android-priority-jobqueue
dmytrodanylyk/android-process-button
yixia/VitamioBundle
jgilfelt/SystemBarTint
derekbrameyer/android-betterpickers
ReactiveX/RxAndroid
tjerkw/Android-SlideExpandableListView
markushi/android-ui
SpecialCyCi/AndroidResideMenu
koral--/android-gif-drawable
rey5137/material
balysv/material-menu
pedrovgs/EffectiveAndroidUI
Yalantis/Context-Menu.Android
singwhatiwanna/dynamic-load-apk
pedrovgs/DraggablePanel
Todd-Davies/ProgressWheel
SecUpwN/Android-IMSI-Catcher-Detector
nispok/snackbar
johannilsson/android-actionbar
ikew0ng/SwipeBackLayout
google/ExoPlayer
Bilibili/DanmakuFlameMaster
robovm/robovm
wasabeef/recyclerview-animators
daimajia/AndroidViewHover
JohnPersano/SuperToasts
beworker/pinned-section-listview
kikoso/android-stackblur
orhanobut/logger
maurycyw/StaggeredGridView
pedant/sweet-alert-dialog
PomepuyN/BlurEffectForAndroidDesign
jdamcd/android-crop
mttkay/ignition
edmodo/cropper
xamarin/XobotOS
lgvalle/Material-Animations
lecho/hellocharts-android
commonsguy/cw-advandroid
facebook/conceal
CyberAgent/android-gpuimage
JoanZapata/android-iconify
saulmm/Android-Material-Examples
chrisbanes/philm
psaravan/JamsMusicPlayer
jgilfelt/android-sqlite-asset-helper
novoda/android-demos
stormzhang/9GAG
cymcsg/UltimateAndroid
thest1/LazyList
orhanobut/dialogplus
johncarl81/parceler
bluelinelabs/LoganSquare
eluleci/FlatUI
android10/Android-CleanArchitecture
siacs/Conversations
mikepenz/LollipopShowcase
alamkanak/Android-Week-View
square/tape
siyamed/android-satellite-menu
commonsguy/cw-android
Flowdalic/asmack
ManuelPeinado/GlassActionBar
romainguy/ViewServer
googlesamples/android-testing
apache/cordova-android
MikeOrtiz/TouchImageView
JakeWharton/Telecine
jjoe64/GraphView
wasabeef/richeditor-android
harism/android_page_curl
cymcsg/UltimateRecyclerView
qiujuer/Genius-Android
loopj/android-smart-image-view
ikimuhendis/LDrawer
RobotiumTech/robotium
RomainPiel/Shimmer-android
grantland/android-autofittextview
todoroo/astrid
satyan/sugar
JakeWharton/timber
romannurik/Android-SwipeToDismiss
diogobernardino/WilliamChart
owncloud/android
eoecn/android-app
orhanobut/hawk
daCapricorn/ArcMenu
white-cat/ThinkAndroid
mttkay/droid-fu
rockerhieu/emojicon
MrEngineer13/SnackBar
square/assertj-android
ginatrapani/todo.txt-android
johnkil/Android-AppMsg
kymjs/KJFrameForAndroid
oguzbilgener/CircularFloatingActionMenu
romainguy/road-trip
markushi/android-circlebutton
redsolution/xabber-android
lucasr/smoothie
novoda/image-loader
pwnall/chromeview
daimajia/AnimationEasingFunctions
calabash/calabash-android
googlemaps/android-maps-utils
mixi-inc/AndroidTraining
avast/android-butterknife-zelezny
alexvasilkov/FoldableLayout
sephiroth74/ImageViewZoom
dlew/joda-time-android
ragunathjawahar/android-saripaar
jgilfelt/android-mapviewballoons
jackpal/Android-Terminal-Emulator
yahoo/squidb
udacity/Sunshine
simpligility/android-maven-plugin
koush/UrlImageViewHelper
kmshack/Android-ParallaxHeaderViewPager
klinker24/Talon-for-Twitter
JoanZapata/android-pdfview
iPaulPro/aFileChooser
commonsguy/cwac-endless
Raizlabs/DBFlow
dexafree/MaterialList
pingpongboss/StandOut
jasonpolites/gesture-imageview
tehmou/rx-android-architecture
jberkel/sms-backup-plus
facebook/shimmer-android
blackfizz/EazeGraph
vekexasia/android-edittext-validator
AntennaPod/AntennaPod
romannurik/Android-MonthCalendarWidget
antonkrasov/AndroidSocialNetworks
500px/500px-android-blur
drakeet/MaterialDialog
guardianproject/ChatSecureAndroid
LarsWerkman/HoloColorPicker
UweTrottmann/SeriesGuide
stephanenicolas/Quality-Tools-for-Android
RomainPiel/Titanic
romannurik/Android-WizardPager
Pkmmte/CircularImageView
facebook/device-year-class
wunderlist/android-sliding-layer-lib
wordpress-mobile/WordPress-Android
baoyongzhang/android-PullRefreshLayout
chrisbanes/Android-BitmapCache
square/wire
dinocore1/DevsmartLib-Android
antoniolg/androidmvp
gabrielemariotti/RecyclerViewItemAnimators
roomorama/Caldroid
balysv/material-ripple
ZieIony/Carbon
frankiesardo/auto-parcel
GDG-Korea/PinterestLikeAdapterView
jpardogo/ListBuddies
expectedbehavior/gauges-android
MizzleDK/Mizuu
mcharmas/android-parcelable-intellij-plugin
Avocarrot/json2view
eowise/recyclerview-stickyheaders
kanytu/android-parallax-recyclerview
emilsjolander/sprinkles
ManuelPeinado/MultiChoiceAdapter
RoboBinding/RoboBinding
sromku/android-simple-facebook
MichaelEvans/ColorArt
hoang8f/android-flat-button
RadiusNetworks/android-ibeacon-service
bmelnychuk/AndroidTreeView
felipecsl/AsymmetricGridView
siyamed/android-shape-imageview
Manabu-GT/ExpandableTextView
sephiroth74/HorizontalVariableListView
passsy/android-HoloCircularProgressBar
LitePalFramework/LitePal
jpardogo/GoogleProgressBar
mihaip/dex-method-counts
gabrielemariotti/androiddev
inmite/android-selector-chapek
chrislacy/TweetLanes
andkulikov/Transitions-Everywhere
ManuelPeinado/RefreshActionItem
flavioarfaria/KenBurnsView
fyhertz/libstreaming
ToxicBakery/ViewPagerTransforms
ChrisRenke/DrawerArrowDrawable
johnkil/Android-ProgressFragment
AltBeacon/android-beacon-library
matburt/mobileorg-android
prolificinteractive/material-calendarview
Rajawali/Rajawali
daizhenjun/ImageFilterForAndroid
bluejamesbond/TextJustify-Android
MostafaGazar/soas
ApmeM/android-flowlayout
rmtheis/android-ocr
thiagolocatelli/android-uitableview
foxykeep/DataDroid
Trinea/android-auto-scroll-view-pager
BlueMor/Android-PullLayout
kaushikgopal/Android-RxJava
zcweng/ToggleButton
Konloch/bytecode-viewer
mmin18/AndroidDynamicLoader
cgeo/cgeo
JakeWharton/Android-DirectionalViewPager
oschina/android-app
Frank-Zhu/PullZoomView
woozzu/IndexableListView
dodola/android_waterfall
h6ah4i/android-advancedrecyclerview
survivingwithandroid/Surviving-with-android
akexorcist/Android-RoundCornerProgressBar
geftimov/android-player
saik0/UnifiedPreference
timehop/sticky-headers-recyclerview
xcltapestry/XCL-Charts
paddybyers/anode
lorensiuswlt/NewQuickAction
erikwt/PullToRefresh-ListView
skyfishjy/android-ripple-background
kanytu/android-material-drawer-template
hmkcode/Android
Diolor/Swipecards
jenzz/Android-UndoBar
evant/JobSchedulerCompat
nirhart/ParallaxScroll
google/santa-tracker-android
good-life/PushTalk
johnkil/Android-RobotoTextView
dm77/barcodescanner
robotmedia/AndroidBillingLibrary
sqlcipher/android-database-sqlcipher
e-biz/androidkickstartr
jeromevdl/android-holo-colors-idea-plugin
tokudu/AndroidPushNotificationsDemo
dmytrodanylyk/shadow-layout
davidschreiber/FancyCoverFlow
jpardogo/FlabbyListView
spring-projects/spring-android-samples
yangfuhai/ASimpleCache
ZhouWeikuan/cocos2d
BlueMor/DragLayout
j256/ormlite-android
Clans/FloatingActionButton
square/phrase
linroid/FilterMenu
hoang8f/android-segmented-control
mcharmas/Android-ReactiveLocation
keithellis/MaterialWidget
darvds/RibbonMenu
spring-projects/spring-android
Maxwin-z/XListView-Android
nvanbenschoten/motion
playgameservices/android-basic-samples
sd6352051/NiftyNotification
splitwise/TokenAutoComplete
dmitry-zaitsev/AndroidSideMenu
codebutler/farebot
jacobmoncur/QuiltViewLibrary
konifar/android-material-design-icon-generator-plugin
Trinea/android-demo
siriscac/RippleView
mrwonderman/android-square-progressbar
BoD/android-switch-backport
zzz40500/android-shapeLoadingView
liaohuqiu/android-GridViewWithHeaderAndFooter
shell-software/fab
emilsjolander/StickyScrollViewItems
carlonzo/StikkyHeader
bpellin/keepassdroid
rno/Android-ScrollBarPanel
lewisjdeane/L-Dialogs
pents90/svg-android
survivingwithandroid/WeatherLib
chiuki/advanced-textview
beworker/tinybus
moagrius/TileView
SimonVT/MessageBar
emilsjolander/android-FlipView
MatthewYork/Colours
soarcn/UndoBar
commonsguy/cwac-merge
timroes/EnhancedListView
square/seismic
medyo/fancybuttons
MartinRGB/GiftCard-Android
couchbase/couchbase-lite-android
afollestad/material-cab
gabrielemariotti/changeloglib
DWorkS/VolleyPlus
OnlyInAmerica/GlanceReader
vinaysshenoy/mugen
HackPlan/AndroidCharts
lucasr/android-layout-samples
QuantumBadger/RedReader
google/google-authenticator
lucasr/dspec
jess-anders/two-way-gridview
grandcentrix/tray
PomepuyN/discreet-app-rate
pedrovgs/Renderers
akquinet/android-archetypes
geftimov/android-pathview
AChep/AcDisplay
bagilevi/android-pedometer
mik3y/usb-serial-for-android
bitfireAT/davdroid
askerov/DynamicGrid
guerwan/TransitionsBackport
lucasr/probe
alamkanak/android-empty-layout
Estimote/Android-SDK
mozilla/MozStumbler
bboyfeiyu/AndroidEventBus
tekinarslan/AndroidMaterialDesignToolbar
dannytiehui/androidpn
jblough/Android-Pdf-Viewer-Library
edmodo/range-bar
SimonVT/android-numberpicker
AlbertGrobas/MovingImageView
Mirkoddd/TabBarView
mikepenz/Android-ActionItemBadge
negusoft/holoaccent
StevenRudenko/ActionsContentView
marvinlabs/android-floatinglabel-widgets
etao-open-source/cube-sdk
sinaweibosdk/weibo_android_sdk
JorgeCastilloPrz/PagedHeadListView
square/moshi
tavendo/AutobahnAndroid
2dxgujun/AndroidTagGroup
schildbach/bitcoin-wallet
weddingparty/AndroidFloatLabel
card-io/card.io-Android-SDK
udacity/Sunshine-Version-2
lovetuzitong/MultiImageSelector
ogrebgr/android_volley_examples
tuenti/ButtonMenu
tizionario/AndroidDrawableFactory
vinc3m1/android-segmentedradiobutton
attenzione/android-ColorPickerPreference
malmstein/yahnac
slapperwan/gh4a
IanGClifton/AndroidFloatLabel
rtyley/agit
connectbot/connectbot
ckurtm/FabButton
pavlospt/RoundedLetterView
wujingchao/SimpleTagImageView
open-keychain/open-keychain
prolificinteractive/ParallaxPager
Flipboard/bottomsheet
ogaclejapan/ArcLayout
Dreddik/AndroidTouchGallery
houkx/android-pluginmgr
noties/Scrollable
AlexKorovyansky/android-fb-like-slideout-navigation
gcacace/android-signaturepad
sockeqwe/mosby
greenrobot/greenrobot-common
chrisjenx/Paralloid
throrin19/Android-Validator
serso/android-checkout
inmite/android-validation-komensky
fyhertz/spydroid-ipcamera
mapbox/mapbox-android-sdk
Subito-it/Masaccio
MarkMjw/PullScrollView
bingoogolapple/BGARefreshLayout-Android
Gnod/ParallaxListView
TwidereProject/Twidere-Android
codechimp-org/AppRater
mendhak/gpslogger
PaoloRotolo/AppIntro
igniterealtime/Smack
orhanobut/wasp
norbsoft/android-typeface-helper
JimiSmith/PinnedHeaderListView
megamattron/SplinterNet
john990/WaveView
freezy/android-xbmcremote
AndlyticsProject/andlytics
pfleidi/yaxim
thquinn/DraggableGridView
Jungerr/GridPasswordView
zarics/ZrcListView
osmdroid/osmdroid
biokys/cropimage
juleswhite/mobilecloud-14
gitgrimbo/android-sliding-menu-demo
MeetMe/Android-HorizontalListView
JakeWharton/double-espresso
ahorn/android-rss
cesards/CropImageView
ai212983/android-spinnerwheel
JakeWharton/NotRxAndroid
PaperAirplane-Dev-Team/BlackLight
ChainsDD/Superuser
mobileresearch/weibo_android_sdk
imbryk/LoopingViewPager
ruboto/ruboto-irb
mrKlar/PagedDragDropGrid
z56402344/BaseAnimation
abarisain/dmix
emmaguy/clean-status-bar
lvillani/android-cropimage
kyze8439690/v2ex-daily-android
atermenji/IconicDroid
Fichardu/CircleProgress
talklittle/reddit-is-fun
TechFreak/WizardPager
anjlab/android-inapp-billing-v3
JayFang1993/DropDownMenu
flavienlaurent/poppyview
shontauro/android-pulltorefresh-and-loadmore
coomar2841/image-chooser-library
robolectric/deckard-gradle
mobsandgeeks/adapter-kit
manmal/hn-android
commonsguy/cwac-wakeful
WhiteHouse/wh-app-android
lafosca/AndroidFaceCropper
infinum/android_dbinspector
kevinsawicki/wishlist
selendroid/selendroid
felixpalmer/android-visualizer
journeyapps/zxing-android-embedded
pocmo/Android-Network-Intents
antoniolg/RecyclerViewExtensions
rgladwell/m2e-android
jerrellmardis/Amphitheatre
litesuits/android-common
BoD/android-contentprovider-generator
winterDroid/android-drawable-importer-intellij-plugin
marvinlabs/android-intents
JakeWharton/gradle-android-test-plugin
ManuelPeinado/ImageLayout
rohaanhamid/ScrollableItemList
petrnohejl/Android-Templates-And-Utilities
googlecast/CastCompanionLibrary-android
inmite/android-grid-wichterle
matrixxun/PullToZoomInListView
andraskindler/parallaxviewpager
simple-android-framework/android_design_patterns_analysis
daimajia/EverMemo
wasabeef/glide-transformations
sgolivernet/curso-android-src
syncthing/syncthing-android
romannurik/AndroidDesignPreview
Glamdring/EasyCamera
halysongoncalves/pugnotification
pungrue26/SelectableRoundedImageView
OrangeGangsters/LolliPin
telecapoland/jamendo-android
antonyt/InfiniteViewPager
shehabic/Droppy
xgc1986/ParallaxPagerTransformer
Jearil/SimpleNoSQL
Musenkishi/wally
FilipPudak/ProgressPieView
qiujuer/ImageBlurring
felipecsl/GifImageView
fabiendevos/nanotasks
mikepenz/Android-Iconics
glomadrian/MvpCleanArchitecture
cricklet/Android-PanesLibrary
JorgeCastilloPrz/ExpandablePanel
EddieRingle/android-undergarment
stormzhang/CustomLoading
ozodrukh/RippleDrawable
LukeDeighton/WheelView
Triggertrap/SeekArc
codinguser/gnucash-android
CyanogenMod/android_frameworks_base
christophesmet/android_maskable_layout
castorflex/FlipImageView
kolavar/android-support-v4-preferencefragment
scottyab/secure-preferences
percolate/caffeine
MustafaFerhan/DebugLog
vyshane/rex-weather
EddieRingle/hubroid
andraskindler/quickscroll
jenzz/Android-MaterialPreference
yingyixu/android-download-manager
drakeet/Seashell-app
InstantWebP2P/node-android
kenumir/android-calendar-card
liuguangqiang/SwipeBack
DWorkS/AStickyHeader
Narfss/ParallaxEverywhere
Almeros/android-gesture-detectors
pbreault/adb-idea
pardom/Ollie
android-cn/android-open-project-demo
lopspower/CircularImageView
sockeqwe/fragmentargs
CyanogenMod/android_packages_apps_Camera
Splitter/android_packages_apps_apolloMod
Kennyc1012/MultiStateView
AizazAZ/Android-Ultra-Photo-Selector
hongyangAndroid/Android-CircleMenu
jaredsburrows/AndroidGradleTemplate
vladexologija/PinterestListView
gast-lib/gast-lib
GeekZooStudio/ECMobile_Android
xiprox/WaniKani-for-Android
alexzaitsev/freepager
marshallino16/FloatingView
johnkil/SideNavigation
uberspot/2048-android
anupcowkur/Reservoir
charbgr/BlurNavigationDrawer
wasabeef/picasso-transformations
cryptocat/cryptocat-android
MoshDev/AndroidIndicators
yqritc/RecyclerView-FlexibleDivider
ryanhoo/Zhihu-Parallax-Animation
frankiesardo/LinearListView
CyanogenMod/android_packages_apps_Trebuchet
sbakhtiarov/gif-movie-view
moxie0/AndroidPinning
foxykeep/ContentProviderCodeGenerator
hidroh/materialistic
fengdai/AlertDialogPro
AigeStudio/DatePicker
nenick/android-gradle-template
badoo/android-weak-handler
palaima/DebugDrawer
JoanZapata/android-asyncservice
jjobes/SlideDateTimePicker
tomahawk-player/tomahawk-android
AlbertGrobas/PolygonImageView
amigold/FunDapter
almalence/OpenCamera
LuckyJayce/ViewPagerIndicator
bhavyahmehta/ListviewFilter
gueei/AndroidBinding
dlew/android-movies-demo
anismiles/websocket-android-phonegap
medyo/dynamicbox
Malinskiy/android-material-icons
Pirngruber/AndroidIM
limccn/Android-Charts
4thline/cling
luminousman/MultipleImagePick
Mariuxtheone/Teleport
mikepenz/wallsplash-android
cyndibaby905/TwitterCover-Android
nadam/nfc-reader
theredsunrise/AndroidCoolDragAndDropGridView
InQBarna/TableFixHeaders
NightWhistler/PageTurner
MartinvanZ/Inscription
pxb1988/dex2jar
kyze8439690/ResideLayout
dbachelder/CreditCardEntry
paypal/PayPal-Android-SDK
commonsguy/cwac-loaderex
blipinsk/FlippableStackView
antonkrasov/AndroidProgressLayout
ushahidi/SMSSync
PaNaVTEC/Clean-Contacts
WhisperSystems/Flock
anupcowkur/Android-Wheel-Menu
federicoiosue/Omni-Notes
japgolly/svg-android
litesuits/android-lite-http
blazsolar/FlowLayout
Manabu-GT/EtsyBlur
baoyongzhang/ActionSheetForAndroid
airk000/Trigger
sephiroth74/AndroidWheel
gdpancheng/LoonAndroid
akexorcist/Android-BluetoothSPPLibrary
mrmans0n/smart-location-lib
cookpad/puree-android
guardianproject/android-ffmpeg-java
wangjiegulu/WheelView
xplodwild/android_packages_apps_Focal
kongnanlive/android-combination-avatar
passy/scdl
chiragjain/Emoticons-Keyboard
PaulTR/AndroidDemoProjects
DroidPlanner/Tower
pwittchen/NetworkEvents
qdrzwd/VideoRecorder
ankurkotwal/making-apps-beautiful
walkingp/AndroidCnblogs
prey/prey-android-client
bugsnag/bugsnag-android
Arasthel/GoogleNavigationDrawerMenu
ismoli/DynamicRecyclerView
lukeFalsina/Grab-n-Run
ShogoMizumoto/ZDepthShadow
astuetz/ViewPagerExtensions
devunwired/custom-touch-examples
StanKocken/EfficientAdapter
Countly/countly-sdk-android
timroes/SwipeToDismissUndoList
ParsePlatform/ParseUI-Android
adennie/fb-android-dagger
zzz40500/Android-PullToNextLayout
yxl/DownloadProvider
sues-lee/SuesNews
chemouna/Decor
twotoasters/clusterkraf
ikarus23/MifareClassicTool
umeng/apf
novoda/sqlite-provider
PSDev/LicensesDialog
passy/Android-DirectoryChooser
brutall/brut.apktool
JorgeCastilloPrz/EasyMVP
j4velin/Pedometer
ragunathjawahar/instant-adapter
hzsweers/barber
Yalantis/CameraModule
surespot/android
nolanlawson/Catlog
LuckyJayce/MVCHelper
geftimov/android-patternview
mogoweb/chromium_webview
telly/groundy
evernote/evernote-sdk-android
halzhang/StartupNews
3pillarlabs/socialauth-android
mediarain/RoboCoP
h6ah4i/android-materialshadowninepatch
FredJul/Flym
birajpatel/GridListViewAdapters
swankjesse/android-http-examples
florent37/WearMenu
Jawnnypoo/PhysicsLayout
stormzhang/AndroidVolley
mg6maciej/android-maps-extensions
LyndonChin/MasteringAndroidDataBinding
linroid/Sky31Radio
quran/quran_android
erickok/transdroid
pedrovgs/TuentiTV
couchbaselabs/TouchDB-Android
curioustechizen/android-ago
evant/android-studio-unit-test-plugin
47deg/android-swipelistview-sample
ribot/easy-adapter
dlazaro66/WheelIndicatorView
BaiduQA/Cafe
jgilfelt/GhostLog
itzikBraun/TutorialView
square/haha
SnowdreamFramework/android-autoupdater
ukanth/afwall
jaydeepw/poly-picker
noinnion/newsplus
alt236/Bluetooth-LE-Library---Android
RaghavSood/AndroidCircularSeekBar
haseman/Android-AR-Kit
pires/android-obd-reader
Nammari/GooglePlusLayout
drakeet/AndroidUIView
bendemboski/DateSlider
cesarferreira/colorize
ManuelPeinado/NumericPageIndicator
jitsi/jitsi-android
googlecast/CastVideos-android
mcxiaoke/fanfouapp-opensource
pedrovgs/Lynx
liato/android-bankdroid
applidium/HeaderListView
sonyxperiadev/ChkBugReport
codebutler/android-websockets
openproject/AndroidDigest
nkzawa/socket.io-android-chat
PGSSoft/scrollscreenshot
MarkMjw/PullToRefresh
matshofman/Android-RSS-Reader-Library
cloay/CRefreshLayout
clayallsopp/routable-android
DesignativeDave/androrat
gothfox/Tiny-Tiny-RSS-for-Honeycomb
pedrovgs/Nox
ened/Android-Tiling-ScrollView
sephiroth74/android-floating-action-menu
jwood/standup-timer
bunnyblue/OpenAtlas
Lesilva/BetterSpinner
gonjay/rubychina4android
asystat/Final-Android-Resizer
nadavfima/GlowPadView
erchenger/SizeAdjustingTextView
SimonVT/android-calendarview
ustwo/clockwise
frapontillo/ImageViewEx
MirakelX/mirakel-android
TechBooster/AndroidOpenTextbook
kymjs/CJFrameForAndroid
romannurik/dashclock
Naturally-Being/G-Rex
CalebFenton/simplify
OrangeGangsters/CircularBarPager
googlesamples/android-play-location
MysticTreeGames/android-page-curl
freshplanet/ANE-Facebook
evant/holdr
google/patchfield
d-max/spots-dialog
jiahuanyu/CircleTimerView
AndroidDeveloperLB/MaterialPreferenceLibrary
LambergaR/VerticalViewPager
sheimi/SGit
leolin310148/ShortcutBadger
wujingchao/MultiCardMenu
ygorbarboza/AKParallax-Android
nostra13/Android-Simple-Social-Sharing
AndroidDeveloperLB/AndroidJniBitmapOperations
owncloud/News-Android-App
Tibolte/Android-Anim-Playground
commonsguy/cw-andtutorials
tajchert/BusWear
adamrocker/simple-side-drawer
CommonUtils/android
wearscript/wearscript-android
ushahidi/Ushahidi_Android
cesarferreira/AndroidQuickUtils
rahulparsani/google-io-2014-compat
frakbot/GlowPadBackport
tibi1712/Folding-Android
JackCho/AndroidVideoView
mixi-inc/Android-Device-Compatibility
ikocijan/MagicViews
47deg/appsly-android-rest
plattysoft/Leonids
gggard/AndroidCaldavSyncAdapater
bishopmatthew/HackerNews
mcxiaoke/Android-Next
konmik/nucleus
rorist/android-network-discovery
bradipao/desCharts
faradaj/BlurBehind
Karumi/HeaderRecyclerView
roman10/roman10-android-tutorial
tibi1712/FoldingNavigationDrawer-Android
jsonfry/uk.co.jasonfry.android.tools
daimajia/little-bear-dictionary
dm77/ZBarScanner
MiCode/legacy-patchrom
ahmetalpbalkan/orman
libpd/pd-for-android
j256/ormlite-core
sufficientlysecure/donations
GcsSloop/AndroidFontsManager
tuenti/SmsRadar
bmeike/ProgrammingAndroidExamples
rexstjohn/UltimateAndroidCameraGuide
sockeqwe/SwipeBack
JeroenMols/LandscapeVideoCamera
SimonVT/android-datepicker
ufo22940268/android-justifiedtextview
googledrive/android-demos
Pixate/pixate-freestyle-android
asksven/BetterBatteryStats
ryanhoo/PhotoCropper
pocmo/Yaaic
falnatsheh/MarkdownView
seven332/EhViewer
antoniolg/MaterializeYourApp
neevek/Paginize
petedoyle/android-support-v4-googlemaps
tianzhijiexian/ActivityOptionsICS
lemonlabs/ExpandableButtonMenu
orhanobut/bee
tyczj/MapNavigator
tgwizard/sls
sakebook/Reachability
Gregadeaux/android-fly-in-app-navigation
pchab/AndroidRTC
wuman/android-oauth-client
ribomation/DroidAtScreen1
denley/PreferenceInjector
klinker41/android-chips
wordpress-mobile/PasscodeLock-Android
futuresimple/android-db-commons
jjoe64/GraphView-Demos
lynfogeek/CollapsingHeader
cyrilmottier/Polaris2
maarek/android-wheel
coderkiss/ProMosaic
bilalsammour/DobList
litesuits/android-lite-async
javatechig/Advance-Android-Tutorials
marvinlabs/android-slideshow-widget
edubarr/header-decor
mthli/Bitocle
rtyley/android-screenshot-lib
wyouflf/xCombine
dodola/DynamicCardLayout
stephanenicolas/RoboDemo
nguillaumin/osmtracker-android
romannurik/FORMWatchFace
evant/rxloader
dineshshetty/Android-InsecureBankv2
thialfihar/apg
dmytrodanylyk/video-crop
QuadFlask/colorpicker
eleybourn/Book-Catalogue
wangjiegulu/AndroidBucket
nelenkov/android-backup-extractor
sromku/android-simple-storage
dmitry-zaitsev/CircleLayout
freshplanet/ANE-Push-Notification
diegocarloslima/ByakuGallery
felipecsl/QuickReturn
mkuklis/phonegap-websocket
florent37/DaVinci
dlew/android-gridlayout
googlemaps/hellomap-android
umeng/android_download_manager
T-Spoon/Android-Developer-Toolbelt
Hipmob/gifanimateddrawable
zeapo/Android-Password-Store
d-tarasov/android-intents
stanfy/enroscar
doridori/Dynamo
GhostFlying/LocationReportEnabler
Shusshu/Android-RecurrencePicker
greatyao/v2ex-android
johnjohndoe/TypedPreferences
cping/LGame
routerkeygen/routerkeygenAndroid
easemob/sdkexamples-android
ubergeek42/weechat-android
ymcao/fullplayer
rahatarmanahmed/CircularProgressView
feicien/StudyDemo
venmo/cursor-utils
liaohuqiu/android-cube-app
forcedotcom/SalesforceMobileSDK-Android
ravidsrk/AndroidGradleStarter
dlazaro66/QRCodeReaderView
alexbbb/android-upload-service
tommy351/ehreader-android
7heaven/SHSegmentControl
mycelium-com/wallet
shardul/Android
msdx/androidkit
inloop/AndroidViewModel
rfc2822/GfxTablet
wdullaer/MaterialDateTimePicker
honeynet/apkinspector
florent37/PicassoPalette
serso/android-calculatorpp
diegocarloslima/FloatingGroupExpandableListView
klinker41/android-smsmms
blazsolar/android-collapse-calendar-view
dmacosta/ATableView
adneal/Apollo-CM
GavinCT/AndroidMultiChannelBuildTool
avianey/androidsvgdrawable-plugin
dmytrodanylyk/realm-browser
psaravan/FileBrowserView
MatusKysel/EMVemulator
Onskreen/cornerstone
hanks-zyh/AnimateCheckBox
hanspeide/anytextview
xiprox/MarkView
GautamGupta/Simple-Android-OCR
HenriqueRocha/android-colorthief
googlesamples/android-XYZTouristAttractions
spengilley/ActivityFragmentMVP
pcgod/mumble-android
guardianproject/gnupg-for-android
vijayrawatsan/android-json-form-wizard
MohammadAdib/Roundr
rahulrj/ChromeOverflowMenu
lorensiuswlt/AndroidImageCrop
johncarl81/transfuse
deano2390/OpenFlappyBird
twitter-university/LearningAndroidYamba
wangdan/AisenForAndroid
bmeike/ProgrammingAndroid2Examples
erickok/mimicry
JesseGu/SinVoice
heruoxin/Clip-Stack
novoda/rxpresso
kontalk/androidclient
crosswalk-project/crosswalk-cordova-android
Takhion/android-extendedactionbar
boxme/AsyncManager
BeeFramework/BeeFramework_Android
dgmltn/Android-ShareEverywhere
antoniolg/DaggerExample
danoz73/QustomDialog
LivotovLabs/zxscanlib
Polidea/RoboSpock
Pedroafa/avatar-android
ppareit/swiftp
inloop/easygcm
rejasupotaro/Rebuild
inovex/ViewPager3D
mixpanel/mixpanel-android
thuytrinh/android-collage-views
martino2k6/StoreBox
plusonelabs/calendar-widget
AnySoftKeyboard/AnySoftKeyboard
JesusM/HoloCircleSeekBar
pardom/AndroidUtils
Kickflip/kickflip-android-sdk
phishman3579/android-heart-rate-monitor
ophilbert/ActivityTransition


출처 : https://raw.githubusercontent.com/Polidea/android-zoom-view/master/src/pl/polidea/view/ZoomView.java
public class ZoomListView extends ListView {
    private static final int INVALID_POINTER_ID = -1;
    private int mActivePointerId = INVALID_POINTER_ID;
    private ScaleGestureDetector mScaleDetector;

    private float mScaleFactor = 1.f;
    private float maxWidth = 0.0f;
    private float maxHeight = 0.0f;
    private float mLastTouchX;
    private float mLastTouchY;
    private float mPosX;
    private float mPosY;
    private float width;
    private float height;


    public ZoomListView(Context context) {
        super(context);
        mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener());
    }

    public ZoomListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener());
    }

    public ZoomListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        width = MeasureSpec.getSize(widthMeasureSpec);
        height = MeasureSpec.getSize(heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    public boolean onTouchEvent(@NonNull MotionEvent ev) {
        super.onTouchEvent(ev);
        final int action = ev.getAction();
        mScaleDetector.onTouchEvent(ev);
        switch (action & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN: {
                final float x = ev.getX();
                final float y = ev.getY();

                mLastTouchX = x;
                mLastTouchY = y;

                mActivePointerId = ev.getPointerId(0);
                break;
            }

            case MotionEvent.ACTION_MOVE: {
                final int pointerIndex = ev.findPointerIndex(mActivePointerId);
                final float x = ev.getX(pointerIndex);
                final float y = ev.getY(pointerIndex);
                final float dx = x - mLastTouchX;
                final float dy = y - mLastTouchY;

                mPosX += dx;
                mPosY += dy;
				
                if (mPosX > 0.0f)
                    mPosX = 0.0f;
                else if (mPosX < maxWidth)
                    mPosX = maxWidth;
				
                if (mPosY > 0.0f)
                    mPosY = 0.0f;
                else if (mPosY < maxHeight)
                    mPosY = maxHeight;

                mLastTouchX = x;
                mLastTouchY = y;

                invalidate();
                break;
            }

            case MotionEvent.ACTION_UP: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }

            case MotionEvent.ACTION_CANCEL: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }

            case MotionEvent.ACTION_POINTER_UP: {
                final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                final int pointerId = ev.getPointerId(pointerIndex);
                if (pointerId == mActivePointerId) {
                    final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                    mLastTouchX = ev.getX(newPointerIndex);
                    mLastTouchY = ev.getY(newPointerIndex);
                    mActivePointerId = ev.getPointerId(newPointerIndex);
                }
                break;
            }
        }

        return true;
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save(Canvas.MATRIX_SAVE_FLAG);
        canvas.translate(mPosX, mPosY);
        canvas.scale(mScaleFactor, mScaleFactor);
        canvas.restore();
    }

    @Override
    protected void dispatchDraw(@NonNull Canvas canvas) {
        canvas.save(Canvas.MATRIX_SAVE_FLAG);
        if (mScaleFactor == 1.0f) {
            mPosX = 0.0f;
            mPosY = 0.0f;
        }
        canvas.translate(mPosX, mPosY);
        canvas.scale(mScaleFactor, mScaleFactor);
        super.dispatchDraw(canvas);
        canvas.restore();
        invalidate();
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            mScaleFactor *= detector.getScaleFactor();
            mScaleFactor = Math.max(1.0f, Math.min(mScaleFactor, 3.0f));
            maxWidth = width - (width * mScaleFactor);
            maxHeight = height - (height * mScaleFactor);
            invalidate();
            return true;
        }
    }
}

}


츌처 : http://stackoverflow.com/questions/13991301/android-maps-api-v2-draw-circle
// 1. some variables:

    private static final double EARTH_RADIUS = 6378100.0;
    private int offset;

// 2. convert meters to pixels between 2 points in current zoom:

    private int convertMetersToPixels(double lat, double lng, double radiusInMeters) {

         double lat1 = radiusInMeters / EARTH_RADIUS;
         double lng1 = radiusInMeters / (EARTH_RADIUS * Math.cos((Math.PI * lat / 180)));

         double lat2 = lat + lat1 * 180 / Math.PI;
         double lng2 = lng + lng1 * 180 / Math.PI; 

         Point p1 = YourActivity.getMap().getProjection().toScreenLocation(new LatLng(lat, lng));
         Point p2 = YourActivity.getMap().getProjection().toScreenLocation(new LatLng(lat2, lng2));

         return Math.abs(p1.x - p2.x);
    }

// 3. bitmap creation:

    private Bitmap getBitmap() {

        // fill color
        Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint1.setColor(0x110000FF);
        paint1.setStyle(Style.FILL);

        // stroke color
        Paint paint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint2.setColor(0xFF0000FF);
        paint2.setStyle(Style.STROKE);

        // icon
        Bitmap icon = BitmapFactory.decodeResource(YourActivity.getResources(), R.drawable.blue);

        // circle radius - 200 meters
        int radius = offset = convertMetersToPixels(lat, lng, 200);

        // if zoom too small
        if (radius < icon.getWidth() / 2) {

            radius = icon.getWidth() / 2;
        }

        // create empty bitmap 
        Bitmap b = Bitmap.createBitmap(radius * 2, radius * 2, Config.ARGB_8888);
        Canvas c = new Canvas(b);

        // draw blue area if area > icon size
        if (radius != icon.getWidth() / 2) {

            c.drawCircle(radius, radius, radius, paint1);
            c.drawCircle(radius, radius, radius, paint2);
        }

        // draw icon
        c.drawBitmap(icon, radius - icon.getWidth() / 2, radius - icon.getHeight() / 2, new Paint());

        return b;
    }

// 4. calculate image offset:

    private LatLng getCoords(double lat, double lng) {

        LatLng latLng = new LatLng(lat, lng);

        Projection proj = YourActivity.getMap().getProjection();
        Point p = proj.toScreenLocation(latLng);
        p.set(p.x, p.y + offset);

        return proj.fromScreenLocation(p);
    }

// 5. draw:

        MarkerOptions options = new MarkerOptions();
            options.position(getCoords(lat, lng));
            options.icon(BitmapDescriptorFactory.fromBitmap(getBitmap()));

            marker = YourActivity.getMap().addMarker(options);

and result:

google maps v2 draw circle

먼저 리스트뷰에서는 다음처럼 설정한다.

예)  listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);


그러면 이제 체크 상태를 ListView가 관리하게 된다. 그런데, custom view를 쓰면 ListView가 그 안에 있는 뷰 중 Checkable이 있으면 checked 상태를 바꾼다. 이 점을 이용하면 checkbox와 연동하게 할 수 있다.


getView에서는 checkbox를 다음과 같이 설정한다. 안드로이드의 ListView에서는 focusable 뷰가 포함되어 있으면 onItemClick을 비롯한 여러 가지 ListView의 기본 동작이 안 먹는다. 그래서 CheckBox에서 focusable을 빼는 것. 그러면 리스트의 항목을 클릭할 때 checkbox가 연동되게 된다. 그런데, 여기까지만 하면 checkbox를 직접 클릭할 때는 그 상태가 ListView와 연동되지 않으므로 checkbox의 clickable을 빼야 한다.

예)     CheckBox checkbox = (CheckBox) convertView.findViewById(R.id.Checkbox);
        checkbox.setChecked(((ListView)parent).isItemChecked(position));
        checkbox.setFocusable(false);
        checkbox.setClickable(false);


버그(?)라고 해야 할지 모르겠으나 안드로이드는 적은 메모리를 사용하는 모바일에서 작동하는 프로그램이기때문에 자원의 재사용에 중점을 많이 두었기에 그런 현상이 발생된다. 


//Uri에서 이미지 이름을 얻어온다.

                    final Uri selectImageUri = intent.getData();


                    final String[] filePathColumn = {MediaStore.Images.Media.DATA};



                    final Cursor imageCursor = this.getContentResolver().query(selectImageUri, filePathColumn, null, null, null);


                    imageCursor.moveToFirst();



                    final int columnIndex = imageCursor.getColumnIndex(filePathColumn[0]);


                    final String imagePath = imageCursor.getString(columnIndex);


                    imageCursor.close();

안드로이드 3.0이후부터는 onCreate함수 안에 아래 라인을 추가해야 하네요
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads() 
.detectDiskWrites()
.detectNetwork() 
.penaltyLog().build()); 
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

참고 사이트
http://android-developers.blogspot.kr/2010/12/new-gingerbread-api-strictmode.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed:+blogspot/hsDu+(Android+Developers+Blog)


요즘 android에 손댈 일이 없어 테스트는 아직 못해보았습니다ㅠㅠ


2012.10.14 iBluemind님 추가 내용입니다^^ 감사합니다(_ _)

StrictMode라는 API가 안드로이드 진저브레드에서부터 탑재되기 시작했습니다. 그리고, 안드로이드 허니콤부터는 이 StrictMode가 기본적으로 항상 Enable 되게 되었기 때문에, 네트워크 요청이나 디스크 IO와 관련된 처리들은 무조건 UI 스레드와 분리해서 처리해야 하게 되었습니다.

하지만, '꼼수'로 이 StrictMode를 해제하여 네트워크 처리를 UI 스레드에서도 처리할 수 있게끔 할 수 있는 것입니다. 그런데, Seriane님의 댓글에 소개된 코드는 오히려 StrictMode를 Enable하는 코드입니다. 링크해주신 페이지를 보더라도 진저브레드에서 이를 켜는 것이라고 소개되어 있지요.

그래서, 네트워크 처리와 디스크 IO 처리 부분에 대한 StrictMode를 Disable하는 방법은 다음과 같습니다.

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.permitDiskReads() 
.permitDiskWrites()
.permitNetwork().build());


@Override
  public boolean shouldOverrideUrlLoading(WebView view, String url) {

   final String items[] = {"갤러리에서 가져오기","카메라로 촬영하기"};
   if (url.startsWith("custom://")) {
      new AlertDialog.Builder(MyPageWeb.this)
         .setIcon(R.drawable.icon)
         .setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
         public void onClick(DialogInterface dialog, int item) {
             Toast.makeText(getApplicationContext(), Integer.toString(item), Toast.LENGTH_SHORT).show();
             dialog.dismiss();
              
             if(item==0) {
//갤러리 호출
              Uri uri = Uri.parse("content://media/external/images/media");
                 Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                 intent.setAction(Intent.ACTION_GET_CONTENT);
                 intent.setType("image/*");
                 startActivityForResult(intent, REQ_SELECT);

             } else if(item==1) {
//카메라로 찍기
              Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 startActivity(intent);
             }
         } 
         })

        .show();
   }
}



//////////////////////////// 선택 하면 리턴값 받기
@Override
 protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
   super.onActivityResult(requestCode, resultCode, intent);
    try {
     if(!intent.getData().equals(null)){

      Bitmap selPhoto = Images.Media.getBitmap(getContentResolver(), intent.getData());

     selPhoto = Bitmap.createScaledBitmap(selPhoto, 100, 100, true);

//      image_bt.setImageBitmap(selPhoto);//썸네일
      Log.e("선택 된 이미지 ", "selPhoto : " + selPhoto);
     }
     
    } catch (FileNotFoundException e) {
     e.printStackTrace();
    } catch (IOException e) {
     e.printStackTrace();
    }

 }

출처 : http://lky1001.tistory.com/47

액션바의 서치뷰에서 검색어를 입력 후 소프트 키보드의 돋보기를 누르고 검색후에도 다시 돋보기 모양으로 바뀌지 않고 그 내용이 그대로 남아 있다.

플레이스토어에서는 검색을 하면 다시 돋보기 모양으로 바뀐다...


이 상태로 돌아가고 싶은데


이 상태로 남아있는다.



구글링한 결과 .. MenuItem 클래스의 collapseActionView() 메소드를 이용하면 된다.

액션바는 액션바셜록 사용


멤버변수 MenuItem mSearchItem 선언


@Override

public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) {

// TODO Auto-generated method stub

        //Used to put dark icons on light action bar

        //boolean isLight = SampleList.THEME == R.style.Theme_Sherlock_Light;


        //Create the search view

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        mSearchView = new SearchView(getSupportActionBar().getThemedContext());

        mSearchView.setQueryHint("버스 번호 또는 정류장명");

        mSearchView.setOnQueryTextListener(queryTextListener);      


        menu.add("Search")

            .setIcon(true ? R.drawable.ic_search_inverse : R.drawable.abs__ic_search)

            .setActionView(mSearchView)

            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);


        menu.add("Back")

        .setIcon(true ? R.drawable.ic_refresh_inverse : R.drawable.ic_refresh)

            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);

        

        mSearchItem = menu.getItem(0);

        return true;

}


private OnQueryTextListener queryTextListener = new OnQueryTextListener() {


@Override

public boolean onQueryTextSubmit(String query) {

// TODO Auto-generated method stub

mSearchItem.collapseActionView();

return false;

}


@Override

public boolean onQueryTextChange(String newText) {

// TODO Auto-generated method stub

return false;

}

출처 : http://nlopez.io/how-to-style-the-actionbar-searchview-programmatically/

I stumbled upon a problem with the styling of a view at work. I had almost everything solved with a custom theme, but it all came down to style a SearchView widget of an ActionBar.

The unstyled version

That's where the fun begins.

All of this must happen in your onCreateOptionsMenu method. With a reference to your SearchView object in there, you can start doing things.

For example, if you'd like to get a reference to its EditText, you could do it using reflection like in this snippet.

int searchSrcTextId = getResources().getIdentifier("android:id/search_src_text", null, null);  
EditText searchEditText = (EditText) searchView.findViewById(searchSrcTextId);  
searchEditText.setTextColor(Color.WHITE);  
searchEditText.setHintTextColor(Color.LTGRAY);  

For changing the close icon, this one.

int closeButtonId = getResources().getIdentifier("android:id/search_close_btn", null, null);  
ImageView closeButtonImage = (ImageView) searchView.findViewById(closeButtonId);  
closeButtonImage.setImageResource(R.drawable.ic_action_cancel);  

And so on. You can get all the references in either the Android code for SearchView.java, or in its layout. For the lazy ones, here are some of those references that you can retrieve (and play with).

// This excerpt is from Android source code (SearchView.java)
mSearchButton = findViewById(R.id.search_button);  
mSearchEditFrame = findViewById(R.id.search_edit_frame);  
mSearchPlate = findViewById(R.id.search_plate);  
mSubmitArea = findViewById(R.id.submit_area);  
mSubmitButton = findViewById(R.id.search_go_btn);  
mCloseButton = (ImageView) findViewById(R.id.search_close_btn);  
mVoiceButton = findViewById(R.id.search_voice_btn);  
mSearchHintIcon = (ImageView) findViewById(R.id.search_mag_icon);  

But as you probably can see in Android's code, you have no direct access to the SearchAutoComplete class. The problem with that is that it's difficult to you to be able to style the magnifying glass next to the hint text.

You can set up with searchView.setQueryHint("your hint") its hint and you can hide it with searchView.setIconifiedByDefault(false) - though that's even worse because then the search icon is at the left of the EditText and it looks ugly.

The ugly version

The thing is, that icon at the left of the hint text is done in Android by using an ImageSpan in a SpannableString, and it depends directly on the theme applied to the control. But what happens if you can't change the theme? (like in my case). Then you have to do more dirty and ugly stuff.

// Accessing the SearchAutoComplete
int queryTextViewId = getResources().getIdentifier("android:id/search_src_text", null, null);  
View autoComplete = searchView.findViewById(queryTextViewId);

Class<?> clazz = Class.forName("android.widget.SearchView$SearchAutoComplete");

SpannableStringBuilder stopHint = new SpannableStringBuilder("   ");  
stopHint.append(getString(R.string.your_new_text));

// Add the icon as an spannable
Drawable searchIcon = getResources().getDrawable(R.drawable.ic_action_search);  
Method textSizeMethod = clazz.getMethod("getTextSize");  
Float rawTextSize = (Float)textSizeMethod.invoke(autoComplete);  
int textSize = (int) (rawTextSize * 1.25);  
searchIcon.setBounds(0, 0, textSize, textSize);  
stopHint.setSpan(new ImageSpan(searchIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

// Set the new hint text
Method setHintMethod = clazz.getMethod("setHint", CharSequence.class);  
setHintMethod.invoke(autoComplete, stopHint);

And that's it. Ugly and hacky as promised.

Styled, finally!

But works!

앞페이지에서 옵션메뉴를 하였다
옵션메뉴는 전화기의 하단 왼쪽 화면 밖을 크릭하면 나타나는 것
프로그램들 마다 다양한 형식의 메뉴시스템을 제공하듯이
안드로이드에는 이것만 있는 것이 아니고
윈도우시스템의 상단 메뉴줄과 같은 것도 있을 것이다
이것을 Action Bar라고 부른다
이번 페이지에서는 Action Bar에 앞의 페이지에서 만든 것을
옮겨 보자
아주 간단하다

&lt;?xml version="1.0" encoding="utf-8"?&gt; &lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt; &lt;item android:id="@+id/menu_calculator" android:title="Calculator" /&gt; &lt;item android:id="@+id/menu_news" android:title="News" /&gt; &lt;item android:id="@+id/menu_search" android:title="Search" /&gt; &lt;item android:id="@+id/menu_location" android:title="Location" /&gt; &lt;item android:id="@+id/menu_alarm" android:title="Alarm" /&gt; &lt;item android:id="@+id/menu_google_play" android:showAsAction="ifRoom|withText" android:title="GooglePlay" /&gt; &lt;/menu&gt; 위의 메뉴를 구성하는 xml화일을 Activity 크래스의 아래 메소드에서 불러 들여서 옵션메뉴를 설치하였던 것이다 public boolean onCreateOptionsMenu(Menu menu) { MenuInflater menuInflater = getMenuInflater(); menuInflater.inflate(R.menu.activity_main, menu); return true; }

Action Bar로 옵션메뉴의 내용을 옮겨본다면 위에서 마지막 메뉴
GooglePlay라는 곳에 

android:showAsAction="ifRoom|withText"

한줄 삽입하면 해당 메뉴는 Action Bar로 옮겨진다
앞페이지 쏘스에 위와 같이 한줄만 달랑 바꾸고 실행시켜보시면
화면상단 타이틀바에 메뉴가 나타남을 볼수 있을 것이다

그런데 Action Bar에 메뉴아이템 6개 전부에

android:showAsAction="ifRoom|withText"

와 같은 속성(Attribute)을 준다면 
Action Bar의 공간이 좁다..그래서 공간이 되는 만큼만 Action Bar에
메뉴가 나타나고, 나머지는 Option Menu공간에 그대로 남게 된다
말그대로 이다
"ifRoom|withText"라는 속성값은
If 만약에 Room 공간이 있다면 문자로 표현한다 with Text 인것이다
그래서 아래와 같이 menu.xml 화일의 내용을 표현하였다면


그림과 같이 Action Bar와 Option Menu로 분배되어 표현된다
그래서 메뉴공간을 활용하기 위하여 Text로 표현하는 것 보다는
Icon 으로 표현하면 좁은 공간에 많은 메뉴를 표현할수 있을 것이다

조그만 화면에 표현을 하기 위하여서는 그림으로 표현하는 것이 바람직하다
그래픽의 폴더가 몇가지의 성격은 아래와 같다



작은 그림 Icon을 넣고 싶다면 아래와 같이 속성을 넣는다

&lt;item android:id="@+id/menu_calculator" android:showAsAction="ifRoom|withText" android:icon="@drawable/ic_action_calculator" android:title="calculator" /&gt;

아래와 같이 태그내의 속성에 icon속성을 넣는 것이다

android:icon="@drawable/ic_action_calculator"
이때..drawable은 위의 그림의 폴더중에 drawable_ldpi,drawable_mdpi,,,,폴더
내에서 아무것이나 화일이름이 ic_action_calculator.jpg 인것을 찾아서
올리게 되는 것이다
이때...좀더 정교하게 설계를 한다면 위의 각 폴더별 icon해상도에
맞추어 넣어주면 가장적절한 해상도의 것을 알아서 찾아
올리게 되는 것이다
해상도가 맞지 않도라고 같은 화일이 다른 해상도에 있다면
이것을 갖여다 사용하고..

이 아이콘을 죄다 만들어야 하나..
Google에서 다운 받으면 기본적인 것들이 만들어져 있으니 활용하면 된다

다운 받으면 아래와 같이 좋은 자료가 된다



위의 그림을 안드로이드프로젝트의 해상도에 맞는 홀더에
넣어주고..menu.xml에서 속성으로 어떤 그림을 사용하겠다고 지정하고
Activity크래스가 실행되면서 이 menu.xml화일을 읽어서
화면에 아래의 그림과 같이 Action Bar에 배치해주게 되는 것이다



Action Bar바탕색이 검정색이니까..이때 아이콘은 검정색의 외의 것으로
사용하여야 나타날 것이다

어라...그런데 Option Menu의 6개의 메뉴를 모두 아이콘으로
만들어 Action Bar에 올리려고 하는데
반만 올라가고 나머지는 여전히 Option Menu에 남아있다
아래의 그림의 맨마지막과 같이 하고 싶다



public class MainActivity extends Activity { 
   public void onCreate(Bundle savedInstanceState) { 
       super.onCreate(savedInstanceState); 
       setContentView(R.layout.activity_main); 

       	ActionBar actionBar = getActionBar();
   		actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM
   				| ActionBar.NAVIGATION_MODE_STANDARD);
       
       
       
   } 

Activity(화면)개체가 생성되면 OnCrete메소드에서
ActionBar개체를 찾아서
setDisplayOptions에 위와 같이 설정하면 App Icon과
App Title이 사라진다
그러면 Action Bar폭에 여유가 생겨서 많은 사용자정의
메뉴를 삽입하게 되는 것
그리고 menu.xml화일에서 각 menu Item의 속성을
android:showAsAction="ifRoom" 혹은 
adnroid:showAsAction="ifRoom|withText" 을
withText라는 값은 만약 여러분이 옵션메뉴에 만든
메뉴아이템에 Title이 있을 경우 Title도 아이콘과 같이
Action Bar에 나타나게 해주는 것
여기에서는 아이콘만 나타나게 하였으므로 "ifRoom"만 주면 된다
아래와 같이 바꿔준다
android:showAsAction="always"
위의 layout xml 화일에서 속성을 줄때 ="값_A|값_B|값_C"와 같이
|로 나누어서 여러개의 값을 전달하는 문법
Java코드에서도

actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM
     | ActionBar.NAVIGATION_MODE_STANDARD);

와 같이 여러개의 값을 전달 하는 문법을 잘 챙기시고..

***[LOG-IN]***



TextView 에서 원하는 부분에 말줄임 넣는 프로그래밍 
final TextView title = (TextView)findViewById(R.id.text);
        title.setText("A really long text");
        ViewTreeObserver vto = title.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

            @Override
            public void onGlobalLayout() {
                ViewTreeObserver obs = title.getViewTreeObserver();
                obs.removeGlobalOnLayoutListener(this);
                if(title.getLineCount() > 3){
                    Log.d("","Line["+title.getLineCount()+"]"+title.getText());
                    int lineEndIndex = title.getLayout().getLineEnd(2);
                    String text = title.getText().subSequence(0, lineEndIndex-3)+"...";
                    title.setText(text);
                    Log.d("","NewText:"+text);
                }

            }
        });


바로가기 : http://nekomimi.tistory.com/666

출처 : http://reddolphin.tistory.com/100


* 카카오톡과 마이피플 심층 분석이랄까….???

  - 카톡, 마플 앱 트래픽, 예상 구현 방법.

* Networking Tutorial for iOS: How To Create A Socket Based iPhone App and Server

* SocketRocket Objective-C WebSocket Client(beta)
  - Socket을 이용한 Chat 구현 오픈 소스.
  - Client, Server 

* MultipeerGroupChat 
  - Apple 예제. iOS7 or later

* XMPP
  - 위키피디아 정리
  - 사이트

* XMPP 소개
  - 소개글. (아키택처, 프로토콜, Ruby 예제 등 간략.)

* XMPPFramework
  - Open Source

* [Server] 공개 채팅서버 OpenFire 설치, 구동 
  - XMPP 윈도우 설치

* XMPP 소개

* Openfire
  - XMPP 서버를 사용하여 IM, Group Chat 등 가능, JAVA, Apache License 
  - Jive software의 igniteRealTime에서 운영.

* Google App Engine XMPP를 활용하여 Android Push Service 만들기(2)

* 구글 앱 엔진 XMPP 활용해 안드로이드 푸시 서비스 구현

* Building a Jabber Client for iOS: XMPP Setup

* APNS, Sockets,  Polling 에 대한 질문.
  - APNS 사용하라고 얘기.

* 아이폰챗 v0.9
  - 개인 블로그, 에제, 서버 & 클라이언트.

* MultipeerGroupChat
  - 
* 안드로이드 채팅 예제

* 채팅 관련 맥부기 Q&A
  -  클래스를 쓰레드로 만들수있나요? 채팅앱만들고있습니다.
  - 카카오톡 등의 채팅어플에서 대화방의 이모티콘 출력 방식 질문드립니다..
  - XMPP 관련 도움부탁드려요,
  - 채팅UI제작중에 입력칸 질문입니다.
  - NSStream vs CGSocket

* Tigase Install
  - 설치 할 때의 정리 문서.(한글)

* Tigase Project
  - Open Source and Free XMPP/Jabber Software

* GitHub Searching ‘chat’

* IBM x-ioschat

* 비영리 오픈소스 메신저 ‘텔레그램’

* Facebook 메신저와 MQTT


출처 : http://charlie0301.blogspot.kr/2013/06/fragmentactivity-fragmenttabhost.html

FragmentActivity, FragmentTabHost 사용하기

이전 블로그에서 이전 함 (원본 글 2013/06/27 작성)

아래 처럼 FragmentTabHost를 사용하면서 이것저것 하려니 개고생 함..
그냥 Android Project를 하나 만들고 MainActivity를 만들때 Navigation Type을 Scrollable Tabs+Swipe로 선택하여
SectionPagerAdapter + FragmentActivity 예제를 만들어 참고하여 app 만드는게 편함..


--------------------------------------------------------------------------------------------------

TabActivity가 deprecated 되면서 FragmentActivity & FragmentTabHost를 사용하게 되어
보던 중 생각보다 Google documentation이 부실해서 여기저기 찾아보고 정리함.

[Android Support Libraries 다운로드 및 설치]

> 아래 처럼 Android SDK Manager를 통해서 다운로드 하고 개발중인 project의 lib에 복사하고 project libraries로 추가

 Downloading the Support Package

The Support Package is provided as a downloadable package from the Android SDK Manager. To install:
  1. Launch the Android SDK Manager.
    From Eclipse, you can select Window > Android SDK Manager. Or, launch SDK Manager.exe from the <sdk>/ directory (on Windows only) or android from the <sdk>/tools/ directory.
  2. Expand the Android Repository, check Android Support package and click Install selected.
  3. Proceed to install the package.
When done, all files (including source code, samples, and the JAR files) are saved into the<sdk>/extras/android/support/ directory. This directory contains each of the different support libraries, such as the library for API level 4 and up and the library for API level 13 and up, each named with the respective version (such as v4/).

Setting Up a Project to Use a Library


To add one of the libraries to your Android project:

Add the JAR file to your project.
Copy the JAR file for the library you want to use into your Android project. To do this:

  • Create the directory libs/ at the root of your project (next to src/, res/, and so forth).
  • Locate the JAR file for the library you want to use and copy it into the libs/ directory.
    For example, the library that supports API level 4 and up is located at <sdk>/extras/android/support/v4/android-support-v4.jar.
Your build system may expect to find the JAR file in a directory other than libs. Read the documentation for your build system to learn where to put the JAR file.

<dl style="color: rgb(34, 34, 34); font-family: Roboto, sans-serif; font-size: 14px; line-height: 19px; background-color: rgb(249, 249, 249);">
If necessary, add the libs/ directory to your build path.
Read the documentation for your build system to learn how to add the JAR file to the build path.
</dl>


[Fragment 개념] 
> Fragment에 대한 전반적인 tutorial.. 추천

[FragmentTabHost reference]

> 사실 아래 예제가 다임.. 좀 더 자세한 설명은 아래 링크를 참고. 
   TabHost.addTab() 에서 class들은 Fragment를 상속받아 만든 class 들임.

 Here is a simple example of using a FragmentTabHost in an Activity:
import com.example.android.supportv4.R;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTabHost;
/**
 * This demonstrates how you can implement switching between the tabs of a
 * TabHost through fragments, using FragmentTabHost.
 */
public class FragmentTabs extends FragmentActivity {
    private FragmentTabHost mTabHost;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.fragment_tabs);
        mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
        mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);

        mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
                FragmentStackSupport.CountingFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
                LoaderCursorSupport.CursorLoaderListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
                LoaderCustomSupport.AppListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
                LoaderThrottleSupport.ThrottledLoaderListFragment.class, null);
    }
}
This can also be used inside of a fragment through fragment nesting:
import com.example.android.supportv4.R;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTabHost;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class FragmentTabsFragmentSupport extends Fragment {
    private FragmentTabHost mTabHost;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        mTabHost = new FragmentTabHost(getActivity());
        mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.fragment1);

        mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
                FragmentStackSupport.CountingFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
                LoaderCursorSupport.CursorLoaderListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
                LoaderCustomSupport.AppListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
                LoaderThrottleSupport.ThrottledLoaderListFragment.class, null);

        return mTabHost;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mTabHost = null;
    }
}

[FragTabHost 사용 상세 예제들]

> 모든 코드(Fragment classes) 포함

> 좀 자세한 설명

[FragTabs를 아래로 위치시키기]

> 웹상에서는 Relative를 사용하거나 Linear의 weight를 사용하는 방법 아니면 Custom tab을 사용하는 방법이 있지만 위에서는 간단하게 해결 함. 아래는 살짝 수정한 코드
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="1" >

    <FrameLayout
        android:id="@+id/realtabcontent"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1" />

    <android.support.v4.app.FragmentTabHost
        android:id="@android:id/tabhost"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="0dp"
            android:layout_height="0dp" />

        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
    </android.support.v4.app.FragmentTabHost>

</LinearLayout>


[Fragment Tab 간 data 전달]
> Android Developers site의 Fragment 관련 내용에서 나오는 내용.

> 좀 더 상세한 내용, 사실 Fragment의 Tag를 알아내는 방법을 몰라 좀 고생했었음.
   Activity에 Tag를 받는 함수를 만들고 각 Fragment Tab이 생성 되었을 때 Activity의 함수를 통해 Tag을 등록
   좀 나이스 한 방법은 아니지만.. 일단 뭐...
 public class MyFragmentB extends Fragment {

 TextView b_received;
 
 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
   Bundle savedInstanceState) {
  View myFragmentView = inflater.inflate(R.layout.fragment_b, container, false);
  
  b_received = (TextView)myFragmentView.findViewById(R.id.b_received);
  String myTag = getTag();
  
  ((AndroidViewPagerActivity)getActivity()).setTabFragmentB(myTag);


[기타]
> 코드가 좀 이상하네...


출처 : http://givenjazz.tistory.com/44



20개 정도 규칙이 있으며 출처는 source.android.com에서 좀 더 자세한 내용을 볼 수 있다.

build된 sdk에는 없지만 sdk 소스를 다운받으면 이클립스용 코딩 포맷과 import순서가 정보가 적힌 xml파일도 같이 받을 수 있는데, 이 글에 첨부했다.

android-formatting.xml은 "Window › Preferences › Java › Code Style > Formatter 에 import하고,
android.importorder "Organize Imports에 import하면
Shift+command+F로 자동포멧정리 기능을 안드로이드에 맞게 사용할 수 있다.

  1. Exceptions: 예외 무시하지말고 처리하기.
  2. Exceptions: 상위 Exception으로 싸잡아서 처리하지 않기.
  3. Finalizers: 왠만하면 쓰지않기 (언제 적용될지 모름)
  4. Imports: *쓰지말고 정확하게 풀네임 적기.

Java Library Rules

표준 코딩컨벤션이 바뀌어서 예전 코딩컨벤션과 충돌이 난다면 예전 코딩컨벤션으로 작성해서 일관성을 유지하기.

Java Style Rules

자바표준 컨벤션에서 추가사항:

  1. Comments/Javadoc: 표준대로 작성하기.
  2. Short methods: 메소드는 40줄이 넘지않게 짧게 작성하기
  3. Fields: 초기에 선언하기나 사용하기 바로 전에 선언할 것.
  4. Local variables: 지역변수 범위는 최소화하기.
  5. Imports: 안드로이드, 서드파티(알파벳 순), java, javax 순으로 import하기.
  6. Indentation: 탭안쓰고 공백 4개 사용하기.
  7. Line length: 한줄에 100칸 이하 유지하기.
  8. Field names: Non-public, non-static 변수는 m으로 시작하고, static변수는 s로 시작하기.
  9. Braces: { 는 줄넘기지말고 사용하기
  10. Annotations: 표준 어노테이션 사용하기.
  11. Acronyms are words: XMLHTTPReques처럼 적지말고 XmlHttpRequest로 적기
  12. TODO style: "TODO: write this description"
  13. Consistency: 일관적으로 작성하기
  14. Logging: 로그도 비용이 드니 적절하기 사용하기
    ERROR > WARNING > INFORMATION > DEBUG > VERBOSE 사용할 것.
    한줄에 출력할 수 있는 80~100글자가 적당.
    StringBuilder는 기본버퍼가 16character라 String보다 항상 좋다고 할 수 없으니 확신이 없으면 그냥 String연산이 무난.
    System.out.print는 어차피 /dev/null로 던져버리니 절대 쓰지말 것. 괜히 비용만 잡아먹음.

Javatests Style Rules

  1. Naming test methods: testMethod_specificCase 이런식으로 이름짓기


Kick-Start: Bower – A Simple Tutorial of Setting-Up and Using Bower.JS

The goal of this post is to provide a simple description of how to install Bower JS and how to use Bower JS to manage client side dependencies. The first time I tried to use Bower I had problems. Hopefully this tutorial will provide others a complete resource to navigate around the issues that I found.

Assumptions:

  • You are a Windows developer
  • You will use the Windows Command Prompt instead of Bash
  • You have little or no knowledge of Node.js
  • You have little or no knowledge of GIT

1. Download and install Node.js

To run Bower you will need to download and install Node.js. Go to http://nodejs.org/ website and select the “install” button (see image below). This should download the version of Node.js you need. For me, when I clicked the “install” the version for Windows 64-bit downloaded. Once Node.js is download, execute the file.

I will not go thought the steps for installing Node.js; it’s very straight forward. During the install I used all default options.

2. Confirm Node.js is installed

When Node.js installation has completed we need to confirm it was installed successfully. Open a Windows Command Prompt and type “Node” and [enter]. You should get prompted with a “>”.

(If you previously had Windows Command Prompt open, you will need to close it and reopen it. The reason is that Node will be added to Environment Variable Path. If the Command Prompt is open when you install Node, it will not have the new Node Path.)


Now at the prompt type something like “2 + 2″ and [enter]. You should get a result. I got back 4. Now we have confirmed that Node.js is installed correctly. You can quit Node.js by using the keyboard and typing [ctrl]+C twice.

3. Create Folder Structure

Create the following folder structure.

(In the image above, ignore “External Libraries”. This is part of the WebStorm IDE)

4. Install Bower

The primary reason to use Bower is so that you do not have to manage client side dependencies (css, JavaScript, and etc). Here we will install Bower so that we can use it latter to manage dependencies.

Use Node Package Manger (npm) to install Bower. Since we are using the “-g” (global) switch we can install Bower from any directory.

(The npm statement is case sensitive.)

5. Test Bower is Installed

Since we will want to install the dependencies in the “app” direction, go ahead and navigate to the “app” directory”

Lets do a Bower search for jQuery. Remember, it is case sensitive

There is a ton of jQuery libraries. But that’s okay.

6. Install Dependencies (jQuery & Underscore)

In the command window enter “bower install jQuery” and press [Enter]. Again remember case sentitivity.

You may receive an error if you do not have GIT installed.

Install GIT

From Bower’s website (bower.io) you can get to GIT’s (git-scm.com) website to down GIT.

From GIT’s (git-scm.com) download GIT

When I installed GIT, I used all the defaults. But a key option that needs to be select is to “Run Git from the Windows Command Prompt”. This will add the PATH variable for Git.

8.Install Dependencies (jQuery & Underscore) – Again

Important – Close the current Command Prompt. If you attempt to install jQUery again with the current command prompt you will get the same error.

Open a new Command Prompt and navigate to the “app” directory that we created previously.

Install jQuery using Bower. Remember, it’s case sensitive.

Now install Underscore

9. Confirm Dependencies

There should be a new directory create by Bower call “bower_components” this is where jQuery and Underscore should have been installed at.

10. Finished

No you can go out and create your application without having to worry maintaining client side dependencies.

I hope this helped.


http://www.yongcloud.co.kr/android_tip.html

'Android > Tip&Tech' 카테고리의 다른 글

[펌]안드로이드 코딩 스타일 안내(가이드)  (0) 2014.11.19
npm 및 bower 설치..  (0) 2014.11.18
[펌]LoaderManager 동작이해  (0) 2014.10.21
[펌]안드로이드 Loader 활용하기  (0) 2014.10.21
자바 표준 스타일 정의  (0) 2014.09.30
출처 : http://i5on9i.blogspot.kr/2013/02/loadermanager.html

LoaderManager Sequence Diagram / LoaderManager flowchart / 


android 3.0 이후부터 LoaderManager 를 제공한다. comparability package 를 사용하면 1.6 에서부터 사용가능하다고 한다.


Loaders 의 특징

  1. every Activities or Fragments : 모든 Activity 와 Fragment 에서 가능하다.(한 activity 또는 fragment 당 한개의 LoaderManager 를 갖는다. 한 개의 LoaderManager 는 여러개의 Loaders 를 가질 수 있다.)
  2. async data loading : data의 비동기 loading 을  을 제공한다.
  3. monitor and deliver the data source : data 의 source 를 모니터하면서 content 가 변경되면 전달해 준다.
  4. automatically reconnect : configuratoin 이 바뀐후(orientation 이 변경되는 것 등의)에 다시 만들어 질 때, 자동적으로 마지막으로 사용한 loader의 cursor 에 접속한다. 그래서 data 를 다시 query 할 필요가 없다.
만약 download 를 하고 있고, 그 progress 를 activity 에서 보여주고 있다면, download 를 하는 도중에 화면의 orientation 을 전환하면 값을 잃어버리게 된다. 이런 경우에 LoaderManager 를 이용하면 좋다고 한다.[ref. 9]



Loader Callbacks

LoaderManager 가 시작할 때 , 끝날 때 우리가 원하는 일을 시킬 수 있다. 이 일을 하는 것이 LoaderCallbacks 이다. 이 LoaderCallbacks 는 LoaderManager.initLoader() 에서 register 하게 된다.


LoaderManager.LoaderCallbacks<?> 을 implement 하면
  • onCreateLoader()
  • onLoadFinished()
  • onLoaderReset()
를 override 하게 된다. 여기서는 이 함수가 호출되는 시점을 알아보자.
  1. onCreateLoader() : getLoaderManager().initLoader()(support library 에서는 getSupportLoaderManager().initLoader) 를 호출하면 바로 onCreateLoader() 가 호출된다.
  2. onLoadFinished() : onStart() 이후, AsyncTask 가 동작을 시작한다. 이 AsyncTask 동작이 끝나면, onLoadFinished() 가 호출된다. 이 곳에는 data 가 load 되고 난 후의 UI update 내용을 적으면 된다.
  3. onLoadReset() : android.app.LoaderManager,restartLoader()에서 새로운 loader 를 가져오고 쓰이지 않는 loader 를 destroy() 하는데 이 때 destroy() 에서 onLoadReset() 이 호출된다.


ref. 6에서 LoaderManager 를 잘 설명해 주고 있다. 그리고 ref. 6의 글쓴이가 만든 source 이다.
https://github.com/alexjlockwood/AppListLoader
이 source 에서는 Fragment 가 LoaderManager.LoaderCallbacks 를 implement 하고 있으니 참고하자.
class AppListFragment extends ListFragment implements
      LoaderManager.LoaderCallbacks<List<AppEntry>>
아래는 위의 소스에 대한 대략적인 sequence diagram 이다.
소스는 대략적으로 아래처럼 동작한다.
  1. AppListFragment 에서 LoaderManager.initLoader() 를 호출(onStart() 이전에 호출해야할 듯 하다.)하면서, AppListFragment 를 LoaderCallBack 으로 등록하고,
  2. LoaderManager 가 onCreateLoader() 를 호출
  3. AppLoader() 가 만들어진다.
  4. Activity 가 만들어지면서 onStart() 를 호출할 때
  5. LoadManager.doStart() 를 호출하게 되고,
  6. AppLoader 의 startLoading() 을 호출한다.
  7. 이 때 forceLoading() 을 호출하는데,
  8. 이 forceLoading() (AsyncTaskLoader.onForceLoading()) 이 LoadTask() 를 만들고 Thread 를 이용해서 실행한다.
  9. 그러면 thread 가 doInBackground() 를 실행하게 되고,
  10. 이 작업이 끝난 후에 onPostExecute() 를 UI thread Handler 에게 넘기게 된다.
  11. 이 onPostExecute() 를 실행하면서 AppLoader 의 deliveryResult() 가 호출된다.
  12. 이 때 super.deliveryResult() 를 실행하면, onLoadFinished() 를 호출해 준다.

Diagrams

LoaderManager_seqDiagram


 +--------------------------+------------------------+
 |                          |                        |
 |   +-------------------+  |                        |
 |   | onCreateLoader()  |  |                        |
 |   +--------+----------+  |                        |
 |            |             |                        |
 |   +--------+----------+  |                        |
 |   | onStartLoading()  +--|-----------+            |
 |   +-------------------+  |           |            |
 |                          |           |            |
 |                          |  +--------+----------+ |
 |            +-------------|--+ loadInBackground()| |
 |            |             |  +-------------------+ |
 |            |             |                        |
 |   +--------+----------+  |                        |
 |   | deliverResult()   |  |                        |
 |   +--------+----------+  |                        |
 |            |             |                        |
 |   +--------+----------+  |                        |
 |   | onLoadFinished()  |  |                        |
 |   +-------------------+  |                        |
 +--------------------------+------------------------+



Stacks


AppListLoader : public class AppListLoader extends AsyncTaskLoader<List<AppEntry>>

UI Thread
Stack trace 

MainActivity$AppListFragment.onCreateLoader(int, Bundle) line: 87 
LoaderManagerImpl.createLoader(int, Bundle, LoaderManager$LoaderCallbacks) line: 487 
LoaderManagerImpl.createAndInstallLoader(int, Bundle, LoaderManager$LoaderCallbacks) line: 496 
LoaderManagerImpl.initLoader(int, Bundle, LoaderManager$LoaderCallbacks) line: 550 
MainActivity$AppListFragment.onActivityCreated(Bundle) line: 77 
FragmentManagerImpl.moveToState(Fragment, int, int, int, boolean) line: 892 
FragmentManagerImpl.moveToState(int, int, int, boolean) line: 1083 
BackStackRecord.run() line: 635 
FragmentManagerImpl.execPendingActions() line: 1431 
MainActivity(FragmentActivity).onStart() line: 523 
Instrumentation.callActivityOnStart(Activity) line: 1133 
MainActivity(Activity).performStart() line: 4475
... 


UI Thread
Stack trace 

AppListLoader.onStartLoading() line: 129 
AppListLoader(Loader).startLoading() line: 197 
LoaderManagerImpl$LoaderInfo.start() line: 263 
LoaderManagerImpl.doStart() line: 711 
MainActivity$AppListFragment(Fragment).onStart() line: 985 
MainActivity$AppListFragment(Fragment).performStart() line: 1336 
FragmentManagerImpl.moveToState(Fragment, int, int, int, boolean) line: 907 
FragmentManagerImpl.moveToState(int, int, int, boolean) line: 1083 
FragmentManagerImpl.moveToState(int, boolean) line: 1065 
FragmentManagerImpl.dispatchStart() line: 1849 
MainActivity(FragmentActivity).onStart() line: 536 
Instrumentation.callActivityOnStart(Activity) line: 1133 
MainActivity(Activity).performStart() line: 44753
... 


Stack trace 


AppListLoader.loadInBackground() line: 52 
AppListLoader.loadInBackground() line: 1 
AppListLoader(AsyncTaskLoader).onLoadInBackground() line: 240 
AsyncTaskLoader$LoadTask.doInBackground(Void...) line: 51 
AsyncTaskLoader$LoadTask.doInBackground(Object[]) line: 40 
ModernAsyncTask$2.call() line: 123
... 


UI Thread
Stack trace 

AppListLoader.deliverResult(List) line: 86 
AppListLoader.deliverResult(Object) line: 1 
AppListLoader(AsyncTaskLoader).dispatchOnLoadComplete(AsyncTaskLoader$LoadTask, Object) line: 221 
AsyncTaskLoader$LoadTask.onPostExecute(Object) line: 61 
AsyncTaskLoader$LoadTask(ModernAsyncTask).finish(Object) line: 461 
... 




UI Thread
Stack trace 

MainActivity$AppListFragment.onLoadFinished(Loader, List) line: 92 
MainActivity$AppListFragment.onLoadFinished(Loader, Object) line: 1 
LoaderManagerImpl$LoaderInfo.callOnLoadFinished(Loader, Object) line: 425 
LoaderManagerImpl$LoaderInfo.onLoadComplete(Loader, Object) line: 393 
AppListLoader(Loader).deliverResult(Object) line: 103 
AppListLoader.deliverResult(List) line: 111 
AppListLoader.deliverResult(Object) line: 1 
AppListLoader(AsyncTaskLoader).dispatchOnLoadComplete(AsyncTaskLoader$LoadTask, Object) line: 221 
AsyncTaskLoader$LoadTask.onPostExecute(Object) line: 61 
AsyncTaskLoader$LoadTask(ModernAsyncTask).finish(Object) line: 461 
...



See Also

  1. How to Use Loaders in Android | Grokking Android

References

  1. SimpleCursorLoader - content provider 가 필요없는 loader
  2. SimpleCursorLoader Example
  3. Android tutorial: Simple (but persistent) data storage with SQLite
  4. Get Started Developing For Android With Eclipse, Reloaded
  5. https://github.com/alexjlockwood/AppListLoader
  6. Life Before Loaders (part 1)
  7. http://code.google.com/codesearch#vhKRzqrOaj0/trunk/src/org/ray/veader/DataHelper.java&ct=rc&cd=14&q=openOrCreateDatabase&sq=
  8. Loaders | Android Developers
  9. Android Development - Example, tutorial, Source Code : Custom Loader : Loading data using Loader Manager in android asynchronously
  10. How to Use Loaders in Android | Grokking Android


'Android > Tip&Tech' 카테고리의 다른 글

npm 및 bower 설치..  (0) 2014.11.18
안드로이드 추천 팁 링크  (0) 2014.11.07
[펌]안드로이드 Loader 활용하기  (0) 2014.10.21
자바 표준 스타일 정의  (0) 2014.09.30
[링크]아날로그 시계 만드는 소스  (0) 2014.08.26

출처 : http://ismydream.tistory.com/136


안드로이드 Loader 활용하기



Loader

- 안드로이드 3.0 에서 소개된 Loader 를 사용하면 액티비티와 프래그먼트에서의 비동기 데이터 로딩을 쉽게 처리할 수 있습니다.



특징

- 모든 액티비티와 프래그먼트에서 사용할 수 있습니다.

- 어플리케이션 UI를 Blocking 하지 않도록 비동기 데이터 로딩을 제공합니다.

- 데이터를 모니터 하기 때문에 데이터가 변경되었을때 변경사항을 확인할 수 있습니다.



API

LoaderManager 

- LoaderManager는 액티비티, 프래그먼트 와 1:1 의 관계를 갖습니다. 액티비티 하나당 하나의 LoaderManger 가 존재하는 셈이죠

그리고 하나의 LoaderManager 는 여러개의 Loader 를 관리하게 됩니다.


LoaderManager.LoaderCallbacks

- Loader 를 컨트롤하기 위해 제공되는 콜백 메소드입니다. 콜백 메소드를 통해서 Loader 를 생성하고 변경할 수 있습니다.


Loader

- 비동기 데이터 로딩을 수행하는 추상 클래스입니다.


AsyncTaskLoader

- AsyncTask 를 제공하는 추상 로더입니다.


CursorLoader

- AsyncTaskLoader 의 하위 클래스로서 ContentrResolver 에 쿼리를 하여 Cursor 를 리턴 받도록 합니다.

- AsyncTaskLoader 를 사용하기 때문에  처리하는 작업이 어플리케이션 UI 를 블락킹하지 않습니다.



Loader 적용하기


Loader 시작하기

- Loader 를 초기화하기 위해서 아래코드를 Activity 의 onCreate(), Fragment 의 onActivityCreated() 콜백함수내에 추가한다.

getLoaderManager().initLoader(

0,  // Loader 를 구분하기 위한 ID 값

null,  // 추가 인자

this // Loader 로 부터 콜백을 받기 위해서 LoaderManager.LoaderCallbacks 를 구현한 객체를 넘겨준다.

);

※ initLoader 메소드는 두가지의 결과를 갖게되는데

- initLoader 에 넘겨준 ID 값을 갖는 Loader 가 이미 존재하는 경우 이미 존재하는 LOader 를 재사용하게 됩니다.

- 존재하지 않는 경우에는 LoaderManager.LoaderCallbacks 인터페이스에 있는 onCreateLoader() 콜백함수를 호출하게 됩니다.


Loader 재시작하기

initLoader 메소드에서 ID 가 이미 존재하는 경우에는 기존 Loader 를 재사용 한다고 했는데 재사용 하더라도 데이터를 초기화하고 싶을 때가 있습니다. 그런 경우에 Loader 를 재사용하며 데이터는 초기화하고 싶을때 재시작하게 됩니다.

// 검색시 검색어가 변경되었을 경우 호출

public boolean onQueryTextChanged( String newText){

mCurFilter = !TextUtils.isEmpty( newText) ? newText : null;

getLoaderManager().restartLoader( 0, null, this);

return true;

}



LoaderManager 콜백 사용하기


LoaderManager.LoaderCallbacks

- onCreateLoader()

initLoader 에 넘겨준 ID 를 갖는 Loader 를 생성하여 넘겨준다. 직접 생성하여야 한다.


- onLoaderFinished()

Loader 가 로딩을 끝내을 때 호출한다.


- onLoaderReset()

Loader 가 리셋 됬을 때 호출한다.


onCreateLoader 예제

public Loader<Cursor> onCreateLoader( int id, Bundle args){

Uri baseUri;

if( mCurFilter != null){

baseUri = Uri.withAppendedPath( Contacts.CONTENT_FILTER_URI, 

Uri.encode( mCurFilter));

} else {

baseUri = Contacts.CONTENT_URI;

}

String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("

+ Contacts.HAS_PHONE_NUMBER + "=1) AND ("

+ Contacts.DISPLAY_NAME + " != '' ))";

return new CursorLoader(

getActivity(),

baseUri, // 가져올 컨텐트의 uri

CONTACTS_SUMMARY_PROJECTION,  // 가져올 컬럼의 정보, null 일 경우 모든 컬럼을 리턴한다.

select, // 가져올 데이터를 필터링 하는 정보 SQL 의 WHERE 절과 유사하다., 모든 데이터를 가져올 경우 null 을 설정한다.

null, // selectionArgs 

Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC" // 정렬 순서 sortOrder

);

}


onLoadFilnished 예제

로딩이 끝난후 adapter 에 Cursor를 설정하는 예제

SimpleCursorAdapter mAdapter;


public void onLoadFinished( Loader<Cursor> loader, Cursor data){

mAdapter.swapCursor( data);

}


onLoaderReset 예제

Loader 가 리셋 되었을 때 호출된다. 그러므로 기존 데이터를 해제해야 한다.

SimpleCursorAdapter mAdapter;


public void onLoaderReset( Loader<Cursor> loader){

mAdapter.swapCursor( null);

}


LoaderManager.LoaderCallbacks 를 구현한 Fragment 예제입니다.

public static class CursorLoaderListFragment extends ListFragment

        implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> {


    // This is the Adapter being used to display the list's data.

    SimpleCursorAdapter mAdapter;


    // If non-null, this is the current filter the user has provided.

    String mCurFilter;


    @Override public void onActivityCreated(Bundle savedInstanceState) {

        super.onActivityCreated(savedInstanceState);


        // Give some text to display if there is no data.  In a real

        // application this would come from a resource.

        setEmptyText("No phone numbers");


        // We have a menu item to show in action bar.

        setHasOptionsMenu(true);


        // Create an empty adapter we will use to display the loaded data.

        mAdapter = new SimpleCursorAdapter(getActivity(),

                android.R.layout.simple_list_item_2, null,

                new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },

                new int[] { android.R.id.text1, android.R.id.text2 }, 0);

        setListAdapter(mAdapter);


        // LoaderManger 를 초기화합니다. ID 가 존재하는 경우는 존재하는 Loader 를 재사용합니다.

// Fragment 는 onActivityCreated 메소드내에서 초기화를 진행합니다.

        getLoaderManager().initLoader(0, null, this);

    }


    @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

        // Place an action bar item for searching.

        MenuItem item = menu.add("Search");

        item.setIcon(android.R.drawable.ic_menu_search);

        item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

        SearchView sv = new SearchView(getActivity());

        sv.setOnQueryTextListener(this);

        item.setActionView(sv);

    }


    public boolean onQueryTextChange(String newText) {

// ActionBar 에서 검색시 검색어가 변경되었을 경우에 기존 로더를 재사용하기 위해 Loader의 데이터를 초기화해 줍니다.

        mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;

        getLoaderManager().restartLoader(0, null, this);

        return true;

    }


    @Override public boolean onQueryTextSubmit(String query) {

        // Don't care about this.

        return true;

    }


    @Override public void onListItemClick(ListView l, View v, int position, long id) {

        // Insert desired behavior here.

        Log.i("FragmentComplexList", "Item clicked: " + id);

    }


    // CursorLoader 에서 가져올 컬럼 정의

    static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {

        Contacts._ID,

        Contacts.DISPLAY_NAME,

        Contacts.CONTACT_STATUS,

        Contacts.CONTACT_PRESENCE,

        Contacts.PHOTO_ID,

        Contacts.LOOKUP_KEY,

    };


    // Loader 를 생성하는 콜백 메소드. Loader 를 생성해서 넘겨주면 LoaderManager 에서 알아서 실행하게 됩니다.

    @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) {

        // This is called when a new Loader needs to be created.  This

        // sample only has one Loader, so we don't care about the ID.

        // First, pick the base URI to use depending on whether we are

        // currently filtering.

        Uri baseUri;

        if (mCurFilter != null) {

            baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,

                    Uri.encode(mCurFilter));

        } else {

            baseUri = Contacts.CONTENT_URI;

        }


        // Now create and return a CursorLoader that will take care of

        // creating a Cursor for the data being displayed.

        String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("

                + Contacts.HAS_PHONE_NUMBER + "=1) AND ("

                + Contacts.DISPLAY_NAME + " != '' ))";

        // CursorLoader 를 생성해서 넘겨줍니다.

        return new CursorLoader(getActivity(), baseUri, 

                CONTACTS_SUMMARY_PROJECTION, select, null,

                Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");

    }

    

    // Loader 작업이 끝난후 결과 데이터를 처리하는 콜백 메소드

    @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) {

        // Swap the new cursor in.  (The framework will take care of closing the

        // old cursor once we return.)

        mAdapter.swapCursor(data);

    }

    

    // Loader 가 리셋되었을때 기존 데이터를 해제하는 콜백 메소드

    @Override public void onLoaderReset(Loader<Cursor> loader) {

        // This is called when the last Cursor provided to onLoadFinished()

        // above is about to be closed.  We need to make sure we are no

        // longer using it.

        mAdapter.swapCursor(null);

    }

}





20개 정도 규칙이 있으며 출처는 source.android.com에서 좀 더 자세한 내용을 볼 수 있다.

build된 sdk에는 없지만 sdk 소스를 다운받으면 이클립스용 코딩 포맷과 import순서가 정보가 적힌 xml파일도 같이 받을 수 있는데, 이 글에 첨부했다.

android-formatting.xml은 "Window › Preferences › Java › Code Style > Formatter 에 import하고,
android.importorder "Organize Imports에 import하면
Shift+command+F로 자동포멧정리 기능을 안드로이드에 맞게 사용할 수 있다.

  1. Exceptions: 예외 무시하지말고 처리하기.
  2. Exceptions: 상위 Exception으로 싸잡아서 처리하지 않기.
  3. Finalizers: 왠만하면 쓰지않기 (언제 적용될지 모름)
  4. Imports: *쓰지말고 정확하게 풀네임 적기.

Java Library Rules

표준 코딩컨벤션이 바뀌어서 예전 코딩컨벤션과 충돌이 난다면 예전 코딩컨벤션으로 작성해서 일관성을 유지하기.

Java Style Rules

자바표준 컨벤션에서 추가사항:

  1. Comments/Javadoc: 표준대로 작성하기.
  2. Short methods: 메소드는 40줄이 넘지않게 짧게 작성하기
  3. Fields: 초기에 선언하기나 사용하기 바로 전에 선언할 것.
  4. Local variables: 지역변수 범위는 최소화하기.
  5. Imports: 안드로이드, 서드파티(알파벳 순), java, javax 순으로 import하기.
  6. Indentation: 탭안쓰고 공백 4개 사용하기.
  7. Line length: 한줄에 100칸 이하 유지하기.
  8. Field names: Non-public, non-static 변수는 m으로 시작하고, static변수는 s로 시작하기.
  9. Braces: { 는 줄넘기지말고 사용하기
  10. Annotations: 표준 어노테이션 사용하기.
  11. Acronyms are words: XMLHTTPReques처럼 적지말고 XmlHttpRequest로 적기
  12. TODO style: "TODO: write this description"
  13. Consistency: 일관적으로 작성하기
  14. Logging: 로그도 비용이 드니 적절하기 사용하기
    ERROR > WARNING > INFORMATION > DEBUG > VERBOSE 사용할 것.
    한줄에 출력할 수 있는 80~100글자가 적당.
    StringBuilder는 기본버퍼가 16character라 String보다 항상 좋다고 할 수 없으니 확신이 없으면 그냥 String연산이 무난.
    System.out.print는 어차피 /dev/null로 던져버리니 절대 쓰지말 것. 괜히 비용만 잡아먹음.

Javatests Style Rules

  1. Naming test methods: testMethod_specificCase 이런식으로 이름짓


http://blog.naver.com/PostView.nhn?blogId=iflowerpot&logNo=80121408847&categoryNo=13&parentCategoryNo=0&viewDate=&currentPage=3&postListTopCurrentPage=&userTopListOpen=true&userTopListCount=5&userTopListManageOpen=false&userTopListCurrentPage=3

'Android > Tip&Tech' 카테고리의 다른 글

[펌]안드로이드 Loader 활용하기  (0) 2014.10.21
자바 표준 스타일 정의  (0) 2014.09.30
kitkat(4.4)에서 맞닥뜨린 이슈 및 해결  (0) 2014.08.14
홈버튼 제어하기  (0) 2014.06.24
안드로이드 투명도 코드  (0) 2014.06.05

출처 : https://medium.com/marojuns-android/kitkat-4-4-%EC%97%90%EC%84%9C-%EB%A7%9E%EB%8B%A5%EB%9C%A8%EB%A6%B0-%EC%9D%B4%EC%8A%88-%EB%B0%8F-%ED%95%B4%EA%B2%B0-1ecb94c24694




'Android > Tip&Tech' 카테고리의 다른 글

자바 표준 스타일 정의  (0) 2014.09.30
[링크]아날로그 시계 만드는 소스  (0) 2014.08.26
홈버튼 제어하기  (0) 2014.06.24
안드로이드 투명도 코드  (0) 2014.06.05
[펌]SeekBar 스타일링 방법  (0) 2014.03.12

http://hns17.tistory.com/entry/App-개발-잠금화면-HomeKey-Control-Problem

100%  FF
95%  F2
90%  E6
85%  D9
80%  CC
75%  BF
70%  B3
65%  A6
60%  99
55%  8C
50%  80
45%  73
40%  66
35%  59
30%  4D
25%  40
20%  33
15%  26
10%  1A
5%  0D
0%  00


출처 :  http://stackoverflow.com/questions/16163215/android-styling-seek-bar

 

I would extract drawables and xml from Android source code and change its color to red. Here is example how I completed this for mdpi drawables:

Custom red_scrubber_control.xml:

<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/red_scrubber_control_disabled_holo" android:state_enabled="false"/>
    <item android:drawable="@drawable/red_scrubber_control_pressed_holo" android:state_pressed="true"/>
    <item android:drawable="@drawable/red_scrubber_control_focused_holo" android:state_selected="true"/>
    <item android:drawable="@drawable/red_scrubber_control_normal_holo"/>
</selector>

Custom: red_scrubber_progress.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@android:id/background"
        android:drawable="@drawable/red_scrubber_track_holo_light"/>
    <item android:id="@android:id/secondaryProgress">
        <scale
            android:drawable="@drawable/red_scrubber_secondary_holo"
            android:scaleWidth="100%" />
    </item>
    <item android:id="@android:id/progress">
        <scale
            android:drawable="@drawable/red_scrubber_primary_holo"
            android:scaleWidth="100%" />
    </item>

</layer-list>

Then copy required drawables from Android source code, I took them here: https://github.com/android/platform_frameworks_base/tree/ics-factoryrom-2-release/core/res/res It is good to copy these drawables for each hdpi, mdpi, xhdpi. For example I use only mdpi:

Then using Photoshop change color from blue to red:

red_scrubber_control_disabled_holo.png: red_scrubber_control_disabled_holo

red_scrubber_control_focused_holo.png: red_scrubber_control_focused_holo

red_scrubber_control_normal_holo.png: red_scrubber_control_normal_holo

red_scrubber_control_pressed_holo.png: red_scrubber_control_pressed_holo

red_scrubber_primary_holo.9.png: red_scrubber_primary_holo.9

red_scrubber_secondary_holo.9.png: red_scrubber_secondary_holo.9

red_scrubber_track_holo_light.9.png: red_scrubber_track_holo_light.9

Add SeekBar to layout:

<SeekBar
    android:id="@+id/seekBar1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:progressDrawable="@drawable/red_scrubber_progress"
    android:thumb="@drawable/red_scrubber_control" />

Result:

enter image description here

Edited:

Here is nice resource Android Holo Colors Generator that will help to create elements with different colors much faster. Just select color and element and it will create required drawable for xhdpi, hdpi and mdpi.

share|improve this answer

출처 :     http://stackoverflow.com/questions/12411060/get-listview-height-after-setadapter

 

ListView lv_marca;

    lv_marca
.setAdapter(adapter_marca);

   
int list_height = getListViewHeight(lv_marca);



   
private int getListViewHeight(ListView list) {
         
ListAdapter adapter = list.getAdapter();

         
int listviewHeight = 0;

          list
.measure(MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED),
                      
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));

          listviewHeight
= list.getMeasuredHeight() * adapter.getCount() + (adapter.getCount() * list.getDividerHeight());

         
return listviewHeight;
   
}

출처 : http://arabiannight.tistory.com/55

 

안드로이드/Android 부모의 속성을 동일 하게 가져 가자!


안드로이드 XML을 개발하면서 List나 뷰의 이벤트 발생에 따라 화살표(Arrow)버튼 이미지도 Press 처리 해야 할 경우가 많은데요. 이런 경우게 onTouchEvent로 터치 했을 경우에 Pressed 처리하거나 터치를 종료할 경우 Normal 처리 해주는 경우가 있었을 겁니다.  하지만 부모 뷰의 속성에 따라 Child뷰의 속성들이 이벤트를 받는 XML 속성이 있는데요.


이 속성을 쓰면 훨씬더 간결하고 편하게 코드를 작성할 수 있습니다.
그 속성의 이름은 바로 요놈 입니다.


 

android:duplicateParentState="true"
 
 



보통 요즘의 화면 구성에는 하나의 레이아웃에 여러개의 뷰들이 들어가는 경우가 많은데요. duplicateParentState 속성을 이용하면 레이아웃안에 Child 뷰들을 부모의 상태와 동일한 상태(State)를 적용 할 수 있습니다.



결국 레이아웃에 onClickListener를 사용한 경우 Child View들에 Selector를 이용하여 Background를 작성해 주면 부모의 이벤트에 따라 Chiled View의 속성이 변하겠죠?



주의!! : 부모의 클릭이벤트를 동일하게 받을 차일드View에 해당 속성을 적용 하시기 바랍니다.

+ Recent posts