홈으로 홈으로 | 무료회원가입 | 아이디/비번찾기 | 즐겨찾기
추천음악방송메인홈1대1상담음악방송청취
뽕짝아가씨(무료음악채널)
okTrot(무료음악채널)
전통가요(무료음악채널)

온라이브스토어(앱다운로드)
온라이브(방송등록및청취)

환상의뽕짝파티 무료음악
명작트로트메들리 무료음악
트로트메들리관광 무료음악
동영상노래방
가사검색

POP Player
신나는 고스톱
컴퓨터 오목
작은 음악다방
자동러시 웹플레이어신청

보안∵서버∵쿠키
윈도우∵프레임
이미지∵배경
시간∵달력∵계산
상태바∵타이틀바
음악∵영상
폼∵전송∵테이블
키보드∵마우스
효과∵링크∵메뉴
Script∵php
기타
PHP 강좌
윈도우관련팁
웹관련팁
홈페이지제작팁
기본강좌
레지스트리
윈도우서버
리눅스서버
Android
Android 개발
2년 전
시스템 정보


StringBuffer buf = new StringBuffer();

buf.append("VERSION.RELEASE {"+Build.VERSION.RELEASE+"}");
buf.append("\\nVERSION.INCREMENTAL {"+Build.VERSION.INCREMENTAL+"}");
buf.append("\\nVERSION.SDK {"+Build.VERSION.SDK+"}");
buf.append("\\nBOARD {"+Build.BOARD+"}");
buf.append("\\nBRAND {"+Build.BRAND+"}");
buf.append("\\nDEVICE {"+Build.DEVICE+"}");
buf.append("\\nFINGERPRINT {"+Build.FINGERPRINT+"}");
buf.append("\\nHOST {"+Build.HOST+"}");
buf.append("\\nID {"+Build.ID+"}");

Log.d("build",buf.toString());

====================================================================================

UI

Screen

화면 크기 가져오기


DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
screenWidth = metrics.widthPixels;

화면 밝기 조정


WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.screenBrightness = (float)progress/100.0f; // 1.0f = 100%
getWindow().setAttributes(lp);

Activity

화면 방향(Screen Orientation) 고정

AndroidManifest.xml에서 해당 Activity 속성을 다음과 같이 수정.


<activity
            android:screenOrientation="landscape"
            ...>
. . .
</activity>

즉 android:screenOrientation 속성을 "landscape" 혹은 "portrait" 등으로 변경.

Title Bar 제거

onCreate() 에서 처리하는 방법


//Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);

//Remove notification bar
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

//set content view AFTER ABOVE sequence (to avoid crash)
this.setContentView(R.layout.your_layout_name_here);

AndroidManifest.xml에서 처리하는 방법


<activity
            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
            ...>
. . .
</activity>

Content View 가져오기

setContentView() 로 지정한 Activity의 Content View를 가져오는 방법.


this.getWindow().getDecorView().findViewById(android.R.id.content)

or


this.findViewById(android.R.id.content)

or


this.findViewById(android.R.id.content).getRootView()




액티비티에 파라매터 전달


Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
Bundle b = new Bundle();
b.putInt("key", 1); //Your id
intent.putExtras(b); //Put your id to your next Intent
startActivity(intent);
finish();


Bundle b = getIntent().getExtras();
int value = b.getInt("key");

Back key로 액티비티를 닫을 때의 이벤트


@Override
public void onBackPressed() { ... }

바깥 터치로 대화 창이 닫히지 않게 하기


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

        // Activity에서 setFinishOnTouchOutside(false)로 속성 변경.
        this.setFinishOnTouchOutside(false);
    }

    private void showInfoDialog(int string_id) {
        ProgressDialog dlg = new ProgressDialog(getActivity());
        dlg.setTitle(R.string.login);
        dlg.setMessage(getString(string_id));
        dlg.setProgressStyle(ProgressDialog.STYLE_SPINNER);

        // Dialog에서는 다음과 같이 셋팅.
        dlg.setCancelable(false);
        dlg.setCanceledOnTouchOutside(false);

        // . . .
    }

Fragment (API 11)

http://muzesong.tistory.com/84

한 Activity 내에서 다시 UI영역을 분할해서 관리할 수 있게 해준다. Fragment도 Activiy와 비슷한 생명주기를 갖는다.

Fragment에 파라매터 전달


/*** From Activity you send data with intent as: ***/
Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
// set Fragmentclass Arguments
Fragmentclass fragobj = new Fragmentclass();
fragobj.setArguments(bundle);


/*** in Fragment onCreateView method: ***/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    String strtext = getArguments().getString("edttext");    
    return inflater.inflate(R.layout.fragment, container, false);
}

ViewPager

'스와이프로 페이지 전환' 막기


public class CustomViewPager extends ViewPager {

private boolean enabled;

public CustomViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.enabled = true;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (this.enabled) {
        return super.onTouchEvent(event);
    }

    return false;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    if (this.enabled) {
        return super.onInterceptTouchEvent(event);
    }

    return false;
}

public void setPagingEnabled(boolean enabled) {
    this.enabled = enabled;
}

}


<mypackage.CustomViewPager
android:id="@+id/myViewPager"
android:layout_height="match_parent"
android:layout_width="match_parent" />

이미지 처리

Bitmap


Bitmap bmImg = BitmapFactory.decodeFile("path of your img1");
imageView.setImageBitmap(bmImg);

Drawable

복제


Drawable clone = drawable.getConstantState().newDrawable();






Note.png

주의!!

같은 리소스ID로부터 만들어진 모든 Drawable 객체는 color filter 등의 상태를 공유하고 있다. 만약 복제의 목적이 이런 공유된 상태에서 분리시키려는 것이라면, clone을 하지말고 다음과 같은 코드를 사용할 것!


// To make a drawable use a separate constant state
drawable.mutate();




Grayscale


    public static Drawable convertToGrayscale(Drawable drawable) {
        ColorMatrix matrix = new ColorMatrix();
        matrix.setSaturation(0);

        ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
        drawable.setColorFilter(filter);

        return drawable;
    }

컬러 변환


    public static Drawable changeColor(Drawable drawable, int color) {
        Drawable d = drawable.mutate();
        d.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);

        return d;
    }

