Google java 스타일 가이드 기준

https://google.github.io/styleguide/javaguide.html

 

  • 패키지명은 모두 소문자 - ex) com.example.deppspace
  • 클래스명은 UpperCamelCase - ex) Example
  • 메소드명은 lowerCamelCase - ex) sendMessage()
  • 상수명은 모두 대문자 단어의 구분은 밑줄 - ex) CONSTANT_CASE
  • 필드명은 lowerCamelCase - ex) computedValues
  • 파라미터명은 lowerCamelCase

1. 리소스 네이밍 규칙

    # drawable

     기본 규칙 : [분류]_[색상]

               ex) ani_sliding_left, select_login, bg_intro_ffffff, bg_rect_5_ffffff_a0ffff_r40

 

       - 분류

유형 축약명 규칙 예시 비고
animation ani [유형]_[목적] ani_loading 애니메이션 정의
selector sel [유형]_[목적]

sel_close

sel_bookmark

 
background bg [유형]_[목적]_[색상] bg_intro 배경
shape rectangle rect bg_[유형]_[테두리 굵기 dp]_[모서리]_[색상] bg_rect_5_ffffff_a0ffff 테두리
shape line line bg_[유형]_[라인 굵기 dp]_[색상] bg_line_2_ff00ff 실선
shape line dash dash bg_[유형]_[라인 굵기 dp]_[색상] bg_dash_ffff00 점선
shape oval oval bg_[유형]_[크기dp]_[색상] bg_oval_4_ff0000 타원
shape ring ring      

        - 색상

         기본 규칙 : [투명도][%]_[색상]

                   ex) a80_ffacee, a40_eeddcc_a80_ffeeec, ffaacc_a60_aaddff

  • 투명도는 alpha의 축약 a를 쓰며, 투명도 %를 표시한다.
  • selector 에서는 [기본 투명도]_[기본 색상]_[눌렀을때 투명도]_[눌렀을때 색상]으로 표시한다.
  • rect 에서는 [배경 투명도]_[배경 색상]_[테두리 투명도]_[테두리 색상]으로 표시한다.
  • 색상이 그라데이션인 경우 [시작 투명도]_[시작 색상]_[중간 투명도]_[중간 색상]_[끝 투명도]_[끝 색상]으로 표시한다.

       - 모서리

 

유형 축약명 규칙 예시 비고
round

r

rt

rb

rtl

rtr

rbl

rbr

[유형][크기 dp]

r30

rt10

rb20

rt10_rb20

rtl10_rtr15_rbl10_rbr15

Radius 표시(단위 dp)

r : 전체

rt : 상단

rb : 하단

rtl : 상단 왼쪽

rtr : 상단 오른쪽

rbl : 하단 왼쪽

rbr : 하단 오른쪽

 

    # layout

유형 축약명 규칙 예시 비고
Activity   activity_[대상] activity_main  
Fragment   fragment_[대상] fragment_coupon  
Item   itme_[대상]_[목적] item_coupon_history  
layout   layout_[대상]

layout_titlebar

layout_dialog

CustomView로 완성된 형태, include 뷰 등

 

2. 뷰 아이디 네이밍(android:id="@+id")

기본 규칙 : [소속]_[소속2]_[대상(역할)]_[뷰명(축약)]

        ex) main_login_btn, coupon_item_title_tv

    # 뷰 컴포넌트 축약

패턴 뷰명 축약
Buttons Button btn
ImageButton ibtn
CheckBox cb
RadioGroup rg
RadioButton rbtn
ToggleButton tbtn
Switch sw
FloatingActionButton fabtn
Widgets View v
ImageView iv
WebView wv
VideoView vv
CalendarView calv
ProgressBar pbr
SeekBar sbr
RatingBar rbr
SearchView scv
TextureView ttv
SufaceView sfv
Layouts ConstraintLayout cl
LinearLayout ll
FramLayout fl
TableLayout tl
Containers Spnner sp
RecyclerView rv
ScrollView sv
HorizontalScrollView hsv
NestedScrollView nsv
ViewPager vp
CardView cv
AppBarLayout abl
NavigationView nv
Toolbar tbr
TabLayout tabl
TabItem tabi
ViewStub vs
Google AdView av
MapView mv
Legacy GridLayout gl
ListView lv
TabHost tabh
RelativeLayout rl
GridView gv
ExpandableListView elv
Gallery gal
ViewFlipper vf
SlidingDrawer sd
DatePicker dp
TimePicker tp
#요약
 - ActivityLifecycleCallbacks : App의 관점에서 본 Activity
 - LifecycleObserver : Lifecycle 대리 수행
 - LifecycleOwner : Lifecycle 커스텀

1. ActivityLifecycleCallbacks
[API level 14]

     App의 Activity의 LifeCycle를 통하여 App의 현재 상태 또는 활성화 되어 있는 Activity를 알 수 있어 상황에 따라 대응 가능. 

     Application에 구현하여 통합 관리 하도록 구성


#Code

public class BaseApplication extends Application {
    private static BaseApplication mInstance = null;
    private AppStatus mAppStatus = AppStatus.FOREGROUND;

    @Override
    public void onCreate() {
        mInstance = this;
        super.onCreate();

        // Activity 라이프 사이클을 탐지하여 포그라운드와 백그라운드 체크
        registerActivityLifecycleCallbacks(new CActivityLifecycleCallbacks());
    }

    public static BaseApplication getInstance() {
        return mInstance;
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
    }

    public AppStatus getAppStatus() {
        return mAppStatus;
    }

    public enum AppStatus {
        BACKGROUND,
        RETURNED_TO_FOREGROUND, // 홈 버튼으로 내린후 다시 실행 된 경우, 처음 실행시
        FOREGROUND,
        MEMORY_OUT; // 최근 앱 사용 목록에서 앱이 삭제 되었을 경우
    }

