http://underclub.tistory.com/367 랩하는 프로그래머 블로그

// VideoView에는 기본 버튼들이 정의되어 있어서 앞에 글에서처럼

// MediaPlayer을 이용해 만들었을 때 버튼을 만들고 정의하는 과정이 필요없다.

// 하지만 VIdeoView로 객체를 만들어 동영상을 재생시키면 무슨 설정을 해도 전체화면으로 나오게 할 수 없다

// 때문에 VIdeoView를 상속받은 클래스를 만들어 사용해야 한다.

// manifest에서 해당 activity에 android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 

// 옵션을 설정해도 해결되지 않아 만들게 되었다.

 

class MyVideoView extends VideoView
{

 public MyVideoView(Context context, AttributeSet attrs) {
  super(context, attrs);
  // TODO Auto-generated constructor stub
 }
 
 
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
 {
       Display dis =((WindowManager)getContext().

                              getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
  

       setMeasuredDimension(dis.getWidth(), dis.getHeight() );
 
 }
}

 

 

주의사항

1.activity에서는 다음과 같이 사용( VideoView가 아님 )

videoView = (MyVideoView)findViewById(R.id.videoView1);

 

2.xml에서는 다음과 같이 선언( VideoView가 아님 )

<package.MyVideoView android:layout_width="fill_parent"android:layout_height="fill_parent" android:id="@+id/aa1" /


http://stackoverflow.com/questions/6520313/how-to-get-rtsp-links-android 에서 참조

package jp.ddo.gallop.android;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;

import jp.ddo.gallop.android.youtube.*;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Xml;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.AdapterView.OnItemClickListener;

public class Main extends Activity implements Runnable {
 private HttpClient mClient;
 private HttpGet mGetMethod;
 private EditText edittext;
 private Button button;
 private ListView listview;
 private Entries<Entry> youtubeEntries;
 private InputStream is;
 private ProgressDialog progressDialog;
 
    /** Called when the activity is first created. */
    @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
       
  edittext = (EditText) findViewById(R.id.EditText01);
  button = (Button) findViewById(R.id.Button01);
  listview = (ListView) findViewById(R.id.ListView01);
       
  // R.id.Button01 OnClickListener
  button.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    // プログレスダイアログ
    progressDialog = new ProgressDialog(Main.this);
    progressDialog.setTitle("YouTube");
    progressDialog.setMessage("検索中・・・");
    progressDialog.setIndeterminate(false);
    progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
    progressDialog.show();