Drawable 내용을 Canvas에 그리기


            Canvas canvas = new Canvas(lq);
            Drawable drawable = drawImageView.getDrawable().mutate();
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);
            canvas.save();

Shape Drawable

http://www.androidpub.com/2113

XML로 정의한 벡터 이미지를 Drawble 객체로 활용할 수 있다.


<!-- 사각형 -->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#FF0000FF"/>
    <stroke android:width="4dp" android:color="#FFFFFFFF"
            android:dashWidth="1dp" android:dashGap="2dp" />
    <padding android:left="7dp" android:top="7dp"
            android:right="7dp" android:bottom="7dp" />
    <corners android:radius="4dp" />
</shape>

<!-- 타원 -->
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
    <solid android:color="#00000000"/>
    <stroke android:width="4dp" android:color="#99000000"
            android:dashWidth="4dp" android:dashGap="2dp" />
    <padding android:left="7dp" android:top="7dp"
            android:right="7dp" android:bottom="7dp" />
    <corners android:radius="4dp" />
</shape>

<!-- Line -->
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="line">
    <stroke android:width="1dp" android:color="#FF000000"
            android:dashWidth="1dp" android:dashGap="2dp" />
</shape>

그라데이션 효과


<gradient android:startColor="#FFFF0000" android:endColor="#80FF00FF" android:angle="270"/>

ImageView

로컬 파일의 이미지 표시


File imgFile = new  File(“filepath”);
if(imgFile.exists()) {
        ImageView myImage = new ImageView(this);
        myImage.setImageURI(Uri.fromFile(imgFile));
}

이미지 갱신

ImageView의 invalidate()를 호출하면 되는데, 반드시 UI 쓰레드에서 실행되야 하는 것에 주의.


runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    imageView.setImageBitmap(BitmapFactory.decodeByteArray(imgArray, 0, imgArray.length));
                    imageView.invalidate();
                }
            });

WebView

http://developer.android.com/guide/webapps/webview.html

HTML View

String 변수에 담겨있는 HTML데이터를 WebView를 통해서 보여주고자 할 때, 문자열 인코딩 문제가 발생할 수 있다. 이 경우, WebView의 loadData() 말고 loadDataWithBaseURL() 매서드를 사용하자. loadData()에서는 인코딩 설정이 제대로 동작하지 않는다. (버그인듯)


WebView htmlView = (WebView) rootView.findViewById(R.id.body_html);
htmlView.loadDataWithBaseURL(null, "<p>何かのテストです。</p>", "text/html", "UTF-8", null);

WebView에서 링크가 새창으로 열리지 않게

WebViewClient를 지정해 주지 않으면, 웹 뷰 내의 링크가 외부 웹브라우져를 통해서 열리게 된다.


WebView webview = new WebView(this /*context*/);
webview.setWebViewClient(new WebViewClient());
webview.loadUrl("http://...");

Java Script

WebView에서 Java Script 사용가능 하게 하기.


WebView webView = (WebView) findViewById(R.id.webview);
webView.getSettings().setJavaScriptEnabled(true);

Alert/Confirm 등 활성화

WebChromeClient를 구현해 준다.


public class MainActivity extends Activity {
    WebView webView;


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

        webView = (WebView) findViewById(R.id.webview);

        webView.getSettings().setDomStorageEnabled(true);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.getSettings().setUserAgentString("IAA");
        webView.getSettings().setAllowFileAccess(true);
        webView.getSettings().setAllowContentAccess(true);
        webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);

        webView.setWebViewClient(new WebViewClient());
        webView.setWebChromeClient(new WebChromeClient() {
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                showAlert(message, result);
                return true;
                //return super.onJsAlert(view, url, message, result);
            }

            @Override
            public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
                return super.onJsConfirm(view, url, message, result);
            }

            @Override
            public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
                return super.onJsPrompt(view, url, message, defaultValue, result);
            }

            public void onProgressChanged(WebView view, int progress) {
                setProgress(progress * 1000);
            }
        });

        webView.addJavascriptInterface(new WebAppInterface(this), "Android");


        webView.loadUrl("http://www.ifanclub.jp/");
        //webView.loadUrl("http://sizuha.iptime.org/");

        Button btnReload = (Button) findViewById(R.id.btn_reload);
        btnReload.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                reload();
            }
        });

        Button btnBack = (Button) findViewById(R.id.btn_back);
        btnBack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                goBack();
            }
        });
    }

    void reload() {
        webView.reload();
    }

    void goBack() {
        webView.goBack();
    }

    void showAlert(String message, final JsResult result) {
        AlertDialog dlg = new AlertDialog.Builder(this)
                .setMessage(message)
                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        result.confirm();
                    }
                })
                .create();

        dlg.setCancelable(false);
        dlg.setCanceledOnTouchOutside(false);
        dlg.show();
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            goBack();
            return true;
        }

        return super.onKeyUp(keyCode, event);
    }
}

Javascript에서 Android 코드 호출


public class WebAppInterface {
    Context mContext;

    /** Instantiate the interface and set the context */
    WebAppInterface(Context c) {
        mContext = c;
    }

    /** Show a toast from the web page */
    @JavascriptInterface
    public void showToast(String toast) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
}


webView.addJavascriptInterface(new WebAppInterface(this), "Android");


    function showAndroidToast(toast) {
        Android.showToast(toast);
    }

ListView

ListView 갱신

Adaptor안에서는 notifyDataSetChanged()를 호출하면 되지만, ListView 자체에서는 다음과 같이 하면 된다.


mListView = (ListView) rootView.findViewById(android.R.id.list);
// . . .
mListView.invalidateViews();

리스트 뷰 맨 아래에 Footer 추가


        // set list
        mListView = (ListView) rootView.findViewById(android.R.id.list);
        mListView.setAdapter(mAdapter);

        // Adding Load More
        View loadMoreView = inflater.inflate(R.layout.item_load_more, null);
        mListView.addFooterView(loadMoreView);

Alert Dialog


