image

onScrollStateChanged함수는 기존에 onScroll 함수가 스크롤 할 때마다 호출되어 반응성이 좋게 코드를 만들 수도 있겠지만,  빈번한 호출로 어플이 버벅일수도 있었다. 그러한 점을 고쳐 newState로 들어오는 스크롤 상태변수는 상태가 변할 때 마다 딱 1번만 호출되어 값을 넘겨준다.

SCROLL_STATE_SETTLING상태는 위든 아래든 스크롤이 끝까지 갔음을 의미한다.

SCROLL_STATE_IDLE상태는 현재 스크롤을 하지 않는 상태,  SCROLL_STATE_DRAGGING 스크롤을 하고 있는 상태이다.

onScrolled함수의 dx, dy 변수는 각자 수직 수평으로 스크롤이 얼마나 되었는지 그 양을 뜻한다. 스크롤 위치가 아니다, 절대.

dy가 음수 값이면 현재 위치를 0 기준 잡고 위로 스크롤 했다는 뜻이고, dy가 양수면 아래로 스크롤 했다는 뜻이다.

'android' 카테고리의 다른 글

네트워크 상태 체크 하기  (1) 2016.04.26
UI Thread 사용법  (0) 2016.04.24
ListView를 대체할 새로운 컴포넌트 Recyclerview  (0) 2016.04.24

Android를 개발하다 보면, 네트워크 통신 전에 꼭 해야 할 것이 있는데 이것이 바로 현재 단말기가 mobile network or Wifi에 연결되어 있는지 확인 후, 통신을 시도하게 된다.

오랜만에 코딩 하고 있는지라, api 23 부터 기존 아래의 코드는 deprecated 되었다.

   1: ConnectivityManager manager = (ConnectivityManager) MyApplication.mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
   2:         NetworkInfo mobile = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
   3:         NetworkInfo wifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
   4:  
   5:         if (mobile.isConnected() || wifi.isConnected()) {
   6:  
   7:  
   8:         } else {
   9:             // WIFI, 3G 어느곳에도 연결되지 않았을때
  10:  
  11:         }

새로운 방식은 아래와 같다.

   1: ConnectivityManager cm = (ConnectivityManager) MyApplication.mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
   2:        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
   3:        if (activeNetwork != null) {
   4:  
   5:            if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI && activeNetwork.isConnectedOrConnecting()) {
   6:                // wifi 연결중
   7:  
   8:            } else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE && activeNetwork.isConnectedOrConnecting()) {
   9:                // 모바일 네트워크 연결중
  10:  
  11:            }
  12:            else
  13:            {
  14:                // 네트워크 오프라인 상태.
  15:            }
  16:        } else {
  17:            // 네트워크 null.. 모뎀이 없는 경우??
  18:        }

흠.. 별로 달라진 것이 없는 것 같지만, 이제 어떤 통신인지 구별도 가능하게 되었다..

MyApplication.mContext는 내가 만든 context를 저장하기 위한 전역 변수 역할을 하는 클래스이다..  필자는 어디서든 쓸 수 있도록 저렇게 쓴다.

다른 분들은 그 자리에는 자신이 만든 main Activity의 context를 넣자.

'android' 카테고리의 다른 글

안드로이드 RecyclerView 스크롤 감지  (0) 2016.04.26
UI Thread 사용법  (0) 2016.04.24
ListView를 대체할 새로운 컴포넌트 Recyclerview  (0) 2016.04.24

안드로이드는 크게 사용자가 만든 쓰레드와 UI를 담당하는 MainThread(UI Thread)가 있는데, Activity내부에서 쓰여진 코드들은 모두

UI쓰레드에서  실행된다.

그래서 쓰레드를 따로 쓰지 않고, 연산이 오래 걸릴 가능성이 있는 network 소켓을 사용한 통신을 한다 던지, file I/O 작업을 하게 되면

오류가 나며, 강제 종료 되게끔 되어있다.