    public class CActivityLifecycleCallbacks implements ActivityLifecycleCallbacks {
        private int running = 0;

        @Override
        public void onActivityCreated(Activity activity, Bundle bundle) {
            CLog.e("APP onActivityCreated === " + activity.getClass().getCanonicalName());
        }

        @Override
        public void onActivityStarted(Activity activity) {
            CLog.e("APP onActivityStarted === " + activity.getClass().getCanonicalName());
            if (++running == 1) {
                mAppStatus = AppStatus.RETURNED_TO_FOREGROUND;
            } else if (running > 1) {
                mAppStatus = AppStatus.FOREGROUND;
           }
        }

        @Override
        public void onActivityResumed(Activity activity) {
            CLog.e("APP onActivityResumed ===" + activity.getClass().getCanonicalName());
        }

        @Override
        public void onActivityPaused(Activity activity) {
            CLog.e("APP onActivityPaused ===" + activity.getClass().getCanonicalName());
        }

        @Override
        public void onActivityStopped(Activity activity) {
            CLog.e("APP onActivityStopped === " + activity.getClass().getCanonicalName());
            if (--running == 0) {
                mAppStatus = AppStatus.BACKGROUND;
            }
        }

        @Override
        public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
            CLog.e("APP onActivitySaveInstanceState ===" + activity.getClass().getCanonicalName());
        }

        @Override
        public void onActivityDestroyed(Activity activity) {
            CLog.e("APP onActivityDestroyed === " + activity.getClass().getCanonicalName());
            mAppStatus = AppStatus.MEMORY_OUT;
            // 메인 Activity가 Destory 된다는 것은 '최근 앱 사용 목록'에서 지우기를 한것임
        }
    }
}

# 호출

if(BaseApplication.getInstance().getAppStatus() == BaseApplication.AppStatus.BACKGROUND) {
      // TODO
 }



'프로그래밍 > Android Tip' 카테고리의 다른 글

Android 개발 가이드  (0) 2019.12.30
[Android] Aquery Image  (0) 2017.08.07
[Android] Aquery Network  (0) 2017.08.07
[Android] ScrollView In ScrollView  (0) 2017.06.28
[Android] 내부 저장소 경로  (0) 2017.06.28

Code

Asynchronous image loading is easy with AQuery.

Simple

//load an image to an ImageView from network, cache image to file and memory

aq
.id(R.id.image1).image("http://www.vikispot.com/z/images/vikispot/android-w.png");

Cache Control

//load an image from network, but only cache with file

//this image is huge, avoid memory caching
boolean memCache = false;
boolean fileCache = true;

aq
.id(R.id.image1).image("http://www.vikispot.com/z/images/vikispot/android-w.png", memCache, fileCache);

Down Sampling (handling huge images)

//we are loading a huge image from the network, but we only need the image to be bigger than 200 pixels wide
//passing in the target width of 200 will down sample the image to conserve memory
//aquery will only down sample with power of 2 (2,4,8...) for good image quality and efficiency
//the resulting image width will be between 200 and 399 pixels

String imageUrl = "http://farm6.static.flickr.com/5035/5802797131_a729dac808_b.jpg";            
aq
.id(R.id.image1).image(imageUrl, true, true, 200, 0);

Related Blog: Downsampling

Fallback Image

//if we are not able to load the image, use a default image (R.drawable.default_image)

String imageUrl = "http://www.vikispot.com/z/images/vikispot/android-w.png";
aq
.id(R.id.image1).image(imageUrl, true, true, 0, R.drawable.default_image);

//make image view "invisible" if image failed to load
imageUrl
= "http://a.b.com/invalid.jpg";                
aq
.id(R.id.image1).image(imageUrl, true, true, 0, AQuery.INVISIBLE);


//make image view "gone" if image failed to load
aq
.id(R.id.image1).image(imageUrl, true, true, 0, AQuery.GONE);

Preloading

//get the bitmap for a previously fetched thumbnail
String thumbnail = "http://farm6.static.flickr.com/5035/5802797131_a729dac808_s.jpg";  
Bitmap preset = aq.getCachedImage(thumbnail);

//set the image view with a thumbnail, and fetch the high resolution image asynchronously
String imageUrl = "http://farm6.static.flickr.com/5035/5802797131_a729dac808_b.jpg";            
aq
.id(R.id.image).image(imageUrl, false, false, 0, 0, preset, AQuery.FADE_IN);

Progress

We can show the image loading progress by using the progress() method. Pass in the progress bar id, or any other view id to the progress method, and the view will be shown or hide to display loading progress.

String imageUrl = "http://farm6.static.flickr.com/5035/5802797131_a729dac808_b.jpg";            
aq
.id(R.id.image).progress(R.id.progress).image(imageUrl, false, false);

Sample grid item layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   
android:layout_width="fill_parent"
   
android:layout_height="100dip"
   
>
   
   
<ProgressBar                
       
android:layout_width="15dip"      
       
android:layout_height="15dip"
       
android:id="@+id/progress"
       
android:layout_centerInParent="true"
       
/>
   
   
<ImageView
       
android:id="@+id/image"      
       
android:layout_width="fill_parent"      
       
android:layout_height="75dip"
       
/>

</RelativeLayout>

Animation

//display the image with a predefined fade in animation
String imageUrl = "http://www.vikispot.com/z/images/vikispot/android-w.png";            
aq
.id(R.id.image).image(imageUrl, true, true, 0, null, 0, AQuery.FADE_IN);

Rounded Corner

The round option transform the image to a rounded corner image with a specified radius. Note that the value is in pixels (not dip).

Due to performance impact, round corner should not be used for large images.

String url = "http://www.vikispot.com/z/images/vikispot/android-w.png";

ImageOptions options = new ImageOptions();
options
.round = 15;

aq
.id(R.id.image).image(url, options);

Aspect Ratio