AlertDialog.Builder alert = new AlertDialog.Builder(MyActivity.this);
alert.setPositiveButton("확인", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        dialog.dismiss();     //닫기
    }
});
alert.setMessage("테스트 메세지");
alert.show();


AlertDialog.Builder alert_confirm = new AlertDialog.Builder(MyActivity.this);
alert_confirm.setMessage("프로그램을 종료 하시겠습니까?").setCancelable(false).setPositiveButton("확인",
new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        // 'YES'
    }
}).setNegativeButton("취소",
new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        // 'No'
    return;
    }
});
AlertDialog alert = alert_confirm.create();
alert.show();

ProgressDialog

http://seesaawiki.jp/w/moonlight_aska/d/%A5%D7%A5%ED%A5%B0%A5%EC%A5%B9%A5%D0%A1%BC%A4%F2%A5%C0%A5%A4%A5%A2%A5%ED%A5%B0%A4%CB%C9%BD%BC%A8%A4%B9%A4%EB


     package com.moonlight_aska.android.progressdialog01;

    import android.app.Activity;
    import android.app.ProgressDialog;
    import android.os.Bundle;
    import android.view.View;

    public class ProgressDialog01 extends Activity {
      private ProgressDialog dlg = null;
      /** Called when the activity is first created. */
      @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        dlg = new ProgressDialog(this);
        // タイトル, 本文を設定
        dlg.setTitle("プログレスバー");
        dlg.setMessage("しばらくお待ちください.");
        // スタイルを設定
        dlg.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);

        findViewById(R.id.button_id).setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
            // TODO Auto-generated method stub
            dlg.show();
            new Thread(new Runnable() {
              @Override
              public void run() {
                try {
                  for(int i=0; i<dlg.getMax(); i++) {
                    // 進捗率を更新
                    dlg.setProgress(i);
                    Thread.sleep(100);
                  }
                } catch (InterruptedException e) {
                  // 例外処理
                }
                dlg.dismiss();
              }
            }).start();
          }
        });
      }
    }

ProgressBar

http://www.adakoda.com/android/000079.html


package com.adakoda.android.progressbarsample;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ProgressBar;

import com.adakoda.android.progressbarsample.R.id;

public class ProgressBarSampleActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        ProgressBar progressBar = (ProgressBar) findViewById(id.progressbar_horizontal);
        // 水平プログレスバーの最大値を設定します
        progressBar.setMax(100);
        // 水平プログレスバーの値を設定します
        progressBar.setProgress(30);
        // 水平プログレスバーのセカンダリ値を設定します
        progressBar.setSecondaryProgress(70);
    }
}


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <ProgressBar android:id="@+id/progressbar_horizontal"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        android:indeterminate="false"
        style="?android:attr/progressBarStyleHorizontal" />
    <ProgressBar android:id="@+id/progressbar_small"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:indeterminate="false"
        style="?android:attr/progressBarStyleSmall" />
    <ProgressBar android:id="@+id/progressbar"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        style="?android:attr/progressBarStyle" />
    <ProgressBar android:id="@+id/progressbar_large"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        style="?android:attr/progressBarStyleLarge" />
</LinearLayout>

PopupMenu (API 11)

http://developer.android.com/reference/android/widget/PopupMenu.html

Text

Underline 효과

Button과 TextView에서 밑줄 효과 넣기.


public static void makeUnderlineText(TextView v) {
    v.setPaintFlags(v.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
}

public static void makeUnderlineText(Button b) {
    b.setPaintFlags(b.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
}

기타

실시간에서 UI컨트롤의 Size 조정

LayoutParams를 이용해야 한다.


Button button = (Button) findViewById(view.getId());
LinearLayout rLGreen = ((LinearLayout) button.getParent());
rLGreen.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));


====================================================================================


IO

Preference


// Context의 getSharedPreferences()로 객체를 가져온다.
// 사용할 수 있는 MODE는 다음과 같다.
// MODE_PRIVATE = 他のアプリからアクセス不可
// MODE_WPRLD_READABLE = 他のアプリから読み込み可能
// MODE_WORLD_WRITEABLE = 他のアプリから書き込み可能
SharedPreferences pref = getSharedPreferences("ファイル名", MODE_PRIVATE);

// 값 가져오기
pref.getString("key", "default value");

// 값 쓰기
SharedPreferences.Editor editor = pref.edit();
editor.putString("key", "value");
editor.commit();

다른 앱에서 Shared Preference 가져오기


Context otherContext = createPackage("com.example.pref", mode);
settings = otherContext.getSharedPreferences("Name", mode);

File

파일이 존재하는지 확인


File file = this.getFileStreamPath("test.txt");  
boolean isExists = file.exists();

디렉토리 만들기


File dir = new File(context.getExternalFilesDirs()  + "/Test/Test2");
if(!dir.exists()){
  dir.mkdirs();
}