왜 그런 것 일까? 우리가 안드로이드 입장이 되어 보면 당연하다. 만일 UI 쓰레드에서 네트워크 통신을 하면, 통신 하는 동안에는 UI

작업을 못하니깐, 말 그대로 화면이 멈출 것이다.

사용자가 화면을 터치해도 무반응일 것이며, 화면이 먹통이 되어버릴 것이다. 그래서 꼭 이런 작업들은 따로 사용자 스레드를 만들

어서 작업해주어야 한다.

사용법은 아래와 같다.

   1: new Thread(new Runnable()
   2: {
   3:     @Override
   4:     public void run()
   5:     {    
   6:       //수행 할 작업 코드
   7:     }
   8: }).start();

간단하다. But, 그런데 사용자 스레드 작업 중, UI를 변경(UI스레드에서 작업)하고 싶다면 어떻게 할까?

예를 들면 통신이 실패 해서 사용자에게 “통신이 상태가 좋지 않습니다” 라고 메세지를 띄우고 싶다면?

그럴 경우도 안드로이드는 친절히 방법을 마련해 놓았다.

아래와 같이 사용하면 된다.

   1: MainActivity.runOnUiThread(new Runnable()
   2: {
   3:     @Override
   4:     public void run()
   5:     {
   6:         //여기에 UI스레드에서 동작하게 하고 싶은 내용 입력
   7:     }
   8: });    

App 내에 자신이 정의한 메인엑티비티.runOnUiThread( )를 사용하면 된다. 제발 소스코드 복사 붙여 넣기 해서, “MainActivity선언이

안되어 있어요..” 라고 말도 안 되는 소리 하지 말자..

기존에 안드로이드 내에서 item목록을 보여주기 위해서는 ListView 컴포넌트를 사용했었다.

문제는 listView가 스크롤(scroll)되면서 getView내에서 계속해서 v.findViewById() 함수를 호출하게 되는데, 이는 불필요한 연산일뿐아니라,

UI성능 저하를 가져온다. 그래서 꼭 필수적으로 쓸 사항은 아니지만, 구글에서는 암묵적으로 ViewHolder 패턴을 쓰라고 권장하고 있는데,

아래와 같다.

   1: @Override
   2:   public View getView(int position, View convertView, ViewGroup parent)
   3:   {
   4:     PersonViewHolder viewHolder;
   5:  
   6:     // 캐시된 뷰가 없을 경우 새로 생성하고 뷰홀더를 생성한다
   7:     if(convertView == null)
   8:     {
   9:         convertView = mInflater.inflate(mLayout, parent, false);
  10:  
  11:         viewHolder = new PersonViewHolder();
  12:         viewHolder.icon = (ImageView) convertView.findViewById(R.id.iconImage);
  13:         viewHolder.name = (TextView) convertView.findViewById(R.id.name);
  14:         viewHolder.address = (TextView) convertView.findViewById(R.id.address);
  15:         viewHolder.phone = (TextView) convertView.findViewById(R.id.phone);
  16:  
  17:         convertView.setTag(viewHolder);
  18:     }
  19:     // 캐시된 뷰가 있을 경우 저장된 뷰홀더를 사용한다
  20:     else
  21:     {
  22:         viewHolder = (PersonViewHolder) convertView.getTag();
  23:     }
  24:  
  25:     viewHolder.name.setText(mItemList.get(position).getName());
  26:     viewHolder.address.setText(mItemList.get(position).getAddress());
  27:     viewHolder.phone.setText(mItemList.get(position).getPhone());
  28:  
  29:     return convertView;

30: }

저렇게 매번 converView를 생성 하는게 아니라, null이 아니면 재사용하는 방법을 사용한다.

하지만, 이제는 Recyclerview를 사용한다면, 저렇게 하지 않아도 된다.