Preserve Image Aspect Ratio
String imageUrl = "http://farm3.static.flickr.com/2199/2218403922_062bc3bcf2.jpg";      
aq
.id(R.id.image).image(imageUrl, true, true, 0, 0, null, AQuery.FADE_IN, AQuery.RATIO_PRESERVE);
Fixed Predefined Aspect Ratio
String imageUrl = "http://farm3.static.flickr.com/2199/2218403922_062bc3bcf2.jpg";      

aq
.id(R.id.image1).image(imageUrl, true, true, 0, 0, null, 0, AQuery.RATIO_PRESERVE);  

//1:1, a square
aq
.id(R.id.image2).image(imageUrl, true, true, 0, 0, null, 0, 1.0f / 1.0f);            
aq
.id(R.id.image3).image(imageUrl, true, true, 0, 0, null, 0, 1.5f / 1.0f);    
       
//16:9, a video thumbnail
aq
.id(R.id.image4).image(imageUrl, true, true, 0, 0, null, 0, 9.0f / 16.0f);    
aq
.id(R.id.image5).image(imageUrl, true, true, 0, 0, null, 0, 3.0f / 4.0f);

Note

The aspect ratio feature will set the ImageView to use the ScaleType MATRIX and adjust its height to the correct aspect ratio.

Anchor

If the image aspect ratio is taller then the desired aspect ratio, the anchor option can be used to control which vertical portion of the image should be displayed.

Anchor values:

  • 1.0 : Display top of the image
  • 0 : Display the center of the image
  • -1.0 : Display bottom of the image
  • AQuery.ANCHOR_DYNAMIC : Display image with a top bias for photos.

 

ImageOptions options = new ImageOptions();

options
.ratio = 1;
options
.anchor = 1.0;
aq
.id(R.id.image1).image(imageUrl, options);

Custom Callback

String imageUrl = "http://www.vikispot.com/z/images/vikispot/android-w.png";

final int tint = 0x77AA0000;

aq
.id(R.id.image1).image(imageUrl, true, true, 0, 0, new BitmapAjaxCallback(){

       
@Override
       
public void callback(String url, ImageView iv, Bitmap bm, AjaxStatus status){
                               
                iv
.setImageBitmap(bm);
               
               
//do something to the bitmap
                iv
.setColorFilter(tint, PorterDuff.Mode.SRC_ATOP);
               
       
}
       
});

File (Async)

Load image from a file asynchronously. Down sampling is recommended when loading huge images from camera or gallery to avoid out of memory errors.

Simple
File file = new File(path);        

//load image from file, down sample to target width of 300 pixels  
aq
.id(R.id.avatar).image(file, 300);
Callback
File file = new File(path);

//load image from file with callback
aq
.id(R.id.avatar).image(file, false, 300, new BitmapAjaxCallback(){

   
@Override
   
public void callback(String url, ImageView iv, Bitmap bm, AjaxStatus status){
       
        iv
.setImageBitmap(bm);
       
       
//do something with the bm
       
   
}
   
});

Duplicated URL

//AQuery detects duplicated image urls request and only fetches 1 image and apply them to all associated image views

String imageUrl = "http://www.vikispot.com/z/images/vikispot/android-w.png";
aq
.id(R.id.image1).image(imageUrl);

//no network fetch for 2nd request, image will be shown when first request is completed
aq
.id(R.id.image2).image(imageUrl);

BitmapAjaxCallback

All the AQuery image methods uses the BitmapAjaxCallback internally. You can configure and use the callback directly if you prefer.

String imageUrl = "http://farm3.static.flickr.com/2199/2218403922_062bc3bcf2.jpg";      

//create a bitmap ajax callback object
BitmapAjaxCallback cb = new BitmapAjaxCallback();

//configure the callback
cb
.url(imageUrl).animation(AQuery.FADE_IN).ratio(1.0f);

//invoke it with an image view
aq
.id(R.id.image).image(cb);

Access Cached Images

//returns the cached file by url, returns null if url is not cached
File file = aq.getCachedFile(url);

Zoomable Web Image

In addition to ImageView, a WebView can be used to display an image along with Android build in zoom support for WebView. Image will be centered and fill the width or height of the webview depending on it's orientation.

private void image_zoom(){

       
String url = "http://farm4.static.flickr.com/3531/3769416703_b76406f9de.jpg";          
        aq
.id(R.id.web).progress(R.id.progress).webImage(url);
       
}

List View Example

When working with AQuery, make sure the views you want to operate can be "findBy" the view or activity you created with the AQuery object. In the case for rendering list items, create an AQuery object with the item container view.

Example

ArrayAdapter<JSONObject> aa = new ArrayAdapter<JSONObject>(this, R.layout.content_item_s, items){
       
       
@Override
       
public View getView(int position, View convertView, ViewGroup parent) {
               
               
if(convertView == null){
                        convertView
= getLayoutInflater().inflate(R.layout.content_item_s, null);
               
}
               
               
JSONObject jo = getItem(position);
               
               
AQuery aq = new AQuery(convertView);
                aq
.id(R.id.name).text(jo.optString("titleNoFormatting", "No Title"));
                aq
.id(R.id.meta).text(jo.optString("publisher", ""));
               
               
String tb = jo.optJSONObject("image").optString("tbUrl");
                aq
.id(R.id.tb).progress(R.id.progress).image(tb, true, true, 0, 0, null, AQuery.FADE_IN_NETWORK, 1.0f);
               
               
               
return convertView;
               
       
}
};

Delay Image Loading

AQuery provide a shouldDelay() method to help you decide whether to load expensive resources when the list is scrolling (flinging) really fast. It's recommended to delay load large images and other resources over the internet.

Please see javadoc for more detail.