파일 복사


    private boolean copyFile(File file , String save_file){
        boolean result;
        if (file != null && file.exists()) {
            try {
                FileInputStream fis = new FileInputStream(file);
                FileOutputStream newfos = new FileOutputStream(save_file);
                int readcount=0;
                byte[] buffer = new byte[1024];
                while ((readcount = fis.read(buffer,0,1024)) != -1) {
                    newfos.write(buffer,0,readcount);
                }
                newfos.close();
                fis.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            result = true;
        } else {
            result = false;
        }
        return result;
    }

HTTP

Apache HTTP Client

Android 6에서 Apache HTTP Client 라이브러리가 제거되었다. 대신 HttpURLConnection 을 권장하고 있다.

그래도 계속 사용하고 싶다면, App/build.gradle 파일의 첫 부분을 다음과 같이 수정한다.
apply plugin: 'com.android.application'

android {
    useLibrary 'org.apache.http.legacy'
.
.
.


파일 내려받기


public class FileDownloader extends AsyncTask<String, String, Integer> {

    final static int BUFFER_SIZE = 4096;

    private String storagePath = "";
    public void setStagePath(String path) {
        storagePath = path;
    }

    public static interface IOnDownloadEvent {
        void onOneFileDownloadEnd(String filenameWithPath);
        void onDownloadTotalEnd(int download_count);
    }

    public IOnDownloadEvent downloadEventRecv;

    public boolean overwrite = false;


    @Override
    protected Integer doInBackground(String... urls) {
        int dn_cnt = 0;

        for (String url_str : urls) {
            // Escape early if cancel() is called
            if (isCancelled()) break;

            File outFile = null;

            try {
                URL url = new URL(url_str);

                final String out_filename = URLUtil.guessFileName(url_str, null, null);
                final String out_filenameWithPath = Environment.getExternalStorageDirectory().toString() +
                        "/" + storagePath + "/" + out_filename;

                outFile = new File(out_filenameWithPath);
                if (!overwrite &&outFile.exists()) continue;

                URLConnection connection = url.openConnection();
                connection.connect();

                outFile.mkdirs();

                InputStream input = new BufferedInputStream(url.openStream(), BUFFER_SIZE);
                OutputStream output = new FileOutputStream(outFile);

                byte data[] = new byte[BUFFER_SIZE];

                int read_count;
                while ((read_count = input.read(data)) != -1) {
                    output.write(data, 0, read_count);
                    dn_cnt++;
                }

                output.flush();
                output.close();
                input.close();

                if (downloadEventRecv != null) downloadEventRecv.onOneFileDownloadEnd(out_filenameWithPath);
            }
            catch (MalformedURLException e) {
                e.printStackTrace();
                continue;
            }
            catch (IOException e) {
                e.printStackTrace();
                if (outFile != null) outFile.delete();

                continue;
            }
        }

        return dn_cnt;
    }

    @Override
    protected void onPostExecute(Integer dnCnt) {
        if (downloadEventRecv != null) downloadEventRecv.onDownloadTotalEnd(dnCnt);

        super.onPostExecute(dnCnt);
    }
}

다운 받기 전에 파일 크기 알아내기


URL url = new URL("http://server.com/file.mp3");
URLConnection urlConnection = url.openConnection();
urlConnection.connect();
int file_size = urlConnection.getContentLength();

JSON


{
"sys":
   {
      "country":"GB",
      "sunrise":1381107633,
      "sunset":1381149604
   },
"weather":[
   {
      "id":711,
      "main":"Smoke",
      "description":"smoke",
      "icon":"50n"
   }
],
"main":
   {
      "temp":304.15,
      "pressure":1009,
   }
}


String in;
JSONObject reader = new JSONObject(in);

JSONObject sys  = reader.getJSONObject("sys");
country = sys.getString("country");

JSONObject main  = reader.getJSONObject("main");
temperature = main.getString("temp");

JSONArray weather = reader.getJSONArray("weather");

SQLite

DB 초기화/Open


public class LocalDbHelper extends SQLiteOpenHelper {
    private static final String DATABASE_NAME = "test.db";
    private static final int DATABASE_VERSION = 1;

    public LocalDbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // create DB tables.
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}


dbHelper = new LocalDbHelper(context);

// open
SQLiteDatabase db = dbHelper.getWritableDatabase();

// close
if (db != null) db.close();
if (dbHelper != null) dbHelper.close();

Data Types

NULL  NULL値  
INTEGER  符号付整数。1, 2, 3, 4, 6, or 8 バイトで格納。날짜 등의 정보도 숫자로 변환해서 처리해야 한다.  
REAL  浮動小数点数。8バイトで格納  
TEXT  テキスト。UTF-8, UTF-16BE or UTF-16-LEのいずれかで格納  
BLOB  Binary Large OBject。入力データをそのまま格納  

Create Table


db.execSQL("CREATE TABLE notice( " +
                "id INTEGER " +
                "title TEXT, " +
                "contents_data TEXT, " +
                "pub_date INTEGER, " +
                "PRIMARY KEY(date DESC, id ASC)" +
                ");");

Query


Cursor cursor = db.query("DB_TABLE_NAME", new String[] { cols, ... },
                "Selection Query", new String[] { query_params, ... }, "groupBy", "having", "orderBy", "limit");

while (cursor.moveToNext()) {
// TODO ...
}

cursor.close();

Insert/Update

삽입 하면서, 이미 데이터가 존재하는 경우는 덮어쓰기(update)를 수행한다.


SQLiteDatabase db = dbHelper.getWritableDatabase();

ContentValues values = new ContentValues();
values.put("column1", 0);
values.put("column2", "string");
values.put("column3", 0.0);

try {
      db.insertWithOnConflict("TABLE_NAME", null, values, SQLiteDatabase.CONFLICT_REPLACE);
}
catch (IllegalStateException e) {
    // DB is already closed.
}

Sound

MediaPlayer


public static void play(int sndResID, float speed) {
        MediaPlayer mp = MediaPlayer.create(context, sndResID);
        play(mp, speed);
}

public static void play(String uri, float speed) {
        MediaPlayer mp = MediaPlayer.create(context, Uri.parse(uri));
        play(mp, speed);
}

private static void play(MediaPlayer mp, float speed) {
        if (Build.VERSION.SDK_INT >= 23 /* Android 6.0 */) {
                PlaybackParams params = mp.getPlaybackParams();
                params.setSpeed(speed);

                mp.setPlaybackParams(params);
        }

        mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                        mp.release();
                }
        });
        mp.start();
}

Sound Pool

초기화


SoundPool sndPool;

if (Build.VERSION.SDK_INT < 21 /* Android 5.0 */) {
    sndPool = new SoundPool(MAX_STREAMS, AudioManager.STREAM_MUSIC, 0);
}
else {
    sndPool = new SoundPool.Builder()
            .setMaxStreams(10)
            .build();
}

Load


sndPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
        @Override
        public void onLoadComplete(SoundPool soundPool, int soundId, int status) {
                // TODO
        }
});

int soundID = sndPool.load(audioPath, 1 /* priority */);

//--- or ---//

int res_id = 00000; // Resource ID
int soundID = sndPool.load(res_id, 1 /* priority */);

Play


boolean loop = false;
sndPool.play(sound_id, 1 /* Left Volume */, 1 /* Right Volume */, 1 /* priority */, loop ? -1 : 0, 1f /* play rate: 0.5f ~ 2.0f */);


====================================================================================

Date/Time

현재 날짜/시간 가져오기


Calendar calendar = Calendar.getInstance();