    // Button01 クリックイベント
    Button01_OnClick();  
   }
  });

  // R.id.ListView01 OnItemClickListener
  listview.setOnItemClickListener(new OnItemClickListener() {
   @Override
   public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
    /*
    Entry entryItem = youtubeEntries.get(position);
    */
   }
  });
 }
   
 // Button01 クリックイベント
 private void Button01_OnClick() {
  String keyword = "";
  String encodeKeyword = "";
  keyword = edittext.getText().toString();

  try {
   encodeKeyword = URLEncoder.encode(keyword, "UTF-8");
   
   // YouTube 検索URL
   String uri = "http://gdata.youtube.com/feeds/api/videos?vq=" + encodeKeyword;
   mClient = new DefaultHttpClient();
   mGetMethod = new HttpGet();
   HttpResponse resp = null;
   
   // Request する URL を設定
   mGetMethod.setURI(new URI(uri));
   
   // METHOD GET で Request 送信
   resp = mClient.execute(mGetMethod);
   
   // Request 結果取得
   if (resp.getStatusLine().getStatusCode() == 200) {
    youtubeEntries = null;
    is = resp.getEntity().getContent();
    
    // YouTubeXMLデータをEntryデータに変換する処理に時間が掛かるためスレッド化してプログレスダイアログを表示
    // スレッドの作成と開始
    Thread thread = new Thread(Main.this);
    thread.start();
   }

  } catch (UnsupportedEncodingException e1) {
   e1.printStackTrace();
  } catch (URISyntaxException e) {
   e.printStackTrace();
  } catch (ClientProtocolException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  } catch (IllegalStateException e) {
   e.printStackTrace();
  }
 }
   
 // YouTube XML データパース
    @SuppressWarnings("static-access")
 private Entries<Entry> GetYouTubeEntries(InputStream is) throws XmlPullParserException, IOException {
     // XML パース処理
  ・・・
  // この処理にかなり時間が掛かっている
     return retEntries;
    }

    // スレッド処理開始
 @Override
 public void run() {
  // XML Parse
  try {
   // YouTube XML データパース
   youtubeEntries = GetYouTubeEntries(is);
   handler.sendEmptyMessage(0);
   is.close();
  } catch (XmlPullParserException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
 
 private Handler handler = new Handler() {
  public void handleMessage(Message msg) {
   // YouTube用アダプター作成
   YouTubeAdapter youtubeAdapter = new YouTubeAdapter(Main.this);
   
   // R.id.ListView01 にアダプターをセット
   listview.setAdapter(youtubeAdapter);
   
   // R.id.ListView01 のアダプターに Entry データ追加
   for (Entry ytEntry : youtubeEntries) {
    youtubeAdapter.addData(ytEntry);
   }
   
   // プログレスダイアログ終了
   progressDialog.dismiss();
  }
 };
}


package org.apache.android.media;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.URLUtil;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.Toast;
import android.widget.VideoView;

public class VideoViewDemo extends Activity {
 private static final String TAG = "VideoViewDemo";

 private VideoView mVideoView;
 private EditText mPath;
 private EditText m_currnt; 
 private ImageButton mPlay;
 private ImageButton mPause;
 private ImageButton mReset;
 private ImageButton mStop;
 private String current;
 private int current_p;
   
 //쓰레드와바
 ProgressBar bar;
 Handler handler=new Handler() {
  @Override
  public void handleMessage(android.os.Message msg) {
   //상태바진행
   bar.incrementProgressBy(1);
   //동영상현재포지션구함
   setCurrentPosition();
  }
 };
 boolean isRunning=false; 
 
 @Override
 public void onCreate(Bundle icicle) {
  super.onCreate(icicle);
  setContentView(R.layout.main);
  mVideoView = (VideoView) findViewById(R.id.surface_view);
  bar = (ProgressBar)(ProgressBar) findViewById(R.id.progress);
  
  //경로 넣음
  mPath = (EditText) findViewById(R.id.path);
  mPath.setText("http://daily3gp.com/vids/747.3gp");
  //mPath.setText("http://rtsp2.youtube.com/CjcLENy73wIaLgmVcsAQigQC-xMYDSANFEITVUdlbnQtWW91VHViZURlbW8tMUgGUgZ2aWRlb3MM/0/0/0/video.3gp");
  //rtsp://rtsp2.youtube.com/CjcLENy73wIaLgmVcsAQigQC-xMYDSANFEITVUdlbnQtWW91VHViZURlbW8tMUgGUgZ2aWRlb3MM/0/0/0/video.3gp

  //진행시간표시
  m_currnt = (EditText) findViewById(R.id.current_p);
  //current_p=mVideoView.getCurrentPosition();
  //문자를 넣어야 한다(테스트용)
  m_currnt.setText("11");  

  
  mPlay = (ImageButton) findViewById(R.id.play);
  mPause = (ImageButton) findViewById(R.id.pause);
  mReset = (ImageButton) findViewById(R.id.reset);
  mStop = (ImageButton) findViewById(R.id.stop);

  mPlay.setOnClickListener(new OnClickListener() {
   public void onClick(View view) {
    playVideo();
   }
  });
  
  mPause.setOnClickListener(new OnClickListener() {
   public void onClick(View view) {
    if (mVideoView != null) {
     mVideoView.pause();
     //쓰레드임시중지
     pStop();
    }
   }
  });
  mReset.setOnClickListener(new OnClickListener() {
   public void onClick(View view) {
    if (mVideoView != null) {
     mVideoView.seekTo(0);
    }
   }
  });
  mStop.setOnClickListener(new OnClickListener() {
   public void onClick(View view) {
    if (mVideoView != null) {
     current = null;
     mVideoView.stopPlayback();
     //쓰레드중지
     onStop();
    }
   }
  });
  runOnUiThread(new Runnable(){
   public void run() {
    playVideo();
    
   }
   
  });
  

  super.onStart();
  bar.setProgress(0);  
  Thread background=new Thread(new Runnable() {
   public void run() {
    try {
     while(isRunning)
      {
      Thread.sleep(1000);
      //함수를 초당주기적으로 호출함
      handler.sendMessage(handler.obtainMessage());
         }
    }
    catch (Throwable t) {
     // just end the background thread
    }
   }
  });
  
  isRunning=true;
  //쓰레드시작
  background.start();
 
 }
  
 //쓰레드임시중지 
 public void pStop() {
  
  isRunning=false;
 }  
 //쓰레드다시가동 
 public void sStop() {

  isRunning=true;
 }  
 //쓰레드완전중지 
 public void onStop() {
  super.onStop();
  isRunning=false;
 } 

 protected void setCurrentPosition() {
  //현재의 포지션을 변수에 저장
  current_p=mVideoView.getCurrentPosition();
  current_p=current_p/1000;
  //텍스트박스에 넣으려면 형변환
  m_currnt.setText(Integer.toString(current_p));
 }

 //동영상동작
 private void playVideo() {
  try {
   final String path = mPath.getText().toString();
   Log.v(TAG, "path: " + path);
   if (path == null || path.length() == 0) {
    Toast.makeText(VideoViewDemo.this, "주소가명확하지않습니다",
      Toast.LENGTH_LONG).show();

   } else {
    // If the path has not changed, just start the media player
    if (path.equals(current) && mVideoView != null) {
     mVideoView.start();
     mVideoView.requestFocus();

     return;
    }
    //current = path;
    //mVideoView.setVideoPath(getDataSource(path));
    mVideoView.setVideoPath(path);
    mVideoView.start();
    mVideoView.requestFocus();

   }
   
  } catch (Exception e) {
   Log.e(TAG, "error: " + e.getMessage(), e);
   if (mVideoView != null) {
    mVideoView.stopPlayback();
   }
  }
 
 }


 
}

출처 : http://croute.me/392

예전에 한번 버튼의 클릭이벤트에 대해서 고찰한적이 있었습니다.
onClick()의 구현이 더 좋을까, OnClickListener 객체를 각각 생성해서 구현하는 것이 좋을까에 대한 내용이었습니다.
어쨋든 전 결론을 onClick()의 구현(implements)으로 내렸었죠.

( 버튼 클릭 이벤트 처리에 관한 고찰 : http://croute.me/326 )

이번에는 저번과는 조금 다른 고찰입니다.

수많은 버튼을 사용해야 하는 경우,
하나씩 아이디를 onClick()에서 siwtch 문 안에 case로 정의내려 처리하기는 너무 곤욕이죠. 휴...
그래서 이런 방법을 생각해 보았습니다.

향상된 for문과 배열을 이용하는 방법.

접기

주의 깊게 향상된 반복문(Enhanced For Loop)을 사용하라

향상된 반복문(때로 "for-each"로 알려진 반복문)은 Iterable 인터페이스를 구현한 컬렉션들을 위해 사용될 수 있습니다. 이러한 객체들로, 반복자는 hasNext() 와 next()을 호출하는 인터페이스를 만들기 위해 할당됩니다. ArrayList의 경우 여러분이 직접 탐색하는 것이 좋을 수 있습니다만, 다른 컬렉션들에서는 향상된 반복문 구문이 명시적인 반복자의 사용과 동등한 성능을 보여줍니다.

그럼에도, 다음 코드로 향상된 반복문의 만족스러운 사용법을 볼 수 있습니다:

public class Foo {
    int mSplat;
    static Foo mArray[] = new Foo[27];

    public static void zero() {
        int sum = 0;
        for (int i = 0; i < mArray.length; i++) {
            sum += mArray[i].mSplat;
        }
    }

    public static void one() {
        int sum = 0;
        Foo[] localArray = mArray;
        int len = localArray.length;

        for (int i = 0; i < len; i++) {
            sum += localArray[i].mSplat;
        }
    }

    public static void two() {
        int sum = 0;
        for (Foo a: mArray) {
            sum += a.mSplat;
        }
    }
}

zero() 는 반복되는 매 주기마다 정적 필드를 두 번 부르고 배열의 길이를 한번 얻습니다.

one() 은 참조를 피하기 위해 지역 변수로 모든 것을 끌어냈습니다.

two() 는 자바 언어의 1.5버전에서 소개된 향상된 반복문 구문을 사용합니다. 컴파일러에 의해 생성된 코드는 배열 참조와 배열의 길이를 지역 변수로 복사해주어, 배열의 모든 원소를 탐색하는데 좋은 선택이 될 수 있습니다. 주 루프 내에 추가적인 지역 읽기/저장이 만들어지고(명백하게 "a"에 저장), one()보다 쪼금 느리고 4 바이트 길어지게 하긴 합니다.

좀 더 명확하게 모든 것을 종합하자면: 향상된 반복문 구문은 배열과 잘 동작하지만, 추가적인 객체 생성이 있게 되는 Iterable 객체와 함께 사용할 때엔 조심해야 합니다.

접기



코드는 아래와 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package me.croute.manybutton;
  
import java.util.ArrayList;
  
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
  
  
/**
 * 많은 버튼이 있을 때 클릭이벤트를 처리하기 위한 예제 코드 * 
 
 * @author croute
 * @since 2011.04.19
 */
public class ManyButtonExampleActivity extends Activity implements OnClickListener
{
    // 여러개의 버튼을 배열로 처리하기 위해 버튼에 대해 배열 선언을 함
    private Button[] mButton = new Button[6];
      
    // 각각 다르게 출력할 스트링을 넣어둘 리스트
    private ArrayList<String> mDataList; 
  
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
  
        mDataList = new ArrayList<String>();
          
        mButton[0] = (Button) findViewById(R.id.main_b_00);
        mButton[1] = (Button) findViewById(R.id.main_b_01);
        mButton[2] = (Button) findViewById(R.id.main_b_02);
        mButton[3] = (Button) findViewById(R.id.main_b_03);
        mButton[4] = (Button) findViewById(R.id.main_b_04);
        mButton[5] = (Button) findViewById(R.id.main_b_05);
  
        // 버튼들에 대한 클릭리스너 등록 및 각 버튼이 클릭되었을 때 출력될 메시지 생성(리스트)
        for(int i = 0 ; i < 6 ; i++)
        {
            // 버튼의 포지션(배열에서의 index)를 태그로 저장
            mButton[i].setTag(i);
              
            // 클릭 리스너 등록
            mButton[i].setOnClickListener(this);
              
            // 출력할 데이터 생성
            mDataList.add("하이" + i + "입니다");
        }
    }
  
    /* (non-Javadoc)
     * @see android.view.View.OnClickListener#onClick(android.view.View)
     */
    @Override
    public void onClick(View v)
    {
        // 클릭된 뷰를 버튼으로 받아옴
        Button newButton = (Button) v;
  
        // 향상된 for문을 사용, 클릭된 버튼을 찾아냄
        for(Button tempButton : mButton)
        {
            // 클릭된 버튼을 찾았으면 
            if(tempButton == newButton)
            {
                // 위에서 저장한 버튼의 포지션을 태그로 가져옴
                int position = (Integer)v.getTag();
                  
                // 태그로 가져온 포지션을 이용해 리스트에서 출력할 데이터를 꺼내서 토스트 메시지 출력
                Toast.makeText(this, mDataList.get(position), Toast.LENGTH_SHORT).show();
            }
        }
    }
}



각각의 버튼을 눌렀을 때 만들어 두었던 데이터대로 잘 출력이 되는군요.









아래는 위 예제에 대한 프로젝트 압출파일 입니다.



출처 : http://www.londatiga.net/it/how-to-create-quickaction-dialog-in-android/

I have updated the quickaction implementation code so it can be used more efficient and the dialog will be automatically dismissed after pressing the action item. All the source codes now available via github so you can track the changes.

Official Twitter application for Android  has introduced new Android UI features and behavior patterns such as Dashboard, Search Bar, QuickAction and Action Bar. One of the interesting pattern is QuickActions that displays contextual actions in a list view. This pattern actually already exists in QuickContact dialog/bar in default Contact application (since Android 2.0).

QuickContact QuickContact

The QuickActions dialog is not included in standard Android SDK, so we have to create it manually. At first, i had no idea on how to create it so i decided to download and read the Contact app source code from  Android git. I found that the QuickContact dialog  uses private API call (com.android.internal.policy.PolicyManager) that does not exists in standard SDK. After posting question about it on google groups and stack overflow, i got the solution for it from Qberticus (thanx Qberticus!).

Qberticus’s QuickActions uses simple/plain layout so i have to create a custom layout so it will look like QuickContact in Contact app or QuickActions in Twitter app. Based on QuickContact source code, i made a slight modification on Qberticus’s BetterPopupWindow class and extended it to implement custom layout. I also made it customizeable, so the icon and text in action list can be customized.

Here are the screenshoots of QuickActions demo:

QuickContact / Twitter-like QuickActions

Code snippet
Create action items

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Add action item
ActionItem addAction = new ActionItem();
  
addAction.setTitle("Add");
addAction.setIcon(getResources().getDrawable(R.drawable.ic_add));
  
//Accept action item
ActionItem accAction = new ActionItem();
  
accAction.setTitle("Accept");
accAction.setIcon(getResources().getDrawable(R.drawable.ic_accept));
  
//Upload action item
ActionItem upAction = new ActionItem();
  
upAction.setTitle("Upload");
upAction.setIcon(getResources().getDrawable(R.drawable.ic_up));

Line 02: Create new action item
Line 04: Set action title
Line 05: Set action icon

Create quickaction instance and setup listener

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
final QuickAction mQuickAction  = new QuickAction(this);
  
mQuickAction.addActionItem(addAction);
mQuickAction.addActionItem(accAction);
mQuickAction.addActionItem(upAction);
  
//setup the action item click listener
mQuickAction.setOnActionItemClickListener(new QuickAction.OnActionItemClickListener() {
    @Override
        public void onItemClick(int pos) {
        if (pos == 0) { //Add item selected
           Toast.makeText(Example1Activity.this, "Add item selected", Toast.LENGTH_SHORT).show();
        } else if (pos == 1) { //Accept item selected
           Toast.makeText(Example1Activity.this, "Accept item selected", Toast.LENGTH_SHORT).show();
        } else if (pos == 2) { //Upload item selected
           Toast.makeText(Example1Activity.this, "Upload items selected", Toast.LENGTH_SHORT).show();
        }
    }
});

Line 1: Create quickaction instance
Line 3-5: Add the action items into quikaction
Line 8: Setup listener for action item clicked, the pos argument on onItemClick method shows which action item is clicked.

Show quickAction dialog

1
2
3
4
5
6
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
    mQuickAction.show(v);
}
});

Line 04: Show quickaction dialog, the v argument used as the anchor where the quickaction displayed.

Gallery3D-like QuickActions

Implementation on My Application

BlitzDroid

Minapolitan (Prototype)

Related post:

link from : http://www.siegmann.nl/epublib/android

Android

Epublib-core runs on Android.
Reading, writing and manipulating epub files is fully supported.
Requirements

Getting started

  1. Download epublib-core-latest.jar from https://github.com/downloads/psiegman/epublib/epublib-core-latest.jar
  2. Download slf4j-android
  3. Add both to your android project


Example code

This Logs info of 'assets/books/testbook.epub'.
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
  
import nl.siegmann.epublib.domain.Book;
import nl.siegmann.epublib.domain.TOCReference;
import nl.siegmann.epublib.epub.EpubReader;
import android.app.Activity;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
  
/**
 * Log the info of 'assets/books/testbook.epub'.
 *
 * @author paul.siegmann
 *
 */