ArrayAdapter<Photo> aa = new ArrayAdapter<Photo>(this, R.layout.photo_item, entries){
       
       
public View getView(int position, View convertView, ViewGroup parent) {
               
               
if(convertView == null){
                        convertView
= getLayoutInflater().inflate(R.layout.photo_item, parent, false);
               
}
               
               
Photo photo = getItem(position);
               
               
AQuery aq = new AQuery(convertView);
               
                aq
.id(R.id.name).text(photo.title);
                aq
.id(R.id.meta).text(photo.author);
               
               
String tbUrl = photo.tb;
               
               
Bitmap placeholder = aq.getCachedImage(R.drawable.image_ph);
               
               
if(aq.shouldDelay(position, convertView, parent, tbUrl)){
                        aq
.id(R.id.tb).image(placeholder, 0.75f);
               
}else{
                        aq
.id(R.id.tb).image(tbUrl, true, true, 0, 0, placeholder, 0, 0.75f);
               
}
               
               
return convertView;
               
       
}
       
};

//apply any custom onScrollListener
aq
.id(R.id.list).scrolled(new OnScrollListener(){...});

//apply the adapter
aq
.id(R.id.list).adapter(aa);

NOTE

The shouldDelay() method uses the setOnScrollListener() method and will override any previously non-aquery assigned scroll listener. If a scrolled listener is required, use the aquery method scrolled(OnScrollListener listener) to register your listener instead.

ListView, GridView, Gallery, and ExpandableListView are supported. For ExpandableListView, use the variation method:

shouldDelay(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent, java.lang.String url) 

ViewHolder Pattern

ViewHolder pattern optimize performance by caching the views returned by findViewById().

ArrayAdapter<JSONObject> aa = new ArrayAdapter<JSONObject>(this, R.layout.content_item_s, items){
       
       
public View getView(int position, View convertView, ViewGroup parent) {
               
               
ViewHolder holder;
               
               
if(convertView == null){                                        
                        convertView
= getLayoutInflater().inflate(R.layout.content_item_s, null);
                        holder
= new ViewHolder();
                        holder
.imageview = (ImageView) convertView.findViewById(R.id.tb);
                        holder
.progress = (ProgressBar) convertView.findViewById(R.id.progress);
                        convertView
.setTag(holder);
               
}else{
                        holder
= (ViewHolder) convertView.getTag();
               
}
               
               
JSONObject jo = getItem(position);
               
String tb = jo.optJSONObject("image").optString("tbUrl");
               
               
AQuery aq = new AQuery(convertView);
                aq
.id(holder.imageview).progress(holder.progress).image(tb, true, true, 0, 0, null, 0, 1.0f);
               
               
return convertView;
       
}
};

Cache Busting

Images on the web usually doesn't change. If your image changes with identical url and would like to refresh the image, simply set file and mem cache to false and it will force the image to be refetched.

String url = "http://www.vikispot.com/z/images/vikispot/android-w.png";

//force a network refetch without any caching
aq
.id(R.id.image).image(url, false, false);

//force no proxy cache by appending a random number to url
String url2 = url + "?t=" + System.currentTimeMillis();
aq
.id(R.id.image2).image(url2, false, false);

Network Failure Recovery

If network is disconnected and causing images to failed to load and use fallback images instead, the fallback images will be cached and continue to be served until the network connection is recovered.

When a next subsequent successful connection is established, the fallback image cache will be flushed and allow failed images to be reloaded.

Cache Configuration

By default, AQuery uses the internal file system to cache files, which is only accessible to your app. If you want to use the external SDCard for storing your cached files, use the setCacheDir() function.

        
File ext = Environment.getExternalStorageDirectory();
File cacheDir = new File(ext, "myapp");
AQUtility.setCacheDir(cacheDir);
       

Sharing Image

In order to share resources to other apps, the file must be on the external storage (SDCard). The makeSharedFile() method create a copy of a cached url to a temporary folder in SDCard. You can then pass the file as an URI and share it with other apps, like Gmail or Facebook.

public void image_send(){
       
       
String url = "http://www.vikispot.com/z/images/vikispot/android-w.png";        
       
File file = aq.makeSharedFile(url, "android.png");
       
       
if(file != null){              
               
Intent intent = new Intent(Intent.ACTION_SEND);
                intent
.setType("image/jpeg");
                intent
.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
                startActivityForResult
(Intent.createChooser(intent, "Share via:"), SEND_REQUEST);
       
}
}

Configuration

More fine tuning can be done when an application starts. A good place to set the configuration is in the onCreate() method of the application.

public class MainApplication extends Application{

       
       
@Override
   
public void onCreate() {    
         
       
//set the max number of concurrent network connections, default is 4
       
AjaxCallback.setNetworkLimit(8);

       
//set the max number of icons (image width <= 50) to be cached in memory, default is 20
       
BitmapAjaxCallback.setIconCacheLimit(20);

       
//set the max number of images (image width > 50) to be cached in memory, default is 20
       
BitmapAjaxCallback.setCacheLimit(40);

       
//set the max size of an image to be cached in memory, default is 1600 pixels (ie. 400x400)
       
BitmapAjaxCallback.setPixelLimit(400 * 400);
       
       
//set the max size of the memory cache, default is 1M pixels (4MB)
       
BitmapAjaxCallback.setMaxPixelLimit(2000000);                  
       
       
super.onCreate();
   
}
       
       
}

Maintenance

AQuery provides few utility functions to help you control ajax and caching behavior.

Clean Up

If you use file cache for images, regularly clean the cache dir when the application exits.

Simple

protected void onDestroy(){
       
       
super.onDestroy();
       
       
//clean the file cache when root activity exit
       
//the resulting total cache size will be less than 3M  
       
if(isTaskRoot()){
               
AQUtility.cleanCacheAsync(this);
       
}
}

Advance

protected void onDestroy(){
       
       
super.onDestroy();
       
       
if(isTaskRoot()){

               
//clean the file cache with advance option
               
long triggerSize = 3000000; //starts cleaning when cache size is larger than 3M
               
long targetSize = 2000000;      //remove the least recently used files until cache size is less than 2M
               
AQUtility.cleanCacheAsync(this, triggerSize, targetSize);
       
}
       
}