날짜/시간 셋팅


Calendar calendar = Calendar.getInstance();
calendar.clear(); // 중요: set 하기 전에 반드시 clear를 해줄 것!
calendar.set(year, month, day, hour, min, sec);
long datetile = calendar.getTimeInMillis();

====================================================================================

Threading

AsyncTask

http://developer.android.com/reference/android/os/AsyncTask.html


private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
}


new DownloadFilesTask().execute(url1, url2, url3);

AsyncTask's generic types

The three types used by an asynchronous task are the following:
1.Params, the type of the parameters sent to the task upon execution.
2.Progress, the type of the progress units published during the background computation.
3.Result, the type of the result of the background computation.

Not all types are always used by an asynchronous task. To mark a type as unused, simply use the type Void:


private class MyTask extends AsyncTask<Void, Void, Void> { ... }

Events

When an asynchronous task is executed, the task goes through 4 steps:
1.onPreExecute()
2.doInBackground(Params...)
3.onProgressUpdate(Progress...)
4.onPostExecute(Result)

주의할 점
The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)


====================================================================================

암호화

SHA1


import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Sha1Hex {
    public String makeSHA1Hash(String input) throws NoSuchAlgorithmException {
            MessageDigest md = MessageDigest.getInstance("SHA1");
            md.reset();
            byte[] buffer = input.getBytes();
            md.update(buffer);
            byte[] digest = md.digest();

            String hexStr = "";
            for (int i = 0; i < digest.length; i++) {
                hexStr +=  Integer.toString( ( digest[i] & 0xff ) + 0x100, 16).substring( 1 );
            }
            return hexStr;
    }
}


====================================================================================

Reource

리소스를 참조해 코드에서 텍스트 크기 설정


<dimen name="text_medium">18sp</dimen>

Set the size in code:


textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimension(R.dimen.text_medium));

More Resource Types

http://developer.android.com/guide/topics/resources/more-resources.html

====================================================================================
Google Cloud Messaging (GCM)

API Key 발급받기

당연히 구글 개발자 등록이 먼저 되어 있어야 한다.
1. https://code.google.com/apis/console 접속
2. API Access > Create new Server Key 메뉴로 들어감.
3. 허가할 IP address를 입력하라고 나오는데, 아무것도 쓰지 않으면 모두 허용.
4. Create 버튼을 누르면 키 생성.

여기서 생성된 키로 서버 어플케이션에서 푸시 메세지를 보낼 수 있다.

Sender ID (Project ID)

클라이언트에서 GCM에 등록을 할 때 필요한 Sender ID로서, Project ID가 있어야 한다.

API Console사이트의 URL에서 project: 이후에 나오는 숫자가 Project ID이다.

필요한 라이브러리(Android)
1. SDK Manager > Extras/Google Play services 라이브러리 설치.

Clinet

App/build.gradle (Android Studio)

dependencies에 compile "com.google.android.gms:play-services:4.0.+" 항목 추가.
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:support-v4:21.0.+'
    compile 'com.android.support:appcompat-v7:21.0.+'
    compile 'com.android.support:recyclerview-v7:21.0.+'
    compile "com.google.android.gms:play-services:4.0.+"
    compile files('src/main/java/jp/co/xxxxxxxxx/pdf/jars/commons-io-2.4.jar')
}


AndroidManifest.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="패키지_이름">

    <!-- for GCM -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

    <permission
        android:name="패키지_이름.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />
    <uses-permission
        android:name="패키지_이름.permission.C2D_MESSAGE" />
    <!-- END -->

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="패키지_이름.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- for GCM -->
        <receiver
            android:name=".GCMBroadcastReceiver"
            android:permission="com.google.android.c2dm.permission.SEND" >
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <category android:name="패키지_이름" />
            </intent-filter>
        </receiver>

        <service android:name=".GCMIntentService" />
        <!-- END -->

    </application>

</manifest>

GcmBroadcastReceiver


import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.support.v4.content.WakefulBroadcastReceiver;

public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // intentをGcmIntentServiceで処理する
        ComponentName comp = new ComponentName(context.getPackageName(), GcmIntentService.class.getName());
        // サービスを起動、サービス動作中はWakeLockを保持する
        startWakefulService(context, (intent.setComponent(comp)));
        setResultCode(Activity.RESULT_OK);
    }
}

GcmIntentService

반드시 GcmIntentService 라는 이름(대소문자 주의)으로 class를 만들어야 한다.


import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;

import com.google.android.gms.gcm.GoogleCloudMessaging;

import java.util.Calendar;

public class GcmIntentService extends IntentService {
    public GcmIntentService() {
        super("MedportalGcmService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.e("GcmItentService", "onHandleIntent!");
        Bundle extras = intent.getExtras();

        for (String key : extras.keySet()) {
            Object value = extras.get(key);
            Log.i(Config.getAppTag(), "|" + String.format("%s : %s (%s)",
                    key, value.toString(),
                    value.getClass().getName()) + "|");
        }

        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
        String messageType = gcm.getMessageType(intent);

        if(! extras.isEmpty())
        {
            if(GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType))
            {
                Log.e("GcmIntentService", "Send error : " + extras.toString());
            }
            else if(GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType))
            {
                Log.i("GcmIntentService", "Deleted messages on server : " + extras.toString());
            }
            else if(GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType))
            {
                final String message = extras.getString("message");
                Log.i("GcmIntentService", "Received : " + extras.toString());

                showNoti(message);
            }
        }

        // Release the wake lock provided by the WakefulBroadcastReceiver.
        GcmBroadcastReceiver.completeWakefulIntent(intent);
    }

    void showNoti(String message) {
        long id = Calendar.getInstance().getTimeInMillis();
        showNoti((int)id, getApplicationContext(), "GCM Sample", message, message);
    }

    void showNoti(int notiID, Context context, String title, String message, String ticker) {
        // 받은 메세지를 Notification에 표시하는 예제.
        // 이 부분은 상황에 맞게....
        Intent intent = new Intent(context, LoginActivity.class);

        // Intent の作成
        PendingIntent contentIntent = PendingIntent.getActivity(
                context, REQUEST_CODE_MAIN_ACTIVITY, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        // LargeIcon の Bitmap を生成
        Bitmap largeIcon = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher);

        // NotificationBuilderを作成
        NotificationCompat.Builder builder = new NotificationCompat.Builder(
                context.getApplicationContext());
        builder.setContentIntent(contentIntent);
        // ステータスバーに表示されるテキスト
        builder.setTicker(ticker);
        // アイコン
        builder.setSmallIcon(R.drawable.ic_launcher);
        // Notificationを開いたときに表示されるタイトル
        builder.setContentTitle(title);
        // Notificationを開いたときに表示されるサブタイトル
        builder.setContentText(message);
        // Notificationを開いたときに表示されるアイコン
        builder.setLargeIcon(largeIcon);
        // 通知するタイミング
        builder.setWhen(System.currentTimeMillis());
        // 通知時の音・バイブ・ライト
        builder.setDefaults(Notification.DEFAULT_SOUND
                | Notification.DEFAULT_VIBRATE
                | Notification.DEFAULT_LIGHTS);
        // タップするとキャンセル(消える)
        builder.setAutoCancel(true);

        // NotificationManagerを取得
        NotificationManager manager = (NotificationManager) context.getSystemService(Service.NOTIFICATION_SERVICE);
        // Notificationを作成して通知
        manager.notify(notiID, builder.build());
    }

}