아래는 내가 앱 내에서 게시판 글 목록을 보여주기 위해 만들어본, 게시판 리스트 뷰이다.

   1: static private class ArticleListAdapter extends RecyclerView.Adapter<ArticleListAdapter.ArticleItem>
   2:     {
   3:         ArrayList<Article> mList = null;
   4:         public ArticleListAdapter(ArrayList<Article> articles)
   5:         {
   6:             mList = articles;
   7:         }
   8:  
   9:         @Override
  10:         public ArticleItem onCreateViewHolder(ViewGroup parent, int viewType) {
  11:             //새로운 itemView가 필요시마다 호출된다.
  12:  
  13:             LayoutInflater inflater = LayoutInflater.from(MyApplication.mContext);
  14:  
  15:             View rootView = inflater.inflate(R.layout.fragment_board_article_row_item,parent,false);
  16:  
  17:             return new ArticleItem(rootView);
  18:         }
  19:  
  20:         @Override
  21:         public void onBindViewHolder(ArticleItem holder, int position) {
  22:           /* itemView가 ArticleItem holder로 넘어오면 우리는 그냥 받아 쓰면된다.
  23:             그것이 화면에서 사라져 재활용되기 위해서 온 view일수도 있고, 새로 만들어진 view일수도있지만
  24:             사용자는 그것에 대해 신경쓸필요없다.*/
  25:             Article article = mList.get(position);
  26:             holder.setTitle(article.getTitle());
  27:             switch (article.getType())
  28:             {
  29:                 case "normal":
  30:                     holder.setType(ArticleItem.ArticleType.NORMAL);
  31:                     break;
  32:                 case "notice":
  33:                     holder.setType(ArticleItem.ArticleType.NOTICE);
  34:                     break;
  35:             }
  36:             holder.setDate(article.getDate());
  37:             holder.setNick(article.getNickName());
  38:  
  39:  
  40:  
  41:         }
  42:  
  43:         @Override
  44:         public int getItemCount() {
  45:             return mList.size();
  46:         }
  47:  
  48:         /*
  49:         * 이전까지 썻던 ViewHolder패턴에서 직접 만들어 쓰던 ViewHolder다.
  50:         * 이제는 만들어 쓸필요없이, RecyclerView에서 자체적으로 제공해주는것을
  51:         * 상속해 쓰기만 하면된다.
  52:         * */
  53:         static class ArticleItem extends RecyclerView.ViewHolder
  54:         {
  55:             enum ArticleType {NOTICE,NORMAL}
  56:             TextView mTitleView = null;
  57:             TextView mDateView = null;
  58:             TextView mNickView = null;
  59:             TextView mArticleTypeView = null;
  60:  
  61:             public ArticleItem(View itemView) {
  62:                 super(itemView);
  63:                 mDateView = (TextView) itemView.findViewById(R.id.articleDate);
  64:                 mTitleView = (TextView) itemView.findViewById(R.id.articleTitle);
  65:                 mArticleTypeView = (TextView) itemView.findViewById(R.id.articleType);
  66:                 mNickView = (TextView) itemView.findViewById(R.id.author);
  67:             }
  68:             public void setDate(String date)
  69:             {
  70:                 mDateView.setText(date);
  71:             }
  72:             public void setTitle(String title)
  73:             {
  74:                 mTitleView.setText(title);
  75:             }
  76:             public void setType(ArticleType type)
  77:             {
  78:                 if(type == ArticleType.NOTICE)
  79:                 {
  80:                     mArticleTypeView.setText("공지");
  81:                 }
  82:                 else
  83:                 {
  84:                     mArticleTypeView.setText("일반");
  85:                 }
  86:             }
  87:             public void setNick(String nick)
  88:             {
  89:                 mNickView.setText(nick);
  90:             }
  91:         }
  92: }

'android' 카테고리의 다른 글

안드로이드 RecyclerView 스크롤 감지  (0) 2016.04.26
네트워크 상태 체크 하기  (1) 2016.04.26
UI Thread 사용법  (0) 2016.04.24

+ Recent posts