Low Memory

Low memory happens when the device is overloaded with apps. When this happens, we want to remove all images from memory cache.

public class MainApplication extends Application{

   
@Override
   
public void onLowMemory(){  

       
//clear all memory cached images when system is in low memory
       
//note that you can configure the max image cache count, see CONFIGURATION
       
BitmapAjaxCallback.clearCache();
   
}
       
}

출처: http://blog.naver.com/xinfra/80207465726


Asynchronous Network

Permission

Make sure the following permission is included in your manifest.

<uses-permission android:name="android.permission.INTERNET" /> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

WRITE_EXTERNAL_STORAGE is required for temporary caching for large response types.

Code

Asynchronous AJAX or RPC calls are simple with AQuery.

Supported Types

AQuery transform the data automatically base on the class type passed in the ajax method.

Supported types:

  • JSONObject
  • JSONArray
  • String (HTML, XML)
  • XmlDom (XML parsing)
  • XmlPullParser (Large XML files)
  • byte array
  • User defined custom type (Transformer)
  • Bitmap

 

If there are native Android data types (without third party dependency) you want AQuery to support, please send us feedback.

JSON


public void asyncJson(){
       
       
//perform a Google search in just a few lines of code
       
       
String url = "http://www.google.com/uds/GnewsSearch?q=Obama&v=1.0";
       
        aq
.ajax(url, JSONObject.class, new AjaxCallback<JSONObject>() {

               
@Override
               
public void callback(String url, JSONObject json, AjaxStatus status) {
                       
                       
                       
if(json != null){
                               
                               
//successful ajax call, show status code and json content
                               
Toast.makeText(aq.getContext(), status.getCode() + ":" + json.toString(), Toast.LENGTH_LONG).show();
                       
                       
}else{
                               
                               
//ajax error, show error code
                               
Toast.makeText(aq.getContext(), "Error:" + status.getCode(), Toast.LENGTH_LONG).show();
                       
}
               
}
       
});
       
}

JSON (activity as callback)

public void asyncJson(){
       
       
//perform a Google search in just a few lines of code
       
       
String url = "http://www.google.com/uds/GnewsSearch?q=Obama&v=1.0";            
        aq
.ajax(url, JSONObject.class, this, "jsonCallback");
       
}

public void jsonCallback(String url, JSONObject json, AjaxStatus status){
       
       
if(json != null){              
               
//successful ajax call          
       
}else{          
               
//ajax error
       
}
       
}

Note that AQuery uses a weak reference to hold the handler for this method. This is to make sure an activity won't be memory leaked when it's terminated before the AJAX request finishes.

HTML/XML

//fetch Google's homepage in html

String url = "http://www.google.com";

aq
.ajax(url, String.class, new AjaxCallback<String>() {

       
@Override
       
public void callback(String url, String html, AjaxStatus status) {
               
       
}
       
});

XML Dom

AQuery provide a light weight XML parser called XmlDom. javadoc

XmlDom is a specialized class for simple and easy XML parsing. It's designed to be used in basic Android api 4+ runtime without any dependency.

Example to parse Picasa's featured photos feed:

public void xml_ajax(){         
       
String url = "https://picasaweb.google.com/data/feed/base/featured?max-results=8";              
        aq
.ajax(url, XmlDom.class, this, "picasaCb");          
}

public void picasaCb(String url, XmlDom xml, AjaxStatus status){

       
List<XmlDom> entries = xml.tags("entry");              
       
List<String> titles = new ArrayList<String>();
       
       
String imageUrl = null;
       
       
for(XmlDom entry: entries){
                titles
.add(entry.text("title"));
                imageUrl
= entry.tag("content", "type", "image/jpeg").attr("src");
       
}
               
        aq
.id(R.id.image).image(imageUrl);
       
}

Related Blog: XML Parsing

XmlPullParser

For large XML response that cannot fit in memory, the XMLPullParser can be used to avoid memory issue.

public void callback(String url, XmlPullParser xpp, AjaxStatus status) {
       
       
Map<String, String> images = new LinkedHashMap<String, String>();
       
String currentTitle = null;
       
       
try{
       
       
int eventType = xpp.getEventType();
       
while(eventType != XmlPullParser.END_DOCUMENT) {
         
               
if(eventType == XmlPullParser.START_TAG){
                       
                       
String tag = xpp.getName();
                       
                       
if("title".equals(tag)){
                                currentTitle
= xpp.nextText();
                       
}else if("content".equals(tag)){
                               
String imageUrl = xpp.getAttributeValue(0);
                                images
.put(currentTitle, imageUrl);
                       
}
               
}
                eventType
= xpp.next();
       
}
       
       
}catch(Exception e){
               
AQUtility.report(e);
       
}
       
        showResult
(images, status);
       
}

bytes

//fetch a remote resource in raw bytes

String url = "http://www.vikispot.com/z/images/vikispot/android-w.png";

aq
.ajax(url, byte[].class, new AjaxCallback<byte[]>() {

       
@Override
       
public void callback(String url, byte[] object, AjaxStatus status) {
               
Toast.makeText(aq.getContext(), "bytes array:" + object.length, Toast.LENGTH_LONG).show();
       
}
});

Bitmap

//fetch a remote resource in raw bitmap

String url = "http://www.vikispot.com/z/images/vikispot/android-w.png";

aq
.ajax(url, Bitmap.class, new AjaxCallback<Bitmap>() {

       
@Override
       
public void callback(String url, Bitmap object, AjaxStatus status) {
               
       
}
});

File

String url = "https://picasaweb.google.com/data/feed/base/featured?max-results=8";              