MainActivity


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

        context = getApplicationContext();

        // Check device for Play Services APK. If check succeeds, proceed with GCM registration.
        if (checkPlayServices()) {
            gcm = GoogleCloudMessaging.getInstance(this);
            regid = getRegistrationId(context);

            if (regid.isEmpty()) {
                registerInBackground();
            }
        }
        else {
            Log.i(Config.getAppTag(), "No valid Google Play Services APK found.");
        }

        // . . .
    }

    /////// GCM ///////////////////
    private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;

    /**
     * Substitute you own sender ID here. This is the project number you got
     * from the API Console, as described in "Getting Started."
     */
    String SENDER_ID = "your Project ID (API Console)";

    GoogleCloudMessaging gcm;
    Context context;

    String regid;


    /**
     * Check the device to make sure it has the Google Play Services APK. If
     * it doesn't, display a dialog that allows users to download the APK from
     * the Google Play Store or enable it in the device's system settings.
     */
    private boolean checkPlayServices() {
        int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
        if (resultCode != ConnectionResult.SUCCESS) {
            if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
                GooglePlayServicesUtil.getErrorDialog(resultCode, this,
                        PLAY_SERVICES_RESOLUTION_REQUEST).show();
            } else {
                Log.i(Config.getAppTag(), "This device is not supported.");
                finish();
            }
            return false;
        }
        return true;
    }

    /**
     * Stores the registration ID and the app versionCode in the application's
     * {@code SharedPreferences}.
     *
     * @param context application's context.
     * @param regId registration ID
     */
    private void storeRegistrationId(Context context, String regId) {
        // GCM 등록이 성공할 때 받은 registration ID를 어딘가에 보관해 둔다.
        Config.gcm_reg_id = regId;
        Config.savePreference();
    }

    /**
     * Gets the current registration ID for application on GCM service, if there is one.
     * <p>
     * If result is empty, the app needs to register.
     *
     * @return registration ID, or empty string if there is no existing
     *         registration ID.
     */
    private String getRegistrationId(Context context) {
        Config.loadPreference(context);

        String registrationId = Config.gcm_reg_id;
        if (registrationId.isEmpty()) {
            Log.i(Config.getAppTag(), "Registration not found.");
            return "";
        }
        // Check if app was updated; if so, it must clear the registration ID
        // since the existing regID is not guaranteed to work with the new
        // app version.
        int registeredVersion = Config.app_ver;
        int currentVersion = getAppVersion(context);
        if (registeredVersion != currentVersion) {
            Log.i(Config.getAppTag(), "App version changed.");

            Config.app_ver = currentVersion;
            Config.savePreference();

            return "";
        }
        return registrationId;
    }

    /**
     * Registers the application with GCM servers asynchronously.
     * <p>
     * Stores the registration ID and the app versionCode in the application's
     * shared preferences.
     */
    private void registerInBackground() {
        new AsyncTask<Void, Void, String>() {
            @Override
            protected String doInBackground(Void... params) {
                String msg = "";
                try {
                    if (gcm == null) {
                        gcm = GoogleCloudMessaging.getInstance(context);
                    }
                    regid = gcm.register(SENDER_ID);
                    msg = "Device registered, registration ID=" + regid;

                    // You should send the registration ID to your server over HTTP, so it
                    // can use GCM/HTTP or CCS to send messages to your app.
                    sendRegistrationIdToBackend();

                    // For this demo: we don't need to send it because the device will send
                    // upstream messages to a server that echo back the message using the
                    // 'from' address in the message.

                    // Persist the regID - no need to register again.
                    storeRegistrationId(context, regid);
                } catch (IOException ex) {
                    msg = "Error :" + ex.getMessage();
                    // If there is an error, don't just keep trying to register.
                    // Require the user to click a button again, or perform
                    // exponential back-off.
                }
                return msg;
            }

            @Override
            protected void onPostExecute(String msg) {
                // TODO ...

                if (Config.DEBUG.SHOW_DEBUG_LOG) {
                    Log.i(Config.getAppTag(), msg);
                }
            }
        }.execute(null, null, null);
    }

    /**
     * @return Application's version code from the {@code PackageManager}.
     */
    private static int getAppVersion(Context context) {
        try {
            PackageInfo packageInfo = context.getPackageManager()
                    .getPackageInfo(context.getPackageName(), 0);
            return packageInfo.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            // should never happen
            throw new RuntimeException("Could not get package name: " + e);
        }
    }

    /**
     * Sends the registration ID to your server over HTTP, so it can use GCM/HTTP or CCS to send
     * messages to your app. Not needed for this demo since the device sends upstream messages
     * to a server that echoes back the message using the 'from' address in the message.
     */
    private void sendRegistrationIdToBackend() {
        // 서버에 registration ID를 전송할 필요가 있을 때, 이곳에서 처리.
        // 굳이 여기서 처리하지 않더라도, 보관해둔 registration ID를 로그인 과정 등에서 전달해도 된다.
    }