public class LogTestBookInfo extends Activity {
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    AssetManager assetManager = getAssets();
    try {
      // find InputStream for book
      InputStream epubInputStream = assetManager
          .open("books/testbook.epub");
  
      // Load Book from inputStream
      Book book = (new EpubReader()).readEpub(epubInputStream);
  
      // Log the book's authors
      Log.i("epublib", "author(s): " + book.getMetadata().getAuthors());
  
      // Log the book's title
      Log.i("epublib", "title: " + book.getTitle());
  
      // Log the book's coverimage property
      Bitmap coverImage = BitmapFactory.decodeStream(book.getCoverImage()
          .getInputStream());
      Log.i("epublib", "Coverimage is " + coverImage.getWidth() + " by "
          + coverImage.getHeight() + " pixels");
  
      // Log the tale of contents
      logTableOfContents(book.getTableOfContents().getTocReferences(), 0);
    } catch (IOException e) {
      Log.e("epublib", e.getMessage());
    }
  }
  
  /**
   * Recursively Log the Table of Contents
   *
   * @param tocReferences
   * @param depth
   */
  private void logTableOfContents(List<TOCReference> tocReferences, int depth) {
    if (tocReferences == null) {
      return;
    }
    for (TOCReference tocReference : tocReferences) {
      StringBuilder tocString = new StringBuilder();
      for (int i = 0; i < depth; i++) {
        tocString.append("\t");
      }
      tocString.append(tocReference.getTitle());
      Log.i("epublib", tocString.toString());
  
      logTableOfContents(tocReference.getChildren(), depth + 1);
    }
  }
}

출처 : http://sankarganesh-info-exchange.blogspot.com/2011/04/dynamically-loading-datas-in-listview.html

Dynamically Loading Data's (Adding Footer to ListView ) in ListView in Android


Add a footer to List View and when the user clicks that Footer, you can show parse the next set of data and show it in the list.



Step1: Create a Button

<Button android:id="@+id/footer" android:gravity="center"
android:layout_gravity="center"
android:text="My Footer"
android:layout_width="wrap_content"
android:layout_height="0dp" android:layout_weight="1"/>

Step2: Make it as Footer to the List View

ListView myList;
View footerView;
ViewGroup footerViewOriginal = (ViewGroup) findViewById(R.id.footer);
footerView = inflater2.inflate(R.layout.footer,footerViewOriginal);
footerView.findViewById(R.id.footer);
myList.addFooterView(footerView, null, true);

Step3: Create on ClickListener and write the action what you want to perform

footerView.findViewById(R.id.footer).setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return false;

}

Monday, August 3, 2009

HTTP connection reuse in Android

Alright, time for something new and hopefully useful, re-using HTTP connections in your application.

I've yet to write an Android application that doesn't make any HTTP requests, and they tend to do it frequently. Since all of my applications are also heavily concurrent, passing around a default HttpClient instance will give you thread contention issues and possibly bad dreams later that night. Establishing a new TCP connection to the same server for each request is wasteful, so I'd like to be able to re-use those connections, via the same HttpClient, and do so in a thread safe way.

This is easily accomplished with a singleton/factory thingy like so:


public class HttpClientFactory {

private static DefaultHttpClient client;

public synchronized static DefaultHttpClient getThreadSafeClient() {

if (client != null)
return client;

client = new DefaultHttpClient();

ClientConnectionManager mgr = client.getConnectionManager();

HttpParams params = client.getParams();
client = new DefaultHttpClient(
new ThreadSafeClientConnManager(params,
mgr.getSchemeRegistry()), params);

return client;
}
}

Now whenever you need an HttpClient instance in your app, you can just do this:

HttpClient client = HttpClientFactory.getThreadSafeClient();

Like most things in HttpClient 4.x, it's very easy to do, the hardest part is just figuring out exactly how to do it. A buddy @google told me that 4.x just performs so better than 3.x that was the reason for the behind switch (early versions of Android used the 3.x releases). Until next weekend..

출처 : http://bluejames77.blog.me/80124862451

예전에 HttpClient을 쓴 법을 있는데.. 최신에 이것을 다시 쓸일이 있어 정리해봅니다. ^-^;

 

제가 짠 메소드인데 이것만 보면 아마 감이 딱 오시지 않을까 생각됩니다.

 

private static String requestConvert ( String szFilePath, int nPageCount, String szThumbnailSize)
 {

  // 아래처럼 해서 넘길 값이 있다면 키와 밸류 형식으로 파라메타를 넘기게 됩니다
  List<NameValuePair> qparams = new ArrayList<NameValuePair>();
  qparams.add(new BasicNameValuePair("FilePath", szFilePath));
  qparams.add(new BasicNameValuePair("PageCount", String.valueOf(nPageCount)));
  qparams.add(new BasicNameValuePair("ThumbnailSize", szThumbnailSize));
  
  String szResult = null;
  URI uri = null;
  
  try
  {

 // url을 아래처럼 정의할 수 잇습니다.

 // 들어가는 파라메터는 순서대로 -> String scheme, String host, int port, String path, String query, String fragment
   uri = URIUtils.createURI("http", "localhost", 80, "/daview/servlet/viewer", 
  // 파라메터 UTF-8로 넘길수도 있습니다.

   URLEncodedUtils.format(qparams, "UTF-8"), null);

   // Get으로 보낼때는 HttpGet을
   HttpGet httpget = new HttpGet(uri);

   // Post으로 보낼때는 HttpPost를 이용하시면 됩니다.

   // HttpPost httpPost = new HttpPost(uri);
   
   HttpClient client = new DefaultHttpClient();
   HttpResponse response = null;

   // post을 이용하실때엔 여기에 httpPost을 넣으시면 됩니다
   response = client.execute( httpget);
   

   // 성공여부는 200입니다 이것은 response.getStatusLine().getStatusCode() 메소드로 호가인 가능합니다.
   //System.out.println( szFilePath + " 성공여부 : " + response.getStatusLine().getStatusCode());

   HttpEntity entity = response.getEntity();
   BufferedReader br = null;
   if (entity != null) {
    

    szResult = EntityUtils.toString(entity);    

   // EntityUtils.toString은 아래 주석과 같은 역할을 해준답니다.
//    br = new BufferedReader( new InputStreamReader( entity.getContent()));
//    String szLine = null;
//    while ( (szLine = br.readLine()) != null )
//    {
//     szResult = szLine;
//    }
    
   }
   
//   System.out.println( "성공여부 : " + szResult);
  } catch (Exception e) {
   e.printStackTrace();
  }
  
  return szResult;
 }

 

참고로 Get과 Post에 대해서 말씀드리면 Get은 한계가 있습니다.

예전엔 256byte였는데 요즘은 2048byte까지 올라온것 같습니다. Post는 한계가 없습니다.