aq
.progress(R.id.progress).ajax(url, File.class, new AjaxCallback<File>(){
       
       
public void callback(String url, File file, AjaxStatus status) {
               
               
if(file != null){
                        showResult
("File:" + file.length() + ":" + file, status);
               
}else{
                        showResult
("Failed", status);
               
}
       
}
       
});

File Download

If you can specify where to store the downloaded file with the download() method. Note that these files will not be deleted like cached files.

String url = "https://picasaweb.google.com/data/feed/base/featured?max-results=16";             

File ext = Environment.getExternalStorageDirectory();
File target = new File(ext, "aquery/myfolder/photos.xml");              

aq
.progress(R.id.progress).download(url, target, new AjaxCallback<File>(){
       
       
public void callback(String url, File file, AjaxStatus status) {
               
               
if(file != null){
                        showResult
("File:" + file.length() + ":" + file, status);
               
}else{
                        showResult
("Failed", status);
               
}
       
}
       
});

InputStream

String url = "https://picasaweb.google.com/data/feed/base/featured?max-results=8";              

aq
.progress(R.id.progress).ajax(url, InputStream.class, new AjaxCallback<InputStream>(){
       
       
public void callback(String url, InputStream is, AjaxStatus status) {
               
               
if(is != null){
                        showResult
("InputStream:" + is, status);
               
}else{
                        showResult
("Failed", status);
               
}
       
}
       
});

Custom Type

AQuery by default supports types that are native to Android. For app specific data types, you can assign a custom Transformer to the ajax call and convert the raw data to a desired type. The benefit of transformer is that it's run under the background thread (similar to the natively supported types), therefore minimizing CPU cycles and avoid blocking on the UI thread.

This example show how to use Gson to transform raw data to user defined types.

private static class Profile{
       
public String id;
       
public String name;            
}

private static class GsonTransformer implements Transformer{

       
public <T> T transform(String url, Class<T> type, String encoding, byte[] data, AjaxStatus status) {                    
               
Gson g = new Gson();
               
return g.fromJson(new String(data), type);
       
}
}

public void async_transformer(){
       
       
String url = "https://graph.facebook.com/205050232863343";              
       
GsonTransformer t = new GsonTransformer();
       
        aq
.transformer(t).progress(R.id.progress).ajax(url, Profile.class, new AjaxCallback<Profile>(){                
               
public void callback(String url, Profile profile, AjaxStatus status) {  
                       
Gson gson = new Gson();
                        showResult
("GSON Object:" + gson.toJson(profile), status);              
               
}                      
       
});
   
}

Custom Type (Static Transformer)

A stateless static default transformer can also be set with AjaxCallback.setTransformer().

Transformers are selected in the following priority:

  1. Native
  2. instance transformer()
  3. static setTransformer()

 

//set the static transformer when application starts
GsonTransformer t = new GsonTransformer();
AjaxCallback.setTransformer(t);

//any subsequent ajax calls will use the static transformer for custom types
String url = "https://graph.facebook.com/205050232863343";
aq
.ajax(url, Profile.class, this, "callback");

Http POST

public void async_post(){
       
   
//do a twiiter search with a http post
       
   
String url = "http://search.twitter.com/search.json";
       
   
Map<String, Object> params = new HashMap<String, Object>();
   
params.put("q", "androidquery");
       
    aq
.ajax(url, params, JSONObject.class, new AjaxCallback<JSONObject>() {

       
@Override
       
public void callback(String url, JSONObject json, AjaxStatus status) {
               
            showResult
(json);
           
       
}
   
});
       
}

Http POST (Multipart)

AQuery support multipart post such as uploading an image to a service. Simply do a regular POST and put byte array, Inputstream, or File as one of the parameters.

private void aync_multipart(){
       
       
String url = "https://graph.facebook.com/me/photos";
       
       
Map<String, Object> params = new HashMap<String, Object>();
       
params.put("message", "Message");
       
       
//Simply put a byte[] to the params, AQuery will detect it and treat it as a multi-part post
       
byte[] data = getImageData();
       
params.put("source", data);
       
       
//Alternatively, put a File or InputStream instead of byte[]
       
//File file = getImageFile();          
       
//params.put("source", file);
       
       
AQuery aq = new AQuery(getApplicationContext());
        aq
.auth(handle).ajax(url, params, JSONObject.class, this, "photoCb");
       
}

Http POST (Custom Entity)

If a custom entity is required, you can use the special AQuery.POST_ENTITY key name to pass in an HttpEntity object.

public void async_post_entity() throws UnsupportedEncodingException{
       
   
String url = "http://search.twitter.com/search.json";
       
   
List<NameValuePair> pairs = new ArrayList<NameValuePair>();
        pairs
.add(new BasicNameValuePair("q", "androidquery"));                        
       
HttpEntity entity = new UrlEncodedFormEntity(pairs, "UTF-8");
   
       
Map<String, Object> params = new HashMap<String, Object>();
       
params.put(AQuery.POST_ENTITY, entity);
   
    aq
.progress(R.id.progress).ajax(url, params, JSONObject.class, new AjaxCallback<JSONObject>() {

       
@Override
       
public void callback(String url, JSONObject json, AjaxStatus status) {
           
            showResult
(json, status);
           
       
}
   
});
}

Http POST JSON

Posting JSON string can be done with custom entity or the following shortcut method. This is same as POST with StringEntity and header "Content-Type": "application/json". Note that the 3rd parameter is the expected http response type of the url, which might or might not be a JSONObject.

JSONObject input = new JSONObject();
input
.putOpt("hello", "world");
               
aq
.post(url, input, JSONObject.class, cb);

Long URL (2000+ length)

Url length shouldn't be longer than 2000 characters. (reference)

The http POST method might be used to get around this limit. For example, Google Chart allow a post method for requests that will run over 2000 characters long.

AQuery detects such case and automatically switch from GET to POST method if required.

Caching