Server

https://android.googleapis.com/gcm/send 이 URL로 다음과 같이 푸시 메세지를 날린다.
Content-Type:application/json
Authorization:key=서버API_KEY

{
  "registration_ids" : ["메세지를 전송할 Client의 Registration ID", ...],
  "data" : {
    // key: value 형식으로 자유롭게 구성할 수 있다.
    ...
  },
}


JSON 데이터 부분의 자세한 사양은 다음 링크를 참조.
참조: http://www.techdoctranslator.com/android/guide/google/gcm/gcm



====================================================================================

Alarm 구현


/* MainActivity class */
    public void setAlram(String title, String message, int year, int month, int day, int hour, int min, int sec) {
        Intent alarmIntent = new Intent(this, AlarmReceiver.class);
        alarmIntent.putExtra("title", title);
        alarmIntent.putExtra("message", message);

        if (Config.DEBUG_MODE) {
            Log.i("PROJECT_D", "alarm: " + title + " | "+ message);
        }

        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

        Calendar startTime = Calendar.getInstance();
        startTime.set(Calendar.YEAR, year);
        startTime.set(Calendar.MONTH, month-1);
        startTime.set(Calendar.DAY_OF_MONTH, day);
        startTime.set(Calendar.HOUR_OF_DAY, hour);
        startTime.set(Calendar.MINUTE, min);
        startTime.set(Calendar.SECOND, sec);

        long alarmStartTime = startTime.getTimeInMillis();
        alarmManager.set(AlarmManager.RTC_WAKEUP, alarmStartTime , pendingIntent);
    }


public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String title = intent.getStringExtra("title");
        String message = intent.getStringExtra("message");

        UILib.showNoti(context, title, message, message);
    }
}

public class UILib {
    static final int REQUEST_CODE_MAIN_ACTIVITY = 1000;
    public static int noti_id_start = 0;

    public static void showNoti(Context context, String title, String message, String ticker) {
        Intent intent = new Intent(context, MainActivity.class);

        // Intent の作成
        PendingIntent contentIntent = PendingIntent.getActivity(
                context, REQUEST_CODE_MAIN_ACTIVITY, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        //// LargeIcon の Bitmap を生成
        //Bitmap largeIcon = BitmapFactory.decodeResource(context.getResources(), R.drawable.app_icon);

        // NotificationBuilderを作成
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context.getApplicationContext());
        builder.setContentIntent(contentIntent);
        // ステータスバーに表示されるテキスト
        builder.setTicker(ticker);
        // Notificationを開いたときに表示されるタイトル
        builder.setContentTitle(title);
        // Notificationを開いたときに表示されるサブタイトル
        builder.setContentText(message);

        // アイコン
        builder.setSmallIcon(android.R.drawable.ic_dialog_info);
        // Notificationを開いたときに表示されるアイコン
        //builder.setLargeIcon(largeIcon);

        // 通知するタイミング
        builder.setWhen(System.currentTimeMillis());
        // 通知時の音・バイブ・ライト
        builder.setDefaults(Notification.DEFAULT_SOUND
                | Notification.DEFAULT_VIBRATE
                | Notification.DEFAULT_LIGHTS);
        // タップするとキャンセル(消える)
        builder.setAutoCancel(true);

        // NotificationManagerを取得
        NotificationManager manager = (NotificationManager) context.getSystemService(Service.NOTIFICATION_SERVICE);
        // Notificationを作成して通知


        manager.notify(noti_id_start++, builder.build());

        if (noti_id_start >= Integer.MAX_VALUE) {
            noti_id_start = 0;
        }
    }
}

AndroidManifest.xml


<application ...>
    <service android:name=".GcmIntentService" />
</application>


====================================================================================

Tips

open URL


Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http:// . . ."));
startActivity(browserIntent);

Locale 설정 가져오기


Locale systemLocale = getResources().getConfiguration().locale;
String strDisplayCountry = systemLocale.getDisplayCountry();
String strCountry = systemLocale.getCountry();
String strLanguage = systemLocale.getLanguage();

네트워크 사용 가능 여부


// ネットワーク接続確認
public static boolean networkCheck(Context context){
    ConnectivityManager cm =  (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
    if (cm == null) return false;

    NetworkInfo info = cm.getActiveNetworkInfo();
    if( info != null ){
        return info.isConnected();
    }
    else {
        return false;
    }
}

Mac Address 가져오기

// need permission: "android.permission.ACCESS_WIFI_STATE"
public static String getMacAddr(Context context) {
    WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    WifiInfo wInfo = wifiManager.getConnectionInfo();
    String mac = wInfo.getMacAddress();

    return mac;
}




화면 꺼짐(절전 모드) 방지


// Activity에서
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);


====================================================================================

문제 및 해결

formatted string을 strings.xml 리소스로 뺄 때의 문제

http://androidgamepark.blogspot.jp/2013/05/multiple-substitutions-specified-in-non.html

String.format() 등에서 사용하는 형식 문자열(formatted string)을 그대로 xml 리소스로 빼내면 다음과 같은 에러가 발생.
Multiple substitutions specified in non-positional format; did you mean to add the formatted="false" attribute?


이유는 %문자가 xml에서 사용되는 특수 기호이기 때문. 다음과 같이 처리하자.


<!-- 이것은 에러 -->
<string name="msg_format_date">%4d年%02d月%02d日</string>

<!-- 이렇게 한다 -->
<string name="msg_format_date">%1$4d年%2$02d月%3$02d日 [新着号]</string>

1$, 2$ 등의 의미는 1번째 인자, 2번째 인자, ... 를 의미한다.

ConnectivityManager.getNetworkInfo() 문제

ICS 버전에서 ConnectivityManager의 getNetworkInfo() 호출이 null이 되는 경우가 있다.


ConnectivityManager cm =
        (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);

3G 기능이 없는 기기일 때, 위 코드에서 ni는 null 값이 되버린다.
그러니 반드시 getNetworkInfo()의 반환값이 null인지 먼저 확인하고 진행할 것.

MapView 추가할 때