(http://www.phpschool.com/gnuboard4/bbs/board.php?bo_table=qna_function&wr_id=131930)

 

그래서 만약 파라메터로 넘길게 많다면 당연히 Get 보다는 Post를 써야 합니다. 그럼 왜 다 Post를 쓰지 Get을 써야 하는걸까요?

그건 Get 방식이 Post보단 빠르기 때문이랍니다.

 

HttpClient을 사용하실려면 여기서 다운 받아서 사용하시면 됩니다.

http://hc.apache.org/httpcomponents-client-ga/


private String writeXml(List<Message> messages){ 
    XmlSerializer serializer = Xml.newSerializer(); 
    StringWriter writer = new StringWriter(); 
    try { 
        serializer.setOutput(writer); 
        serializer.startDocument("UTF-8", true); 
        serializer.startTag("", "messages"); 
        serializer.attribute("", "number", String.valueOf(messages.size())); 
        for (Message msg: messages){ 
            serializer.startTag("", "message"); 
            serializer.attribute("", "date", msg.getDate()); 
            serializer.startTag("", "title"); 
            serializer.text(msg.getTitle()); 
            serializer.endTag("", "title"); 
            serializer.startTag("", "url"); 
            serializer.text(msg.getLink().toExternalForm()); 
            serializer.endTag("", "url"); 
            serializer.startTag("", "body"); 
            serializer.text(msg.getDescription()); 
            serializer.endTag("", "body"); 
            serializer.endTag("", "message"); 
        } 
        serializer.endTag("", "messages"); 
        serializer.endDocument(); 
        return writer.toString(); 
    } catch (Exception e) { 
        throw new RuntimeException(e); 
    }  

출처 : http://bench87.tistory.com/38

외국사이트에서 퍼왔습니다.

 
스샷에 보이듯이 말풍선만 뛰울수 있습니다...

소스는 자꾸 안된다는 분이 많아서 제가 되도록 살짝 고쳤습니다..

 

Android MapView Balloons

This project provides an easy way to annotate map overlay items with a simple information balloon when using the Android Maps external library (com.google.android.maps). It consists of BalloonOverlayView, a view representing the balloon that is displayed over your MapView andBalloonItemizedOverlay, an abstract extension of ItemizedOverlay.

The presentation of the balloons was mostly reverse engineered from Google's Places Directory application.

Usage

Create a subclass of BalloonItemizedOverlay in the same way you would do for the base ItemizedOverlay class. Rather than overriding onTap()(which is already implemented and final in the subclass to invoke the balloon view display for each item tap), you override onBalloonTap() to handle a screen tap event on the balloon itself.

The data displayed in each balloon is mapped to the title and snippet arguments you provide to the constructor of each OverlayItem.

The repository contains a working sample application project which fully demonstrates its usage.

Implementation

As of version 1.1, android-mapviewballoons is an Android Library project. Refer to 'Referencing a library project from an application' in this document for instructions on how to include it in your own Android project. Ensure you have the latest Android SDK, tools and Eclipse plugin installed.

Whats Missing?

  • Custom balloon layouts and data mappings
  • Long press support
  • Trackball support (not tested)
  • Focus events (not tested)

The code in this project is licensed under the Apache Software License 2.0.


Copyright (c) 2010 readyState Software Ltd.

프로젝트파일 구조입니다..참고해서 만들어주세요..ㅎㅎ



myMpa.java

01 /***
02  * Copyright (c) 2010 readyState Software Ltd
03  
04  * Licensed under the Apache License, Version 2.0 (the "License"); you may
05  * not use this file except in compliance with the License. You may obtain
06  * a copy of the License at
08  * Unless required by applicable law or agreed to in writing, software
09  * distributed under the License is distributed on an "AS IS" BASIS,
10  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  * See the License for the specific language governing permissions and
12  * limitations under the License.
13  
14  */
15   
16 package mapviewballoons.example;
17   
18 import java.util.List;
19   
20 import android.graphics.drawable.Drawable;
21 import android.os.Bundle;
22   
23 import com.google.android.maps.GeoPoint;
24 import com.google.android.maps.MapActivity;
25 import com.google.android.maps.MapController;
26 import com.google.android.maps.MapView;
27 import com.google.android.maps.Overlay;
28 import com.google.android.maps.OverlayItem;
29   
30 public class MyMap extends MapActivity {
31   
32     MapView mapView;
33     List<OVERLAY> mapOverlays;
34     Drawable drawable;
35     Drawable drawable2;
36     MyItemizedOverlay itemizedOverlay;
37     MyItemizedOverlay itemizedOverlay2;
38       
39     @Override
40     public void onCreate(Bundle savedInstanceState) {
41           
42         super.onCreate(savedInstanceState);
43         setContentView(R.layout.main);
44           
45         mapView = (MapView) findViewById(R.id.mapview);
46         mapView.setBuiltInZoomControls(true);
47           
48         mapOverlays = mapView.getOverlays();
49           
50         // first overlay
51         drawable = getResources().getDrawable(R.drawable.marker);
52         itemizedOverlay = new MyItemizedOverlay(drawable, mapView);
53           
54         GeoPoint point = new GeoPoint((int)(51.5174723*1E6),(int)(-0.0899537*1E6));
55         OverlayItem overlayItem = new OverlayItem(point, "Tomorrow Never Dies (1997)"
56                 "(M gives Bond his mission in Daimler car)");
57         itemizedOverlay.addOverlay(overlayItem);
58           
59         GeoPoint point2 = new GeoPoint((int)(51.515259*1E6),(int)(-0.086623*1E6));
60         OverlayItem overlayItem2 = new OverlayItem(point2, "GoldenEye (1995)"
61                 "(Interiors Russian defence ministry council chambers in St Petersburg)");      
62         itemizedOverlay.addOverlay(overlayItem2);
63           
64         mapOverlays.add(itemizedOverlay);
65           
66         // second overlay
67         drawable2 = getResources().getDrawable(R.drawable.marker2);
68         itemizedOverlay2 = new MyItemizedOverlay(drawable2, mapView);
69           
70         GeoPoint point3 = new GeoPoint((int)(51.513329*1E6),(int)(-0.08896*1E6));
71         OverlayItem overlayItem3 = new OverlayItem(point3, "Sliding Doors (1998)"
72                 "(interiors)");
73         itemizedOverlay2.addOverlay(overlayItem3);
74           
75         GeoPoint point4 = new GeoPoint((int)(51.51738*1E6),(int)(-0.08186*1E6));
76         OverlayItem overlayItem4 = new OverlayItem(point4, "Mission: Impossible (1996)"
77                 "(Ethan & Jim cafe meeting)");      
78         itemizedOverlay2.addOverlay(overlayItem4);
79           
80         mapOverlays.add(itemizedOverlay2);
81           
82         final MapController mc = mapView.getController();
83         mc.animateTo(point2);
84         mc.setZoom(16);
85           
86     }
87       
88     @Override
89     protected boolean isRouteDisplayed() {
90         return false;
91     }
92   
93 }
94 </OVERLAY>
MyItemizedOverlay.java




MyItemizedOverlay.java
01 /***
02  * Copyright (c) 2010 readyState Software Ltd
03  
04  * Licensed under the Apache License, Version 2.0 (the "License"); you may
05  * not use this file except in compliance with the License. You may obtain
06  * a copy of the License at
08  * Unless required by applicable law or agreed to in writing, software
09  * distributed under the License is distributed on an "AS IS" BASIS,
10  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  * See the License for the specific language governing permissions and
12  * limitations under the License.
13  
14  */
15   
16 package mapviewballoons.example;
17   
18 import java.util.ArrayList;
19   
20 import android.content.Context;
21 import android.graphics.drawable.Drawable;
22 import android.widget.Toast;
23   
24 import com.google.android.maps.MapView;
25 import com.google.android.maps.OverlayItem;
26   
27   
28 public class MyItemizedOverlay extends BalloonItemizedOverlay<OVERLAYITEM> {
29   
30     private ArrayList<OVERLAYITEM> m_overlays = new ArrayList<OVERLAYITEM>();
31     private Context c;
32       
33     public MyItemizedOverlay(Drawable defaultMarker, MapView mapView) {
34         super(boundCenter(defaultMarker), mapView);
35         c = mapView.getContext();
36     }
37   
38     public void addOverlay(OverlayItem overlay) {
39         m_overlays.add(overlay);
40         populate();
41     }
42   
43     @Override
44     protected OverlayItem createItem(int i) {
45         return m_overlays.get(i);
46     }
47   
48     @Override
49     public int size() {
50         return m_overlays.size();
51     }
52   
53     @Override
54     protected boolean onBalloonTap(int index) {
55         Toast.makeText(c, "onBalloonTap for overlay index " + index,
56                 Toast.LENGTH_LONG).show();
57         return true;
58     }
59       
60 }
61 </OVERLAYITEM></OVERLAYITEM></OVERLAYITEM>

BalloonOverlayView.java

001 /***
002  * Copyright (c) 2010 readyState Software Ltd
003  
004  * Licensed under the Apache License, Version 2.0 (the "License"); you may
005  * not use this file except in compliance with the License. You may obtain
006  * a copy of the License at
008  * Unless required by applicable law or agreed to in writing, software
009  * distributed under the License is distributed on an "AS IS" BASIS,
010  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011  * See the License for the specific language governing permissions and
012  * limitations under the License.
013  
014  */
015   
016 package mapviewballoons.example;
017   
018 import android.content.Context;
019 import android.view.Gravity;
020 import android.view.LayoutInflater;
021 import android.view.View;
022 import android.widget.FrameLayout;
023 import android.widget.ImageView;
024 import android.widget.LinearLayout;
025 import android.widget.TextView;
026   
027 import com.google.android.maps.OverlayItem;
028   
029 /**
030  * A view representing a MapView marker information balloon.
031  * <P>
032  * This class has a number of Android resource dependencies:
033  * </P>
034 <UL>
035  * <LI>drawable/balloon_overlay_bg_selector.xml</LI>
036  * <LI>drawable/balloon_overlay_close.png</LI>
037  * <LI>drawable/balloon_overlay_focused.9.png</LI>
038  * <LI>drawable/balloon_overlay_unfocused.9.png</LI>
039  * <LI>layout/balloon_map_overlay.xml</LI>
040  * </UL>
041  * <P></P>
042  
043  * @author Jeff Gilfelt
044  *
045  */
046 public class BalloonOverlayView extends FrameLayout {
047   
048     private LinearLayout layout;
049     private TextView title;
050     private TextView snippet;
051   
052     /**
053      * Create a new BalloonOverlayView.
054      
055      * @param context - The activity context.
056      * @param balloonBottomOffset - The bottom padding (in pixels) to be applied
057      * when rendering this view.
058      */
059     public BalloonOverlayView(Context context, int balloonBottomOffset) {
060   
061         super(context);
062   
063         setPadding(10, 0, 10, balloonBottomOffset);
064         layout = new LinearLayout(context);
065         layout.setVisibility(VISIBLE);
066   
067         LayoutInflater inflater = (LayoutInflater) context
068                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
069         View v = inflater.inflate(R.layout.balloon_overlay, layout);
070         title = (TextView) v.findViewById(R.id.balloon_item_title);
071         snippet = (TextView) v.findViewById(R.id.balloon_item_snippet);
072   
073         ImageView close = (ImageView) v.findViewById(R.id.close_img_button);
074         close.setOnClickListener(new OnClickListener() {
075             public void onClick(View v) {
076                 layout.setVisibility(GONE);
077             }
078         });
079   
080         FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
081                 LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
082         params.gravity = Gravity.NO_GRAVITY;
083   
084         addView(layout, params);
085   
086     }
087       
088     /**
089      * Sets the view data from a given overlay item.
090      
091      * @param item - The overlay item containing the relevant view data 
092      * (title and snippet). 
093      */
094     public void setData(OverlayItem item) {
095           
096         layout.setVisibility(VISIBLE);
097         if (item.getTitle() != null) {
098             title.setVisibility(VISIBLE);
099             title.setText(item.getTitle());
100         } else {
101             title.setVisibility(GONE);
102         }
103         if (item.getSnippet() != null) {
104             snippet.setVisibility(VISIBLE);
105             snippet.setText(item.getSnippet());
106         } else {
107             snippet.setVisibility(GONE);
108         }
109           
110     }
111   
112 }
BalloonItemizedOverlay.java

001 /***
002  * Copyright (c) 2010 readyState Software Ltd
003  
004  * Licensed under the Apache License, Version 2.0 (the "License"); you may
005  * not use this file except in compliance with the License. You may obtain
006  * a copy of the License at
008  * Unless required by applicable law or agreed to in writing, software
009  * distributed under the License is distributed on an "AS IS" BASIS,
010  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011  * See the License for the specific language governing permissions and
012  * limitations under the License.
013  
014  */
015   
016 package mapviewballoons.example;
017   
018   
019   
020 import java.lang.reflect.Method; 
021 import java.util.List;
022   
023 import android.graphics.drawable.Drawable;
024 import android.util.Log;
025 import android.view.MotionEvent;
026 import android.view.View;
027 import android.view.View.OnTouchListener;
028 import android.view.ViewGroup.LayoutParams;
029   
030 import com.google.android.maps.GeoPoint;
031 import com.google.android.maps.ItemizedOverlay;
032 import com.google.android.maps.MapController;
033 import com.google.android.maps.MapView;
034 import com.google.android.maps.Overlay;
035 import com.google.android.maps.OverlayItem;
036   
037 /**
038  * An abstract extension of ItemizedOverlay for displaying an information balloon
039  * upon screen-tap of each marker overlay.
040  
041  * @author Jeff Gilfelt
042  */
043 public abstract class BalloonItemizedOverlay<ITEM> extends ItemizedOverlay<OVERLAYITEM> {
044   
045     private MapView mapView;
046     private BalloonOverlayView balloonView;
047     private View clickRegion;
048     private int viewOffset;
049     final MapController mc;
050       
051       
052     public BalloonItemizedOverlay(Drawable defaultMarker, MapView mapView) {
053         super(defaultMarker);
054         this.mapView = mapView;
055         viewOffset = 0;
056         mc = mapView.getController();
057     }
058       
059       
060     public void setBalloonBottomOffset(int pixels) {
061         viewOffset = pixels;
062     }
063       
064   
065     protected boolean onBalloonTap(int index) {
066         return false;
067     }
068   
069   
070     @Override
071     protected final boolean onTap(int index) {
072           
073         boolean isRecycled;
074         final int thisIndex;
075         GeoPoint point;
076           
077         thisIndex = index;
078         point = createItem(index).getPoint();
079           
080         if (balloonView == null) {
081             balloonView = new BalloonOverlayView(mapView.getContext(), viewOffset);
082             clickRegion = (View) balloonView.findViewById(R.id.balloon_inner_layout);
083             isRecycled = false;
084         } else {
085             isRecycled = true;
086         }
087       
088         balloonView.setVisibility(View.GONE);
089           
090         List<OVERLAY> mapOverlays = mapView.getOverlays();
091         if (mapOverlays.size() > 1) {
092             hideOtherBalloons(mapOverlays);
093         }
094           
095         balloonView.setData(createItem(index));
096           
097         MapView.LayoutParams params = new MapView.LayoutParams(
098                 LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, point,
099                 MapView.LayoutParams.BOTTOM_CENTER);
100         params.mode = MapView.LayoutParams.MODE_MAP;
101           
102         setBalloonTouchListener(thisIndex);
103           
104         balloonView.setVisibility(View.VISIBLE);
105   
106         if (isRecycled) {
107             balloonView.setLayoutParams(params);
108         } else {
109             mapView.addView(balloonView, params);
110         }
111           
112         mc.animateTo(point);
113           
114         return true;
115     }
116       
117     /**
118      * Sets the visibility of this overlay's balloon view to GONE. 
119      */
120     private void hideBalloon() {
121         if (balloonView != null) {
122             balloonView.setVisibility(View.GONE);
123         }
124     }
125       
126     /**
127      * Hides the balloon view for any other BalloonItemizedOverlay instances
128      * that might be present on the MapView.
129      
130      * @param overlays - list of overlays (including this) on the MapView.
131      */
132     private void hideOtherBalloons(List<OVERLAY> overlays) {
133           
134         for (Overlay overlay : overlays) {
135             if (overlay instanceof BalloonItemizedOverlay<!--?--> && overlay != this) {
136                 ((BalloonItemizedOverlay<!--?-->) overlay).hideBalloon();
137             }
138         }
139           
140     }
141       
142     /**
143      * Sets the onTouchListener for the balloon being displayed, calling the
144      * overridden onBalloonTap if implemented.
145      
146      * @param thisIndex - The index of the item whose balloon is tapped.
147      */
148     private void setBalloonTouchListener(final int thisIndex) {
149           
150         try {
151             @SuppressWarnings("unused")
152             Method m = this.getClass().getDeclaredMethod("onBalloonTap", int.class);
153               
154             clickRegion.setOnTouchListener(new OnTouchListener() {
155                 public boolean onTouch(View v, MotionEvent event) {
156                       
157                     View l =  ((View) v.getParent()).findViewById(R.id.balloon_main_layout);
158                     Drawable d = l.getBackground();
159                       
160                     if (event.getAction() == MotionEvent.ACTION_DOWN) {
161                         int[] states = {android.R.attr.state_pressed};
162                         if (d.setState(states)) {
163                             d.invalidateSelf();
164                         }
165                         return true;
166                     } else if (event.getAction() == MotionEvent.ACTION_UP) {
167                         int newStates[] = {};
168                         if (d.setState(newStates)) {
169                             d.invalidateSelf();
170                         }
171                         // call overridden method
172                         onBalloonTap(thisIndex);
173                         return true;
174                     } else {
175                         return false;
176                     }
177                       
178                 }
179             });
180               
181         } catch (SecurityException e) {
182             Log.e("BalloonItemizedOverlay", "setBalloonTouchListener reflection SecurityException");
183             return;
184         } catch (NoSuchMethodException e) {
185             // method not overridden - do nothing
186             return;
187         }
188   
189     }
190       
191 }
192 </OVERLAY></OVERLAY></OVERLAYITEM></ITEM>




balloon_overlay.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content"
    android:orientation="horizontal" 
    android:paddingBottom="35dip"
    android:paddingLeft="10dip" 
    android:minWidth="200dip" 
    android:id="@+id/balloon_main_layout"
    android:background="@drawable/balloon_overlay_bg_selector" 
    android:paddingTop="0dip"
    android:paddingRight="0dip">
   <LinearLayout 

       android:layout_width="wrap_content" 

       android:layout_height="wrap_content"

       android:orientation="vertical" 

       android:layout_weight="1"

       android:paddingTop="10dip" 

       android:id="@+id/balloon_inner_layout">

       <TextView android:layout_height="wrap_content"

           android:layout_width="fill_parent" 

           android:id="@+id/balloon_item_title"

           android:text="balloon_item_title" 

           android:textSize="16dip"

           android:textColor="#FF000000"></TextView>

       <TextView android:layout_height="wrap_content"

           android:layout_width="fill_parent" 

           android:id="@+id/balloon_item_snippet"

           android:text="balloon_item_snippet" 

           android:textSize="12dip"></TextView>

   </LinearLayout>

   

     <ImageView android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:src="@drawable/balloon_overlay_close"
        android:id="@+id/close_img_button" 
        android:paddingLeft="10dip"
        android:paddingBottom="10dip" 
        android:paddingRight="8dip"
        android:paddingTop="8dip"></ImageView>
</LinearLayout>








main.xml

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mainlayout" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <com.google.android.maps.MapView android:id="@+id/mapview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:clickable="true" android:apiKey="YOUR_API_KEY" /> </RelativeLayout>






 
졸업장품으로 간단하게 어플을 만들었는데 그중 하나가 이 소스를 이용하여 일본 나고야 관광어플을 만들었습니다.
아래 스샷은 위에 소스를 이용하여 사진도 넣을수 있게 변경한것입니다..ㅎㅎ
이런식으로 꾸미면 지역소개 어플마들때 훨신 더 이쁘게 만들어지더라구요.. 










지도위에 찍히는 마커도 저희가 바꿔봤습니다.
 






말풍선이 두개 필요하여 위에 소스를 이용하여 수정하였습니다..
파란색 마커는 상세 페이지가 없고
금색마커는 상세페이지가 있는데 클릭시 index값을 공유하는 바람에
클릭이벤트 처리에 한계를 느껴서 수정하게 되었습니다.(무슨말인지..ㅋㅋㅋ) 







말풍선을 클릭했을시 상세페이지로 가게 됩니다..ㅎㅎ
 



저 위 소스를 이용하여 더 많은것도 할수 있겠죠?
다음에는 구글맵으로 길찾기 기능을 소개해볼려고합니다.


출처 : http://www.dingpong.net/tt/277

안드로이드의 EditText에 포커스가 가게 되면 기본적으로 폰에서 설정한 기본 언어에 대한 키보드로 노출이 됩니다. 그런데 ID 값과 같은 것을 입력 받아야 하는 EditText와 같은 경우에는 처음에 영문 키보드가 나오도록 하고 싶은 경우가 있을 수 있습니다. 그럴 경우 아래와 같은 라인을 추가하면 영문 키보드가 바로 나오도록 할 수 있습니다.

android:inputType="textVisiblePassword"


 EditText의 XML에 위 라인을 추가하면 됩니다. 이것은 EditText에 password 모드를 설정하면 키보드가 영문으로 띄워지는 것을 생각해서 구현한 방법입니다. 검색을 해보면 privateOption 같은 것을 조절해서 하는 방법이 있는데 잘 안되더라구요. 참고로 갤럭시S 에서는 위 방법으로 잘 안되서 아래와 같이 설정하였습니다.

android:inputType="textUri"

 하단에 Space 버튼 대신에 .com 이라는 버튼이 나오는데, 어쩔 수 없이 사용 할 수 밖에 없는 것 같습니다.

- 안드로이드 2.1 & 2.2 버전으로 테스트 되었습니다.
출처 : http://www.mtalking.com/?p=403
안드로이드 device 에서 3G나 WIFI 연결 정보를 알아볼때 사용
우선 AndroidManifest.xml에 " android.permission.ACCESS_NETWORK_STATE "  permission이 필요하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ConnectivityManager cManager;
NetworkInfo mobile;
NetworkInfo wifi;
  
cManager=(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
mobile = cManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
wifi = cManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
  
if(mobile.isConnected()){
    //3G 연결되있음.
}
  
if(wifi.isCOnnected()){
    //wifi 연결되있음.
}
위 코드는 필요시 한번 정보를 가지고 오면 끝이다.
그러나 네트워크 상황이 변화될때마다 특정 작업을 수행해야  한다면 다음과 같이 해야한다.
우선 BroadcastReceiver를 상속받는 class 를 만든다
ex)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class TestReceiver extends BroadcastReceiver {
  
    String action;
  
    @Override
    public void onReceive(Context context, Intent intent) {
  
        action=intent.getAction();
  
        Log.d("TestReceiver","action : " + action);
  
        if(action.equals(ConnectivityManager.CONNECTIVITY_ACTION)){
  
            /*
  
            네트워크 변화가 생길때마다 이쪽으로 들어온다.
  
            */
       }
  
    }
  
}
그다음 AndroidManifest.xml에 등록을 해준다.
ex)
1
2
3
4
5
<receiver android:name =".TestReceiver">
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</receiver>

출처 : http://blog.tacticalnuclearstrike.com/2010/01/using-multipartentity-in-android-applications/

Using MultipartEntity in Android applications

To be able to upload files from an Android application and use the Multipart content type you need to add some additional jar files to your application.

The files needed are apache-mime4j, httpclient, httpcore and httpmime. All are opensource projects built by the Apache foundation.

Download the 4 files and add them to your project then you should be able to use the following code to post strings and files to pages.

01
02
03
04
05
06
07
08
09
10
11
12
13
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://www.tumblr.com/api/write");
  
try {
  MultipartEntity entity = new MultipartEntity();
  
  entity.addPart("type", new StringBody("photo"));
  entity.addPart("data", new FileBody(image));
  httppost.setEntity(entity);
  HttpResponse response = httpclient.execute(httppost);
} catch (ClientProtocolException e) {
} catch (IOException e) {
}

The image variable in this case is a File that contains an image captured by the camera on the phone.

출처 : http://www.softwarepassion.com/android-series-get-post-and-multipart-post-requests/

Today I will describe shortly how to execute http GET and POST request on Android platform.
The code is very simple and straightforward, for post request with attachement, you would have to add apache-mime4j-0.6.jar and httpmime-4.0.1.jar to your build path.

HTTP GET

try {
        HttpClient client = new DefaultHttpClient();  
        String getURL = "http://www.google.com";
        HttpGet get = new HttpGet(getURL);
        HttpResponse responseGet = client.execute(get);  
        HttpEntity resEntityGet = responseGet.getEntity();  
        if (resEntityGet != null) {  
                    //do something with the response
                    Log.i("GET RESPONSE",EntityUtils.toString(resEntityGet));
                }
} catch (Exception e) {
    e.printStackTrace();
}

HTTP POST

     try {
        HttpClient client = new DefaultHttpClient();  
        String postURL = "http://somepostaddress.com";
        HttpPost post = new HttpPost(postURL);
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("user", "kris"));
            params.add(new BasicNameValuePair("pass", "xyz"));
            UrlEncodedFormEntity ent = new UrlEncodedFormEntity(params,HTTP.UTF_8);
            post.setEntity(ent);
            HttpResponse responsePOST = client.execute(post);  
            HttpEntity resEntity = responsePOST.getEntity();  
            if (resEntity != null) {    
                Log.i("RESPONSE",EntityUtils.toString(resEntity));
            }
    } catch (Exception e) {
        e.printStackTrace();
    }