Caching is easy with ajax requests. Just pass in an expire time as a parameter, and if the data is available, it will be served from the file cache instead of fetching over the network.

String url = "http://www.google.com";

//return a cached copy if the data is recently fetched within 15 minutes
long expire = 15 * 60 * 1000;

aq
.ajax(url, String.class, expire, new AjaxCallback<String>() {

   
@Override
   
public void callback(String url, String html, AjaxStatus status) {        
        showResult
(html);
   
}
       
});

Refresh Content

Passing expire time as -1 will ensure the content be refreshed immediately and to be file cached.

String url = "http://www.google.com";

long expire = -1;

aq
.ajax(url, String.class, expire, new AjaxCallback<String>() {

   
@Override
   
public void callback(String url, String html, AjaxStatus status) {        
        showResult
(html);
   
}
       
});

Invalidating Cache

Calling the invalidate method of the AjaxStatus object will invalidate the url content so that it will not be cached. It's useful when http status is 200 but the object returned is invalid.

public void callback(String url, JSONObject json, AjaxStatus status) {
   
       
if(json != null){
               
if("1".equals(json.optString("status"))){
                       
//do something
               
}else{
                       
//we believe the request is a failure, don't cache it
                        status
.invalidate();
               
}
       
}
}

Progress

We can show the loading progress by using the progress() method. Pass in the progress bar id, or any other view id to the progress method, and the view will be shown or hide to display ajax progress.

String url = "http://www.google.com/uds/GnewsSearch?q=Obama&v=1.0";                
aq
.progress(R.id.progress).ajax(url, JSONObject.class, this, "jsonCb");
ProgressDialog dialog = new ProgressDialog(this);

dialog
.setIndeterminate(true);
dialog
.setCancelable(true);
dialog
.setInverseBackgroundForced(false);
dialog
.setCanceledOnTouchOutside(true);
dialog
.setTitle("Sending...");

String url = "http://www.google.com/uds/GnewsSearch?q=Obama&v=1.0";                
aq
.progress(dialog).ajax(url, JSONObject.class, this, "jsonCb");
//Use activity's setProgressBarIndeterminateVisibility(show);
//Remember to call this before setContentView(): requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
String url = "http://www.google.com/uds/GnewsSearch?q=Obama&v=1.0";          
aq
.progress(this).ajax(url, JSONObject.class, this, "jsonCb");  

Activity Finished Detection

AQuery will examine the initialization context and skip the ajax callback if an activity is already stopped before the aync task is completed. This behavior avoid unnecessary work and avoid modifying ui states that could be illegal (such as showing a dialog when an activity is not longer active).

//using the activity as context will ensure no callback is called when activity is finished
AQuery aq = new AQuery(activity);

//using the application context will ensure the callback to be called as long as the application is running
AQuery aq = new AQuery(getApplicationContext());

Synchronous Call (Block)

If the ajax call is run outside of main thread, the sync() method can be used to block the calling thread until the ajax call is completed (or until it's timed out).

Fetch result synchronously:

String url = "http://www.google.com/uds/GnewsSearch?q=Obama&v=1.0";
       
AjaxCallback<JSONObject> cb = new AjaxCallback<JSONObject>();          
cb
.url(url).type(JSONObject.class);            
       
aq
.sync(cb);
       
JSONObject jo = cb.getResult();
AjaxStatus status = cb.getStatus();

Note that this will block the thread until the result is returned. The actual work will be done in another thread pool. Calling this method in Main/UI thread will cause an exception.

Ajax Status

An AjaxStatus object is returned with any callback. This object holds some meta information regarding the aync task performed.

public void callback(String url, JSONObject json, AjaxStatus status) {
   
   
int source = status.getSource();
   
int responseCode = status.getCode();
   
long duration = status.getDuration();
   
Date fetchedTime = status.getTime();
   
String message = status.getMessage();
   
String redirect = status.getRedirect();
   
DefaultHttpClient client = status.getClient();

   
//returns the html response when response code is not 2xx
   
String errorResponse = status.getError();  
}

javadoc

Advance

The AQuery object provide various commonly used "ajax" methods. For more advanced (but less commonly used) features such as http header and authentication, AjaxCallback can be used directly to customize the requests.

Note: url and type are required parameters.

String url = "http://www.google.com/uds/GnewsSearch?q=Obama&v=1.0";

AjaxCallback<JSONObject> cb = new AjaxCallback<JSONObject>();        
cb
.url(url).type(JSONObject.class).weakHandler(this, "jsonCb").fileCache(true).expire(0);

aq
.ajax(cb);

Http Headers

Use the header method to configure http request headers.

String url = "http://www.google.com";

AjaxCallback<String> cb = new AjaxCallback<String>();        
cb
.url(url).type(String.class).weakHandler(this, "stringCb");

cb
.header("Referer", "http://code.google.com/p/android-query/");
cb
.header("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.2) Gecko/20100101 Firefox/6.0.2");

aq
.ajax(cb);

Http Cookies

Use the cookie method to set http cookies.

String url = "http://www.androidquery.com/p/doNothing";

AjaxCallback<JSONObject> cb = new AjaxCallback<JSONObject>();          
cb
.url(url).type(JSONObject.class).weakHandler(this, "cookieCb");

cb
.cookie("hello", "world").cookie("foo", "bar");              
aq
.ajax(cb);

Http Response Headers

status.getHeaders()

Returns a list of headers. If the request is cached or a http multipart post, this method returns an empty list.

Http Response Cookies

status.getCookies();

Returns a list of cookies. If the request is cached or a http multipart post, this method returns an empty list.

Encoding (BETA)

The default ajax callback uses UTF-8 to transform the object. If type String is specified and the content is html, AQuery will make a best-effort attempt to detect the encoding by inspecting the response header and the inline html META tag. If file cache is enabled, the content will be stored as UTF-8 bytes and subsequent read will not require encoding detection again.

If custom encoding is needed, uses the encoding() method to fix the encoding.

        
//Using String.class type will attempt to detect the encoding of a page and transform it to utf-8
               
String url = "http://114.xixik.com/gb2312_big5/";
aq
.progress(R.id.progress).ajax(url, String.class, 0, this, "encodingCb");
               
       

Maintenance

AQuery provides few utility functions to help you control ajax and caching behavior.

Clean Up

If you use file cache for images, regularly clean the cache dir when the application exits.

Simple

protected void onDestroy(){
       
       
super.onDestroy();
       
       
//clean the file cache when root activity exit
       
//the resulting total cache size will be less than 3M  
       
if(isTaskRoot()){
               
AQUtility.cleanCacheAsync(this);
       
}
}

Advance

protected void onDestroy(){
       
       
super.onDestroy();
       
       
if(isTaskRoot()){

               
//clean the file cache with advance option
               
long triggerSize = 3000000; //starts cleaning when cache size is larger than 3M
               
long targetSize = 2000000;      //remove the least recently used files until cache size is less than 2M
               
AQUtility.cleanCacheAsync(this, triggerSize, targetSize);
       
}
       
}

출처 : http://blog.naver.com/xinfra/80207467204

스크롤뷰 안에 스크롤 가능한 뷰들(맵뷰, 리스트뷰, 그리드뷰 등)을 구성 했을 경우 자식 스크롤뷰에서 스크롤시에 자식이 스크롤 되지 않고 부모가 스크롤 이벤트를 받아서 움직인다. 이를 방지하기위해 자식이 이벤트 처리 동안 부모의 이벤트를 무시 되게 처리 해야 한다.

#xml
 
<ScrollView
	android:id="@+id/calladd_sv"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	android:fillViewport="true">

	<LinearLayout
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:orientation="vertical">
		<RelativeLayout
			android:id="@+id/calladd_map_rect_rl"
			android:layout_width="match_parent"
			android:layout_height="match_parent">
		</RelativeLayout>
	</LinearLayout>
</ScrollView>

#java
        scrollView = (ScrollView)findViewById(R.id.calladd_sv);
        mMapView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                scrollView.requestDisallowInterceptTouchEvent(true);
                return false;
            }
        });