MapActivity에서 supoer.onCreate()가 먼저 호출된 다음에 MapView가 추가되어야 오류가 발생하지 않는다.

layout.xml 등으로 MapView를 추가할 때도 setContentView() 호출이 supoer.onCreate() 다음에 되도록 주의.

Debug Certificate expired

어느날 프로젝트를 빌드하는데 Debug Certificate expired 오류가 뜬다. 이건 뭥미?
해결: clean project 후 rebuild는 이미 시도해 보았겠지? 그래도 저 오류가 뜬다면 debug.keystore 인증기간이 지난 것이다. (인증기간이 1년짜리라고 한다. 쫌시럽게..) Windows '사용자(Users)' 폴더 밑에 .android 라는 폴더에서 debug.keystore 파일을 지워보고 다시 빌드하면 된다.

네트워크 스레드 문제

Android 3.0 이상에서 android.os.NetworkOnMainThreadException 오류를 만났다면, 이것은 메인 스레드에서 네트워크 작업을 수행했기 때문이다.



http://android-developers.blogspot.kr/2010/12/new-gingerbread-api-strictmode.html
http://www.androidpub.com/1123776 (번역)

앱 우선순위 높이기

시스템 자원 부족으로 프로세스 킬이 진행될 때, 조금이라도 오래 살고 싶으면 Service(비록 아무일도 안하더라도)를 이용해서 앱의 우선순위(중요도)를 높여야 한다.

남용하지는 말자. 리소스를 많이 사용하는 게임이나 네비게이션, 영상 처리 등의 앱에서 사용하는게 좋을 듯.
서비스 작성(예시)


public class NokillService extends Service {

        @Override
        public IBinder onBind(Intent intent) {
                return null;
        }

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
                setForgroundService();
                return Service.START_STICKY;
        }

        void setForgroundService() {
                final Intent it = new Intent(this, MainActivity.class);
                PendingIntent pi = PendingIntent.getActivity(this, 0, it, 0);

                Notification noti;

                if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                        noti = new Notification.Builder(this)
                        .setContentTitle("AppTitle")
                        .setContentText("running...")
                        .setTicker("running...")
                        .setSmallIcon(R.drawable.ic_launcher)
                        .build();
                }
                else {
                        noti = new Notification(R.drawable.ic_launcher, "App Title", System.currentTimeMillis());
                        noti.setLatestEventInfo(this, "App Title", "running...", pi);
                }

                startForeground(1, noti);
        }

}

중요한건, 서비스 내에서 startForeground()를 호출해서 foreground 서비스로 활성화되어야 한다는 것.

foreground 서비스로 등록하기 위해서는 Notification이 필수로 제공되어야 한다.
AndroidManifest.xml 등록
<service android:name="com.qbigstudio.service.NokillService"/>

서비스 호출 및 종료(예시)


public void startNokillService() {
        nokillServ = new Intent(this, NokillService.class);
        startService(nokillServ);
}

public void stopNokillService() {
        if (nokillServ != null)
                stopService(nokillServ);

        nokillServ = null;
}
추천추천 : 1623 추천 목록
번호 제목
1,317
 프로그램 없이 하드디스크 복사 및 백업하기
1,316
 Windows7 업데이트 기록 삭제방법
1,315
 포토샵 psd 파일 연결 레지스트리(registry) 편집
1,314
 윈도 10 최신 업데이트 후 인터넷 속도의 저하가 발생할 때 조치 사항
1,313
 Autotuning level 해제 (윈도우비스타 이상 윈도우)인터넷 속도 빠르게 하는 방법
1,312
 윈도우에서 특정프로세스를 일괄 종료하는법
1,311
 MediaPlayer 클래스 사용법
1,310
 안드로이드에서 audio player 실행하기
1,309
 [Android] MediaPlayer 음악재생기 만들기
1,308
 Eclipse와 Android NDK 연동하기
1,307
 Android Sliding Drawer Functionality 안드로이드 슬라이딩 드로우 예제 sample
1,306
 Android Speech To Text
1,305
 Android WebPageLoader with progress-bar
1,304
 Android Text To Speech(TTS)
1,303
 Android Playing Audio from a web url
1,302
 Button height different from background height in Android image design
1,301
 Android Getting Started with Material Design
1,300
 Using toast inside timertask perfect
1,299
 네트워크 상태 [Android]
1,298
 Webview source [Android]
1,297
 공유 Intent [Android]
1,296
 intent uri 모음 [Android]
1,295
 http requestWebViewClient [Android]
1,294
 캐시 삭제
1,293
 캐시 지우기 [Android]
1,292
 바로풀어(수학 문제 질의응답 SNS) 에 사용된 오픈소스 라이브러리 [Android]
1,291
 Webviw [Android]
1,290
 오픈소스 라이브러리 모음 [Android]
1,289
 Android webview 개발시 알아둬야 할 것들 [Android]
1,288
 webview 동영상 재생 [Android]
1,287
 [Android] Webview 404 에러 처리
1,286
 [Android] webview ssl 문제
1,285
 [Android] Webview url 숨기기
1,284
 [Android] AlarmManager 일정시간 이벤트 실행
1,283
 안드로이드 오픈소스 끝판
목록
인기절정뽕짝파티
트로트재생목록
인기트로트모음
지루박디스코메들리
밤무대애창곡
전자올겐경음악
종합성인가요방
못잊을옛날노래
카바레 음악
트롯디스코팡팡
관광 메들리
트롯카페
가요감상실
추억의옛노래
스페셜가요광장
BillBoard Free
추천가요모음
경음악.전자올겐
스페셜음악여행
WOLRD POPs
K-POP\BillBoard
JP\CN
POP TOP BEST
K.R.노래방

추천가요\인기
F뮤직 인기\발라드
F뮤직 애창\트로트
트로트성인가요
인기가요
프리미엄 POP
경음악\기타
프리미엄 최신가요
프리미엄 성인가요
가요축제\트롯1번지
댄스\메들리\리믹스
카페\명상\경음악\기타
뮤직트로트 부산광역시부산진구 가야동 ㅣ 개인정보취급방침
Copyright (C) musictrot All rights reserved.