HTTP POST with File attachment

File file = new File("path/to/your/file.txt");
try {
         HttpClient client = new DefaultHttpClient();  
         String postURL = "http://someposturl.com";
         HttpPost post = new HttpPost(postURL);
     FileBody bin = new FileBody(file);
     MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);  
     reqEntity.addPart("myFile", bin);
     post.setEntity(reqEntity);  
     HttpResponse response = client.execute(post);  
     HttpEntity resEntity = response.getEntity();  
     if (resEntity != null) {    
               Log.i("RESPONSE",EntityUtils.toString(resEntity));
         }
} catch (Exception e) {
    e.printStackTrace();
}

Hope this helps!



안드로이드 공부하시는 분들은 자신이 만든 어플리케이션이 멋지게 작동하는걸 원하실 겁니다.
그중에하나가 에니메이션이죠.
그런데 에니메이션 하면 보통 ViewFlipper 를 많이들 생각하실겁니다.
하지만 ViewFlipper는 뷰를 컨트롤하는거지 Activity간의 에니메이션을 컨트롤하지는 않습니다.

그래서 있는것이 overridePendingTransition 입니다.

사용 예) overridePendingTransition(R.anim.push_right_in, R.anim.push_right_out);


인텐트로 넘어갈때 써주시면 됩니다.
다만 아셔야 할것이 있습니다.
이것은 안드로이드 버전과 관련이있더군요.
제가 1.5로 어플을 만드는데 처음에 이걸썻다가 오작동 혹은 오류가 뜨길래 잘못된 정보인줄 알았습니다만,
2.1로 만든 어플에서는 작동이 되었습니다.