'프로그래밍 > Android Tip' 카테고리의 다른 글

Android 개발 가이드  (0) 2019.12.30
ActivityLifecycleCallbacks, LifecycleObserver, LifecycleOwner  (0) 2018.11.13
[Android] Aquery Image  (0) 2017.08.07
[Android] Aquery Network  (0) 2017.08.07
[Android] 내부 저장소 경로  (0) 2017.06.28

System directories

MethodResult
Environment.getDataDirectory()/data
Environment.getDownloadCacheDirectory()/cache
Environment.getRootDirectory()/system

External storage directories

MethodResult
Environment.getExternalStorageDirectory()/storage/sdcard0
Environment.getExternalStoragePublicDirectory(DIRECTORY_ALARMS)/storage/sdcard0/Alarms
Environment.getExternalStoragePublicDirectory(DIRECTORY_DCIM)/storage/sdcard0/DCIM
Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS)/storage/sdcard0/Download
Environment.getExternalStoragePublicDirectory(DIRECTORY_MOVIES)/storage/sdcard0/Movies
Environment.getExternalStoragePublicDirectory(DIRECTORY_MUSIC)/storage/sdcard0/Music
Environment.getExternalStoragePublicDirectory(DIRECTORY_NOTIFICATIONS)/storage/sdcard0/Notifications
Environment.getExternalStoragePublicDirectory(DIRECTORY_PICTURES)/storage/sdcard0/Pictures
Environment.getExternalStoragePublicDirectory(DIRECTORY_PODCASTS)/storage/sdcard0/Podcasts
Environment.getExternalStoragePublicDirectory(DIRECTORY_RINGTONES)/storage/sdcard0/Ringtones

Application directories ( 사용 예 : context.getCacheDir() )

MethodResult
getCacheDir()/data/data/package/cache
getFilesDir()/data/data/package/files
getFilesDir().getParent()/data/data/package

Application External storage directories

MethodResult
getExternalCacheDir()/storage/sdcard0/Android/data/package/cache
getExternalFilesDir(null)/storage/sdcard0/Android/data/package/files
getExternalFilesDir(DIRECTORY_ALARMS)/storage/sdcard0/Android/data/package/files/Alarms
getExternalFilesDir(DIRECTORY_DCIM)/storage/sdcard0/Android/data/package/files/DCIM
getExternalFilesDir(DIRECTORY_DOWNLOADS)/storage/sdcard0/Android/data/package/files/Download
getExternalFilesDir(DIRECTORY_MOVIES)/storage/sdcard0/Android/data/package/files/Movies
getExternalFilesDir(DIRECTORY_MUSIC)/storage/sdcard0/Android/data/package/files/Music
getExternalFilesDir(DIRECTORY_NOTIFICATIONS)/storage/sdcard0/Android/data/package/files/Notifications
getExternalFilesDir(DIRECTORY_PICTURES)/storage/sdcard0/Android/data/package/files/Pictures
getExternalFilesDir(DIRECTORY_PODCASTS)/storage/sdcard0/Android/data/package/files/Podcasts
getExternalFilesDir(DIRECTORY_RINGTONES)/storage/sdcard0/Android/data/package/files/Ringtones


출처 : https://gist.github.com/granoeste/5574148

'프로그래밍 > Android Tip' 카테고리의 다른 글

Android 개발 가이드  (0) 2019.12.30
ActivityLifecycleCallbacks, LifecycleObserver, LifecycleOwner  (0) 2018.11.13
[Android] Aquery Image  (0) 2017.08.07
[Android] Aquery Network  (0) 2017.08.07
[Android] ScrollView In ScrollView  (0) 2017.06.28

+ Recent posts