아무튼 Activity간의 이동시에 에니메이션을 추가하고싶으시면 overridePendingTransition를 써주시면 됩니다

File: res/layout/main.xml


<?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">

<ListView

android:id="@android:id/list"

android:layout_width="wrap_content"

android:layout_height="wrap_content" android:listSelector="@android:color/transparent" />

<TextView

android:id="@android:id/empty"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/empty" />

</LinearLayout>

 

 

 

 

File: res/layout/item.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="horizontal" android:padding="10sp" android:background="@drawable/item_selector">

 <CheckBox

android:id="@+id/checkbox"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:focusable="false" />

<TextView android:id="@+id/title"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:ellipsize="end"

android:singleLine="true"

android:textStyle="bold"

android:padding="7dip"

android:textSize="18sp"

android:layout_toRightOf="@id/checkbox"

android:textColor="@color/black" />

</RelativeLayout>

 

 

 

File: res/drawable/item_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@color/green" />
<item android:state_selected="true" android:drawable="@color/blue" />
<item android:drawable="@color/white" /></selector>
 
 

File: res/values/colors.xml

<?xml version="1.0" encoding="utf-8"?>

<resources>

<color name="red">#ff00</color>

<color name="green">#f0f0</color>

<color name="blue">#f00f</color>

<color name="white">#ffff</color>

<color name="black">#f000</color>

</resources>



출처 : http://www.shop-wiz.com/document/android/google_map_example1

[설명]
- GPS를 이용한 내위치값 받기
DDMS > Emulator Control > Location Controls > Manual(원하는 좌표값 입력후 "Send")
manifest xml : <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 확인
이번에도 먼저 전체 소스를 보여 드리겠습니다.
[설명]
AndroidManifest.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="utf-8"?>
      package="com.ProjectMyPosition"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".ProjectMyPosition"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <uses-library android:name="com.google.android.maps" />
    </application>
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>   
    
[설명]
res/layout/main.xml
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.maps.MapView
    android:id="@+id/mapview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:clickable="true"
    android:apiKey="your apikey here"
/>       
    
[설명]
res/values/strings.xml
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<resources
    <string name="hello">Hello World, ProjectMyPosition!</string>
    <string name="app_name">ProjectMyPosition</string>
    <string name="Location_fail_title">데이터 오류</string>
    <string name="Location_fail_message">현재 위치 정보를 얻어올 수 없습니다. GPS를 ON하셨는지 확인바랍니다.</string>
</resources>
          
    
[설명]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.ProjectMyPosition;
  
import android.os.Bundle;
  
import com.google.android.maps.MapActivity;
  
    public class ProjectMyPosition extends MapActivity {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState){
             super.onCreate(savedInstanceState); 
             setContentView(R.layout.main); 
        }
          
        @Override
        protected boolean isRouteDisplayed() {
            return false;
        }   
    }   
    
[설명]
ProjectMyPosition.java
너무 길어서 압박감이 느껴지시나요?
이전 장에서 다룬것에서 몇가지가 추가 되었습니다.
추가된 내용중 핵심은 loadGps() 에 있는
provider = locationManager.getBestProvider(criteria, true);
location = locationManager.getLastKnownLocation(provider);
입니다. location을 구하기 위해 provider를 구하는 것입니다.
물론 location은
이전장에 GeoPoint point = new GeoPoint((int)(37.5643406*1E6),(int)(126.9756087*1E6));
대신에 eoPoint point = new GeoPoint((int)(location.getLatitude()*1E6),(int)(location.getLongitude()*1E6)); 처럼 능동적으로 하기 위해서입니다.

나머지는 에러 처리 구문이라고 보시면됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package com.ProjectMyPosition;
  
import java.util.List;
  
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
  
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;
    public class ProjectMyPosition extends MapActivity {
        private static final String TAG = ProjectMyPosition.class.toString();
        private static boolean result = false;
          
        private LocationManager locationManager;
        private String provider;
        private Location location;
          
        private MapView mapView;
        private MapController mapController;
          
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState){
             super.onCreate(savedInstanceState); 
             setContentView(R.layout.main);
               
             //xml에 apiKey정의가 없을 경우 MapView mapview = new MapView(context, "your api key");처럼 사용가능
            mapView = (MapView) findViewById(R.id.mapview);
            mapView.setBuiltInZoomControls(true);  
  
  
         
            // load GPS( GPS 로 부터 현재의 내 위치값 가져오기 )
            loadGps();//location 값 할당
              
            List<Overlay> mapOverlays = mapView.getOverlays();
            Drawable drawable = this.getResources().getDrawable(R.drawable.androidmarker);
            MyItemizedOverlay itemizedoverlay = new MyItemizedOverlay(drawable,this);
              
            //GeoPoint  point = new GeoPoint((int)(37.5643406*1E6),(int)(126.9756087*1E6));
            GeoPoint  point = new GeoPoint((int)(location.getLatitude()*1E6),(int)(location.getLongitude()*1E6));
            OverlayItem overlayitem = new OverlayItem(point, "Hi Pondol!", "I'm in Seoul!");
            itemizedoverlay.addOverlay(overlayitem);
     
            mapController = mapView.getController();
            mapController.setCenter(point);
            mapController.setZoom(15);
           // mapController.animateTo( point );
            mapOverlays.add(itemizedoverlay);
              
              
        }
          
        @Override
        protected boolean isRouteDisplayed() {
            return false;
        }   
  
          
        public void loadGps() {
            Log.w(TAG , "loadGps Start" );
              
            String context = Context.LOCATION_SERVICE;//안드로이드 시스템으로 부터 LocationManager 서비스를 요청하여 할당
            locationManager = (LocationManager)getSystemService(context);
             
            //GPS 환경설정
            Criteria criteria = new Criteria();
            criteria.setAccuracy(Criteria.ACCURACY_FINE);       // 정확도
            criteria.setPowerRequirement(Criteria.POWER_LOW);   // 전원 소비량
            criteria.setAltitudeRequired(false);                // 고도, 높이 값을 얻어 올지를 결정
            criteria.setBearingRequired(false);                 // provider 기본 정보
            criteria.setSpeedRequired(false);                   //속도
            criteria.setCostAllowed(true);                      //위치 정보를 얻어 오는데 들어가는 금전적 비용
              
            //상기 조건을 이용하여 알맞은 GPS선택후 위치정보를 획득
              
            //manifest xml  : <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />//로케이션 메니저의 provider 
            provider = locationManager.getBestProvider(criteria, true);
            Log.i(TAG, "provider:"+provider);
            if(provider == null){//GPS 장치가 없는 휴대폰이거나 설정이 꺼져있는 경우 바로 alert 처리하거나 GPS 설정으로 이동
                result = chkGpsService();
                if(result){
                    loadGps();
                }
                  
            }else{
                location = locationManager.getLastKnownLocation(provider);//가장 최근의 로케이션을 가져온다. 안드로이드 폰이 꺼져있었거나 다른 위치로 이동한 경우 값이 없다.
                //location = locationManager.getLastKnownLocation( LocationManager.NETWORK_PROVIDER );
                //이럴경우는 NETWORK_PROVIDER 로 부터 새로운 location을 지정 받는다.
                //특정조건(시간, 거리)이 되면  Listener를 invoke 시킨다.: 여기서는 1초 마다 5km)
                locationManager.requestLocationUpdates(provider, 1000, 5, loclistener);//현재정보를 업데이트
                  
                if(location == null){
                    location = locationManager.getLastKnownLocation(provider);
                    if(location == null){//그래도 null인경우 alert;
                        Log.w(TAG, "get Location From GPS Fail !!!!!");
                        AlertDialog.Builder adb = new AlertDialog.Builder(ProjectMyPosition.this);
                        adb.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                            }
                        });
                        adb.setTitle( R.string.Location_fail_title );
                        adb.setMessage(R.string.Location_fail_message);
                        adb.show();
                    }
  
                }
            }
        }   
          
        private final LocationListener loclistener = new LocationListener(){
            public void onLocationChanged(Location location) {
                Log.w(TAG , "onLocationChanged" );
            }
  
            public void onProviderDisabled(String provider) {
                Log.w(TAG , "onProviderDisabled" );
            }
  
            public void onProviderEnabled(String provider) {
                Log.w(TAG , "onProviderEnabled" );
            }
  
            public void onStatusChanged(String provider, int status, Bundle extras) {
                Log.w(TAG , "onStatusChanged" );
            
        };
          
        private boolean chkGpsService() {//GPS의 설정여부 확인 및 자동 설정 변경
            String gs = android.provider.Settings.Secure.getString(getContentResolver(),
            android.provider.Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
            Log.w("chkGpsService" , "get GPs Service" );
              
            if (gs.indexOf("gps", 0) < 0) {
                Log.w("chkGpsService" , "status: off" );
                // GPS OFF 일때 Dialog 띄워서 설정 화면으로 이동.
                AlertDialog.Builder gsDialog = new AlertDialog.Builder(this);
                gsDialog.setTitle("GPS Status OFF !!!");
                gsDialog.setMessage("Change Setting !!");
                gsDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        // GPS설정 화면으로 이동
                        Intent intent = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                        intent.addCategory(Intent.CATEGORY_DEFAULT);
                        startActivity(intent);
                    }
                }).create().show();
                return false;
            } else {
                Log.w("chkGpsService" , "status: on" );                 
                return true;
            }
        }     
  
    }
        
[설명]
MyItemizedOverlay.java
기존의 구글 맵 뷰에서 설명한 것과 동일 하므로 별다른 설명은 없습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.ProjectMyPosition;
  
import java.util.ArrayList;
  
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.drawable.Drawable;
  
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.OverlayItem;
  
public class MyItemizedOverlay extends ItemizedOverlay {
  
    private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
    private Context mContext;
       
    // constructor 
    public MyItemizedOverlay(Drawable defaultMarker, Context context) {
        super(boundCenterBottom(defaultMarker));
        mContext = context;
    }
       
    public void addOverlay(OverlayItem overlay) {
        mOverlays.add(overlay);
        populate();
    }
       
    @Override
    protected OverlayItem createItem(int i) {
      return mOverlays.get(i);
    }
   
    @Override
    public int size() {
        return mOverlays.size();
    }
       
    @Override
    protected boolean onTap(int index) {
      OverlayItem item = mOverlays.get(index);
      AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
      dialog.setTitle(item.getTitle());
      dialog.setMessage(item.getSnippet());
      dialog.show();
      return true;
    }   
   
   
}   
출처 : http://cafe.naver.com/ccjmaster.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=1158&

<반복되는 배경 · 패턴 이미지 만들기>

 

  오늘은 반복되는 배경 이미지를 만들어 보겠습니다.

 

  간단히 말해, 이런 간단한 이미지를 가지고 패턴이 반복되는 배경을 만드는 것입니다.

 

 

 

 

  생각보다 간단합니다.

 

  보시다시피 Main Class에는 손 댈 일이 없습니다.

 

  먼저, drawable 폴더에 xml을 하나 만들어주시구요,

 

  pattern에 사용할 이미지도 넣어주셔야겠죠?

 

 



 자, 이제 background.xml을 열고 다음과 같이 작성합니다.

 

  bitmap 속성을 주셔야하는데, 이것을 대문자로 주시면 적용되지 않습니다.

 

  마찬가지로 @drawable/pattern, 이렇게 반복시켜 줄 이미지를 선택하신 다음

 

  android:tileMode="repeat"라고 설정해주시기 바랍니다.

 

 

 

 

  그리고 원래 생성되어 있던 main.xml을 열어주세요.

 

  android:background="@drawable/background"라고 해주시면 됩니다.

 

  당연히 background라는 XML이 drawable에 있어야겠죠?

 

 

 

 

  그런 다음 Application을 실행시켜주면, 이렇게 나오게 될 것입니다.

 

 

 

  참, 간단하죠?

 

출처 : http://jsharkey.org/blog/2008/08/18/separating-lists-with-headers-in-android-09/

Separating Lists with Headers in Android 0.9

Monday August 18, 2008 at 4:42 PM

Earlier today the latest Android 0.9 SDK was released, and it’s packed full of wonderful changes. As you play around, you might see ListViews split into sections using separating headers. (Example shown on the right is the browser settings list.)

There isn’t an easy way of creating these separated lists, so I’ve put together SeparatedListAdapter which does it quickly. To summarize, we’re creating a new BaseAdapter that can contain several other Adapters, each with their own section headers.

First let’s create some simple XML layouts to be used for our lists: first the header view, then two item views that we’ll use later for the individual lists. (Thanks to Romain Guy for helping me find existing styles to keep these XML layouts nice and tidy.)

  1. <!-- list_header.xml -->  
  2. <TextView  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     android:id="@+id/list_header_title"  
  5.     android:layout_width="fill_parent"  
  6.     android:layout_height="wrap_content"  
  7.     android:paddingTop="2dip"  
  8.     android:paddingBottom="2dip"  
  9.     android:paddingLeft="5dip"  
  10.     style="?android:attr/listSeparatorTextViewStyle" />  
  11.   
  12. <!-- list_item.xml -->  
  13. <TextView  
  14.     xmlns:android="http://schemas.android.com/apk/res/android"  
  15.     android:id="@+id/list_item_title"  
  16.     android:layout_width="fill_parent"  
  17.     android:layout_height="fill_parent"  
  18.     android:paddingTop="10dip"  
  19.     android:paddingBottom="10dip"  
  20.     android:paddingLeft="15dip"  
  21.     android:textAppearance="?android:attr/textAppearanceLarge"  
  22.     />  
  23.   
  24. <!-- list_complex.xml -->  
  25. <LinearLayout  
  26.     xmlns:android="http://schemas.android.com/apk/res/android"  
  27.     android:layout_width="fill_parent"  
  28.     android:layout_height="wrap_content"  
  29.     android:orientation="vertical"  
  30.     android:paddingTop="10dip"  
  31.     android:paddingBottom="10dip"  
  32.     android:paddingLeft="15dip"  
  33.     >  
  34.     <TextView  
  35.         android:id="@+id/list_complex_title"  
  36.         android:layout_width="fill_parent"  
  37.         android:layout_height="wrap_content"  
  38.         android:textAppearance="?android:attr/textAppearanceLarge"  
  39.         />  
  40.     <TextView  
  41.         android:id="@+id/list_complex_caption"  
  42.         android:layout_width="fill_parent"  
  43.         android:layout_height="wrap_content"  
  44.         android:textAppearance="?android:attr/textAppearanceSmall"  
  45.         />  
  46. </LinearLayout>  

Now let’s create the actual SeparatedListAdapter class which provides a single interface to multiple sections of other Adapters. After using addSection() to construct the child sections, you can easily use ListView.setAdapter() to present the now-separated list to users.

As for the Adapter internals, to correctly find the selected item among the child Adapters, we walk through subtracting from the original position until we find either a header (position = 0) or item in the current child Adapter (position < size).

Here’s the source for SeparatedListAdapter:

  1. public class SeparatedListAdapter extends BaseAdapter {   
  2.   
  3.     public final Map<String,Adapter> sections = new LinkedHashMap<String,Adapter>();   
  4.     public final ArrayAdapter<String> headers;   
  5.     public final static int TYPE_SECTION_HEADER = 0;   
  6.   
  7.     public SeparatedListAdapter(Context context) {   
  8.         headers = new ArrayAdapter<String>(context, R.layout.list_header);   
  9.     }   
  10.   
  11.     public void addSection(String section, Adapter adapter) {   
  12.         this.headers.add(section);   
  13.         this.sections.put(section, adapter);   
  14.     }   
  15.   
  16.     public Object getItem(int position) {   
  17.         for(Object section : this.sections.keySet()) {   
  18.             Adapter adapter = sections.get(section);   
  19.             int size = adapter.getCount() + 1;   
  20.   
  21.             // check if position inside this section   
  22.             if(position == 0return section;   
  23.             if(position < size) return adapter.getItem(position - 1);   
  24.   
  25.             // otherwise jump into next section   
  26.             position -= size;   
  27.         }   
  28.         return null;   
  29.     }   
  30.   
  31.     public int getCount() {   
  32.         // total together all sections, plus one for each section header   
  33.         int total = 0;   
  34.         for(Adapter adapter : this.sections.values())   
  35.             total += adapter.getCount() + 1;   
  36.         return total;   
  37.     }   
  38.   
  39.     public int getViewTypeCount() {   
  40.         // assume that headers count as one, then total all sections   
  41.         int total = 1;   
  42.         for(Adapter adapter : this.sections.values())   
  43.             total += adapter.getViewTypeCount();   
  44.         return total;   
  45.     }   
  46.   
  47.     public int getItemViewType(int position) {   
  48.         int type = 1;   
  49.         for(Object section : this.sections.keySet()) {   
  50.             Adapter adapter = sections.get(section);   
  51.             int size = adapter.getCount() + 1;   
  52.   
  53.             // check if position inside this section   
  54.             if(position == 0return TYPE_SECTION_HEADER;   
  55.             if(position < size) return type + adapter.getItemViewType(position - 1);   
  56.   
  57.             // otherwise jump into next section   
  58.             position -= size;   
  59.             type += adapter.getViewTypeCount();   
  60.         }   
  61.         return -1;   
  62.     }   
  63.   
  64.     public boolean areAllItemsSelectable() {   
  65.         return false;   
  66.     }   
  67.   
  68.     public boolean isEnabled(int position) {   
  69.         return (getItemViewType(position) != TYPE_SECTION_HEADER);   
  70.     }   
  71.   
  72.     @Override  
  73.     public View getView(int position, View convertView, ViewGroup parent) {   
  74.         int sectionnum = 0;   
  75.         for(Object section : this.sections.keySet()) {   
  76.             Adapter adapter = sections.get(section);   
  77.             int size = adapter.getCount() + 1;   
  78.   
  79.             // check if position inside this section   
  80.             if(position == 0return headers.getView(sectionnum, convertView, parent);   
  81.             if(position < size) return adapter.getView(position - 1, convertView, parent);   
  82.   
  83.             // otherwise jump into next section   
  84.             position -= size;   
  85.             sectionnum++;   
  86.         }   
  87.         return null;   
  88.     }   
  89.   
  90.     @Override  
  91.     public long getItemId(int position) {   
  92.         return position;   
  93.     }   
  94.   
  95. }  

As expected, it correctly prevents the section headers from being selected, and seamlessly stiches together the various Adapters.

This approach also uses convertView correctly as long as the child Adapters return getItemViewType() and getViewTypeCount() normally. No special changes are needed for an Adapter to become a child.

Now let’s use SeparatedListAdapter in some example code. We use the XML layouts defined earlier to create an ArrayAdapter and an advanced two-row SimpleAdapter, and then add both as sections to our SeparatedListAdapter.

  1. public class ListSample extends Activity {   
  2.   
  3.     public final static String ITEM_TITLE = "title";   
  4.     public final static String ITEM_CAPTION = "caption";   
  5.   
  6.     public Map<String,?> createItem(String title, String caption) {   
  7.         Map<String,String> item = new HashMap<String,String>();   
  8.         item.put(ITEM_TITLE, title);   
  9.         item.put(ITEM_CAPTION, caption);   
  10.         return item;   
  11.     }   
  12.   
  13.     @Override  
  14.     public void onCreate(Bundle icicle) {   
  15.         super.onCreate(icicle);   
  16.   
  17.         List<Map<String,?>> security = new LinkedList<Map<String,?>>();   
  18.         security.add(createItem("Remember passwords""Save usernames and passwords for Web sites"));   
  19.         security.add(createItem("Clear passwords""Save usernames and passwords for Web sites"));   
  20.         security.add(createItem("Show security warnings""Show warning if there is a problem with a site's security"));   
  21.   
  22.         // create our list and custom adapter   
  23.         SeparatedListAdapter adapter = new SeparatedListAdapter(this);   
  24.         adapter.addSection("Array test"new ArrayAdapter<String>(this,   
  25.             R.layout.list_item, new String[] { "First item""Item two" }));   
  26.         adapter.addSection("Security"new SimpleAdapter(this, security, R.layout.list_complex,   
  27.             new String[] { ITEM_TITLE, ITEM_CAPTION }, new int[] { R.id.list_complex_title, R.id.list_complex_caption }));   
  28.   
  29.         ListView list = new ListView(this);   
  30.         list.setAdapter(adapter);   
  31.         this.setContentView(list);   
  32.   
  33.     }   
  34.   
  35. }  

The resulting interface behaves just like the browser preferences list, and you could easily create other custom Adapters to insert into the various sections, such as including icons or checkboxes.

These section headers can really help separate out otherwise-cluttered activities. I used them several places in my CompareEverywhere application which lets you easily compare prices and read reviews for any product with a barcode.

Watch my blog using Google Reader: Add to Google


Anyone that is in need of it .. attached here is the Motorola Atrix4G addon for the Android SDK .. also the instructions for installation and execution.

http://www.mediafire.com/?73hkz09wr0l1kqe

Installing and Using Motorola SDK Add-ons

A Motorola SDK add-on, when added to the Android™ SDK, allows you to run and debug your applications on an emulated Motorola handset. Note that while the device image that the add-on presents does not necessarily reflect the look of the actual device, from a functional standpoint it should be a fairly faithful emulation of the actual handset.

Installing the add-on

To install the Motorola SDK add-on, unzip it, and copy the resulting directory to the directory named add-ons within the Android SDK that you are using (if you are using MOTODEV Studio for Android and are not sure where it placed the Android SDK, check the SDK Location field in the Android preferences dialog).

** NOTE: If MOTODEV Studio for Android or Eclipse™ were running when you copied the SDK add-on, you will need to restart it for the add-on to be recognized by your development environment.

Using the add-on

In order to run or debug your applications on an emulated Motorola handset, you must first create an AVD that has its AVD Target set to reference the SDK add-on. You can then deploy your applications to it. When creating your projects, you can either target the emulated Motorola device specifically (which you would do if your application runs only on that device), or you can select a more general, compatible target such as Android 1.5. The following sections detail the steps involved in each of these tasks.

Creating an AVD



To create an AVD named "Motorola" using the command line, do the following (you may need to be within the Android SDK's "tools" directory):

  1. android list targets
    The details for each possible target are listed, starting with a unique ID number that identifies that target. Make note of the ID number for the Motorola add-on you want to target.
  2. android create avd -n Motorola -t target-ID
    For target-ID supply the ID number for the target you obtained from the previous step.
To create it from within MOTODEV Studio for Android:
  1. Select Android AVD Manager from the Window menu. The Android Virtual Devices Manager dialog appears.
  2. Enter Motorola (or whatever name you want to give the new AVD) in the Name field.
  3. From the Target list, select the target named for the Motorola device you are targeting.
  4. From the Skin list, select the skin named for your target device.
  5. If you want the emulated device to have an SD card, in the SDCard field either specify the path and filename to a file containing an existing SD card image, or specify a size (such as 64M) to create a new, empty SD card image. Leave this field blank if the device isn't to have an SD card.
  6. Click Create AVD.
  7. Click Finish to close the dialog.
When creating Run or Debug configurations, you can now select this new AVD when choosing a target device.

**NOTE: If your newly-created AVD does not appear in the Device Management view, click Refresh, which is located in the top right corner of that view.

Starting the AVD

If you start a Run or Debug configuration that specifies a Motorola SDK add-on AVD as the target device, the AVD will be automatically launched for you. If you want to start the AVD without deploying an application to it, you can do so either from the command line or from within MOTODEV Studio for Android. From the command line, the following command will start the AVD named "Motorola":
emulator -avd Motorola
To start it from within MOTODEV Studio for Android, select the AVD from within the Device Management view and click Start.

Targeting the Motorola device

If your application is designed specifically for a Motorola device, select the corresponding Motorola SDK add-on as the project target when creating the project.



To change an existing project so that it targets the SDK add-on from an Eclipse-based IDE such as MOTODEV Studio for Android:
  1. Right-click the project in the Package Explorer and select Properties.
  2. From the list of properties select Android.
  3. The project build target is shown in the right side of the dialog; select the one named for your target device.
If you are not using an Eclipse-based IDE you can change your project's target with the android update project command; see Google's developer documentation on developing in other IDEs.
제작하는 한 어플리케이션에 버튼은 총 몇개나 등장할까요?

버튼의 이벤트를 등록하려면 또 똑같은 코딩을 몇번을 해야 할 지 모릅니다.

그래서 준비한 강쉪의 특별 소스.

'모든 뷰를 등록하자'입니다.

Android SDK는 java코딩만으로도 충분히 xml의 역할을 대신 할 수 있지만,

바로 눈으로 보이는 구조와 편리함, 연동성을 생각한다면 불가피하게 xml을 사용 할 수 밖에 없습니다.

Android SDK가 1.0부터 발전을 거듭해와 현재 나온 2.2 버전까지

달라진 메소드는 없지만 사라지거나 새로 생긴것들이 많습니다.

이번 주제와도 비슷한 예를 들자면

xml의 버튼에

<Button
    android:onClick = "ClickHandler"        //java에 연동되는 id가 아닌 onClick에 아이디를 줍니다.
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
>

라고 사용하신다면

java에선

public void ClickHandler(View target){
    Intent i = new Intent();
    switch(target.getId()){
    case R.id.$#^%^#%^%:
        break;
    }
}

이런식으로 손쉽게 구현이 가능해 집니다

이는 Android SDK 2.1 이상의 버젼에서만 사용되는 메소드로 그 이전의 SDK를 사용하면 구현되지 않습니다.

이제 이벤트를 처리하는 메소드를 알아봤으니

본격적으로 리스너를 등록해 보도록 하겠습니다.




한 프로젝트에 버튼이 50개 정도 등장한다고 생각해 봅시다.

그중 각 Activity마다 10개씩의 버튼을 사용 해야 한다면??

생각만 해도 어지럽습니다.

그래서 등장한것이


메인 Layout에 ID넣기!

일단은 다른생각 말고 따라해 보세요 ^^

예를들어 자신의 프로젝트에 Main으로 쓰이는 xml이

RelativeLayout이라면?

그 최상위 Layout에

android:id="@+id/mainview_layout"

이라고 등록을 해줍니다.

그리고 자바로 넘어가

onCreate 안에

RelativeLayout layout = (RelativeLayout)findViewById(R.id.mainview_layout);
setOnclickListener(layout);       //최상위 레이아웃 리스너 등록
    

이렇게 등록을 해주시는 겁니다.

이게 끝이 아니죠

    private void setOnclickListener(ViewGroup group){   //모든 뷰 그룹 등록
     View[] childViews = getChildViews(group);
     for (View view : childViews){     
      if(view instanceof Button){
       view.setOnClickListener(this);
      }else if(view instanceof ViewGroup){
       setOnclickListener((ViewGroup)view); //재귀돌림
      }
     }
    }

이렇게 모든 뷰를 등록 해줍니다.

이게 무슨 뜻일까요??

for문을 이용해 View에 생겨나는 자식 View들을 모두 등록해 줍니다.

하지만!

xml의 구조상  한 Layout안에 다른 Layout을 생성할 필요가 있겠죠.

그 때에는 재귀를 돌려 한번더 등록해주는 것입니다.

    private View[] getChildViews(ViewGroup group){
     int childCount = group.getChildCount();
     final View[] childViews = new View[childCount];
     for (int index =0;index < childCount; index++){
      childViews[index] = group.getChildAt(index);
     }
     return childViews;
    }

그 후 자식View에 java에서 쓰일 아이디값을 채워 넣어주면 ok!


xml에서 각 버튼의 아이디 값을 주어

그것이 R.id에 등록이 되고

또 그것을 java에서 사용하는데 보다 많은 도움이 되는 소스라 생각됩니다. ^^

그럼 이만 다음에 뵙겠습니다
width height w/h % 대표기종
320 480 66.67% 아이폰3Gs, Android G1
640 960 66.67% 아이폰4
==========================================================아이폰
480 800 60.00% 갤럭시S, 넥서스원, Desire
480 854 56.21% 모토로이
540 960 56.25% 아트릭스
==========================================================안드로이드 3.0
1280    720       ...   이후 넥서스프리미엄 출시이후(예정)
==========================================================안드로이드 4.0

+ Recent posts