Java & Spring2019. 2. 7. 12:54

간단하게 다음 메소드로 할 수 있다. (자바 7부터 추가)

Arrays.sort(배열); // 올림차순
Arrays.sort(배열, Collections.reverseOrder()); // 내림차순

※ 숫자는 기본이고 영문과 한글도 잘 정렬된다.




Posted by 홍규홍규
HTML, CSS2019. 1. 28. 10:31

웹스톰 사용할 때 태그를 쓰다보면 = 사용 시 중괄호가 자동으로 생성된다.

<input placeholder={} />


객체가 아닌 문자열을 넣을 때는 아주 불편한 기능이 되어버려 해당 기능을 끄는 게 낫다.

Settings - Editor - General - Smart Keys 에서 

Add quotes for attribute value on typing '=' and attribute completion 을 체크해제 하면 된다.



'HTML, CSS' 카테고리의 다른 글

z-index 사용 시 주의사항  (0) 2018.03.30
Posted by 홍규홍규
Java & Spring2019. 1. 24. 11:15
<context : annotation-config />
<context : component-scan />

두 가지는 유사하면서도 차이점이 존재한다.

둘 다 application-context에 정의해서 사용할 수 있는데 헷갈리던 부분이 있어 명확하게 다시 정리해보고자 한다.


<context : annotation-config />

이미 등록된 bean에 대해서만 Annotation을 활성화한다.

어딘가에 bean을 등록해놓으면 @Autowired와 @Qualifier Annotation을 해석해서 가져다 쓰겠다는 의미이다.

@Autowired와 @Qualifier 두 가지만 해결한다.

따라서 위 태그를 사용하더라도 xml에 bean을 반드시 선언해야 한다.

<context : component-scan/>

bean의 등록 여부와 관계없다. 스프링이 알아서 bean 스캔을 통해 Annotation을 해석하고 활성화한다.

@Autowired와 @Qualifier 뿐만 아니라 @Service, @Component, @Controller, @Repository 등 모든 클래스를 스캔하고

bean을 작성한다.

따라서 이 태그를 사용하면 위 태그는 사용할 필요가 없다.

다만 이 경우 base-package를 통해 스프링이 스캔할 패키지 위치를 지정해두는 것이 일반적이다.

<context : component-scan base-package="com.sample"/>


마지막으로 둘의 중요한 공통점은 의존 주입(DI)이다. 스프링에서 흔히 말하는 의존주입은 위 과정을 통해 일어난다.

그리고 이 의존 주입(또는 의존성 주입)은 스프링 IoC의 중요한 개념 중 하나이다.


- 이상 끗



Posted by 홍규홍규
안드로이드2018. 12. 18. 15:38

예전 구독 기능을 구현할 땐 일일이 필요한 것들을 붙여서 했는데 

현재는 인앱결제를 라이브러리로 만든 친절하고도 대단한 분이 계신다. 


이번에는 구독이 아닌 광고 제거를 위한 1회성 결제가 필요한데 라이브러리를 사용해서 구현해보고자 한다.

당연한 얘기지만, 실제 기능을 만들기 위해 내가 해야 할 일이 매우, 매우 많이 줄어든다.


우선 해당 라이브러리가 소개된 github는 아래에 링크를 남겨두자.

https://github.com/anjlab/android-inapp-billing-v3


그럼 쉽게 쉽게 간단하게 간단하게 편하게 편하게 구현해볼까?


1. build.gradle에 다음을 추가한다.

implementation 'com.anjlab.android.iab.v3:library:1.0.44'

2. AndroidManifest.xml에 다음 퍼미션을 추가한다.

<uses-permission android:name="com.android.vending.BILLING" />

3. 해당 라이브러리 기능을 구현할 클래스를 하나 작성한다.

  - 적어도 두 군데의 액티비티에서 사용할 것이므로 별도의 클래스로 만듦

public class BillingModule implements BillingProcessor.IBillingHandler {
  private Context context;
  private BillingProcessor mBillingProcessor;

  public BillingModule(Context context) {
    this.context = context;
  }

  public void initBillingProcessor() {
    mBillingProcessor = new BillingProcessor(context, "rsa_key", this);
    // 아래와 차이는 기트허브 페이지에서 확인할 수 있다. 상황에 맞게 사용하면 됨.
    // mBilling Processor = BillingProcessor.newBillingProcessor(context, "rsa_key", this); 
    // rsa_key는 개발자 콘솔에서 제공하는 id
  }

  public void purchaseProduct() { // 아이템 구매 요청
    if(mBillingProcessor.isPurchased(itemId)) {
      // 이미 광고 제거를 위한 결제를 완료했기 때문에 해당 처리를 해주면 된다.
      return;
    }
    mBillingProcessor.purchase((Activity)context, itemId);
  }

  public void releaseBillingProcessor() { 
    if(mBillingProcessor != null)
      mBillingProcessor.release();
  }
  
  public BillingProcessor getBillingProcessor() { 
    return mBillingProcessor;
  }

  @Override
  public void onProductPurchased(@NonNull String id, @Nullable TransactionDetails transactionDetails) {
    // 아이템 구매 성공 시 호출.
    // 따라서 보상을 지급하든(광고 제거) 혹은 해당 아이템을 소비하든 해당 기능을 작성 
  }

  @Override
  public void onPurchaseHistoryRestored() {
    // 구매 내역 복원 및 구매한 모든 PRODUCT ID 목록이 Google Play에서 로드 될 때 호출.
  }

  @Override
  public void onBillingError(int errCode, @Nullable Throwable throwable) {
    // 구매 시 에러가 발생했을 때 처리
    if(errCode != com.anjlab.android.iab.v3.Constants.BILLING_RESPONSE_RESULT_USER_CANCELED) { 
      // 사용자가 취소한 게 아니라면 에러 발생에 대해 사용자에게 고지하는 등의 처리
    }
  }

  @Override
  public void onBillingInitialized() {
    // 개발자 콘솔에서 등록한 아이템 아이디
    SkuDetails mProduct = mBillingProcessor.getPurchaseListingDetails("remove_ad"); 
    if(mProduct == null)
      return;
    itemId = mProduct.productId;
    mBillingProcessor.loadOwnedPurchasesFromGoogle(); // 소유하고 있는 구매 아이템 목록을 가져온다.
    if(mBillingProcessor.isPurchased(mProduct.productId) {
      // 이미 광고 제거를 구매했다면 다시 구매할 필요가 없으므로 
      // 해당 부분 처리. 또는 이미 구매 시 광고 제거 구매를 애초에 막는다.
    }
  }
}

4. 필요한 클래스에서 해당 기능을 수행.

public class SplashActivity extends Activity {
  BillingModule billingModule; 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    ...
    billingModule = new BillingModule(this);
    billing.initBillingProcessor(); 
    // 광고 제거 구매 내역이 있는지 확인 후, 있다면 배너 광고나 전면 광고가 보이지 않도록 처리한다.
    ...
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
   billingModule.releaseBillingProcessor();
  }
}

광고 제거를 구매할 수 있는 액티비티에서는 다음을 수행해준다.

public class PurchaseActivity extends Activity {
  private BillingProcessor mBillingProcessor;
  private BillingModule billingModule;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    ...
    billingModule = new BillingModule(this);
    billingModule.initBillingProcessor();
    mBillingProcessor = billingModule.getBillingProcessor();
    ...
  }

  ...

  private void purchaseProduct() { // 아이템 구매 요청
    billingModule.purchaseProduct();
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(mBillingProcessor.handleActivityResult(requestCode, resultCode, data)) {
      if(resultCode == RESULT_OK) {
        아이템 구매가 성공했을 경우 처리
      }
    }
  }
}

이 라이브러리를 만들어주신 분에게 진심으로 감사드리며..까먹지 말자 ^.,^

Posted by 홍규홍규
안드로이드2018. 12. 10. 16:09

파이어 베이스 가입 및 앱 추가 과정은 구글 검색하면 수도 없이 많아서 생략..귀찮은 건 안 비밀..

안드로이드 스튜디오에서 직접 하거나 아래 url에서 가입 및 세팅.

https://console.firebase.google.com/?hl=ko


기존 파이어베이스를 이용한 방식은 FirebaseInstanceIdService와 FirebaseMessagingService를 상속한

두 개의 클래스를 가지고 구현하였는데 현재는 FirebaseInstanceIdService가 deprecated되었다.


따라서 FirebaseMessagingService만을 활용하여 구현해보고자 한다.

프로젝트 단위 build.gradle에 다음을 추가한다.

buildscript {
  dependencies {
    ...
    classpath 'com.google.gms:google-services:4.0.1'
  }
}

앱 단위 build.gradle에 다음을 추가한다. 나의 경우 하단에 com.google.gms.google-services도 추가해야

정상적으로 구현이 되었다.

dependencies {
  ...
  implementation 'com.google.firebase:firebase-messaging:17.3.4'
  ...
}
apply plugin: 'com.google.gms.google-services'

주의할 것은 appli plugin: 'com.google.gms.google-services' 를 추가할 경우 play-services-ads를 사용하고 있다면

17.1.2 버전을 사용할 경우 오류가 발생한다. 따라서 버전을 17.1.1로 낮춰야 한다.

implementation 'com.google.android.gms:play-services-ads:17.1.1'

AndroidManifest.xml에도 추가해야 할 것이 있다.

<service
    android:name=".MyFirebaseMessagingService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>

이제 준비가 끝난 거 같다. 맞나? 


다음으로 FirebaseMessagingService를 상속받는 클래스를 만든다.

public class MyFirebaseMessagingService extends FirebaseMessagingService {
  @Override
  public void onMessageReceived(RemoteMessage remoteMessage) {
    if(remoteMessage.getData() == null)
      return;
    sendNotification(remoteMessage.getData().get("title"), remoteMessage.getData().get("content"));
  }
 
  private void sendNotification(String title, String content) {
    if(title == null)
      title = "기본 제목";

    Intent intent = new Intent(this, MainActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
    Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtonManager.TYPE_NOTIFICATION);

    // 오레오(8.0) 이상일 경우 채널을 반드시 생성해야 한다.
    final String CHANNEL_ID = "채널ID";
    NotificationManager mManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      final String CHANNEL_NAME = "채널 이름";
      final String CHANNEL_DESCRIPTION = "채널 Description";
      final int importance = NotificationManager.IMPORTANCE_HIGH;

      // add in API level 26
      NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, importance);
      mChannel.setDescription(CHANNEL_DESCRIPTION);
      mChannel.enableLights(true);
      mChannel.enableVibration(true);
      mChannel.setVibrationPattern(new long[]{100, 200, 100, 200});
      mChannel.setSound(defaultSoundUri, null);
      mChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
      mManager.createNotificationChannel(mChannel);
    }
  
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);
    builder.setAutoCancel(true);
    builder.setDefaults(Notification.DEFAULT_ALL);
    builder.setWhen(System.currentTimeMillis());
    builder.setSmallIcon(R.mipmap.ic_launcher);
    builder.setContentText(content);
    if(Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
      // 아래 설정은 오레오부터 deprecated 되면서 NotificationChannel에서 동일 기능을 하는 메소드를 사용.
      builder.setContentTitle(title);
      builder.setSound(defaultSoundUri);
      builder.setVibrate(new long[]{500, 500});
    }

    mManager.notify(0, builder.build());
  }

  @Override
  public void onNewToken(string s) {
    super.onNewToken(s);
    /* 
     * 기존의 FirebaseInstanceIdService에서 수행하던 토큰 생성, 갱신 등의 역할은 이제부터 
     * FirebaseMessaging에 새롭게 추가된 위 메소드를 사용하면 된다. 
     */
  }
}


이정도면 대충 정리가 되었으려나. 급하게 작성하느라 제대로 했는지 모르겠다.

까먹지 말자 좀 ... !



Posted by 홍규홍규
안드로이드2018. 11. 27. 15:38

예외상황을 만들어두어 발생 시 토스트를 띄우도록 구현해놨는데 토스트가 안 뜨는 문제가 발생했다.

로그캣을 보니 아래와 같은 메시지를 발견할 수 있었다.


Suppressing toast from package [packagename] by user request.


애플리케이션 관리에서 알림을 차단해버렸기 때문에 발생한 거였다.

누구야 이거 한 사람 ㅡㅡ+

Posted by 홍규홍규
안드로이드2018. 10. 26. 13:58

간단하게 다음과 같다.

...
String drawablePath = getURLForResource(R.drawable.test_01);
...
}

private String getURLForResource(int resId) {
  return Uri.parse("android.resource://" + R.class.getPackage().getName() + "/" + resId).toString();
}

Glide 같은 라이브러리를 쓸 때 웹 이미지가 아닌 내부 이미지를 사용할 경우가 있다.

그럴 때 사용하면 유용할 듯 싶다.

Posted by 홍규홍규
안드로이드2018. 8. 16. 15:36

API 26(Oreo)부터 Vibrator 클래스의 vibrate() 메소드가 deprecated 되었다.

레퍼런스 문서를 보면 대신 VibrationEffect가 추가되었다. 


다음과 같이 사용하면 되겠다.

Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);

if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1)
  vibrator.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE));
  // vibrator.vibrate(VibrationEffect.createWaveform(pattern, VibrationEffect.DEFAULT_AMPLITUDE));
else
  vibrator.vibrate(500);
  // vibrator.vibrate(pattern, repeat); // 0은 무한반복, -1은 반복 없음.

이상 끗~!

Posted by 홍규홍규
안드로이드2018. 8. 1. 11:42

6. 각각의 게시글에 대한 레이아웃 작성하기 - listview.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:layout_marginBottom="10dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/title"
            android:layout_width="250dp"
            android:layout_height="match_parent"
            android:gravity="center_vertical"
            android:textColor="#666"
            android:paddingLeft="20dp"
            android:text=""
            android:textSize="15dp"/>

        <TextView
            android:id="@+id/date"
            android:layout_width="90dp"
            android:layout_height="match_parent"
            android:gravity="center|right"
            android:textColor="#999"
            android:text=""
            android:textSize="13dp"/>

    </LinearLayout>

</LinearLayout>


7. Adapter 클래스 생성

public class BoardAdapter extends BaseAdapter {
  private Context context;
  private List<Board> boardList;

  public BoardAdapter(List<Board> boardList) {
    this.boardList = boardList;
  }

  @Override
  public int getCount() {
    return boardList.size();
  }

  @Override
  public Object getItem(int i) {
    return boardList.get(i);
  }

  @Override
  public long getItemId(int i) {
    return i;
  }

  @Override
  public View getView(int i, View view, ViewGroup viewGroup) {
    final int pos = i; // ListView 위치(첫 번째 = 0)
    context = viewGroup.getContext();

    if(view == null) {
      LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      if(inflater != null)
        view = inflater.inflate(R.layout.listview, viewGroup, false); 
    }

    TextView title = view.findViewById(R.id.title),
             date = view.findViewById(R.id.date);

    Board board = boardList.get(i);

    title.setText(board.getTitle());
    date.setText(board.getCreateDate());

    view.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        // 게시글 터치 시 내용 보여주는 다이얼로그 띄우기
        showContent(boardList.get(pos).getTitle(), boardList.get(pos).getContent()); 
      }
    });

    return view;
  }

  private void showContent(String title, String content) {
    final Dialog dialog = Util.getCustomDialog(context, R.layout.content_dialog); 
    // 8-9번 참고
    dialog.setCancelable(false);
    dialog.show();
    TextView dTitle = dialog.findViewById(R.id.dialog_title),
             dContent = dialog.findViewById(R.id.dialog_content);
    ImageView dClose = dialog.findViewById(R.id.dialog_close_img);
    Button bClose = dialog.findViewById(R.id.dialog_close);
    dTitle.setText(title);
    dContent.setText(content);
    dContent.setMovementMethod(new ScrollingMovementMethod());
    dClose.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        dialog.dismiss();
      }
    });
    bClose.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        dialog.dismiss();
      }
    });
  }
}


8. 내용을 보여줄 커스텀 다이얼로그 레이아웃 작성

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="300dp"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:gravity="center"
    android:background="@drawable/custom_dialog_bg"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/dialog_title"
            android:layout_width="250dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="6dp"
            android:layout_marginLeft="5dp"
            android:layout_marginTop="6dp"
            android:padding="7dp"
            android:text=""
            android:textColor="#666"
            android:textSize="14dp" />

        <ImageView
            android:id="@+id/dialog_close_img"
            android:layout_width="22dp"
            android:layout_height="22dp"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="10dp"
            android:contentDescription="@null"
            android:src="@drawable/btn_close" />
        
    </LinearLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#EEE" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/dialog_content"
            android:layout_width="match_parent"
            android:layout_height="290dp"
            android:lineSpacingExtra="4dp"
            android:padding="10dp"
            android:scrollbars="vertical"
            android:scrollbarSize="3dp"
            android:text=""
            android:textColor="#555"
            android:textSize="14dp" />
        
    </LinearLayout>

    <LinearLayout
        android:id="@+id/layout_dialog_close"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal">

        <Button
            android:id="@+id/dialog_close"
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:layout_gravity="center"
            android:background="@drawable/btn_style_blue"
            android:text="@string/name_close"
            android:textColor="#FFF"
            android:textSize="16dp" />
        
    </LinearLayout>

</LinearLayout>


- 화면은 아래와 같다.



9. Util.getCustomDialog 작성

public class Util {
  // ...
  public static Dialog getCustomDialog(Context context, int layout) {
    Dialog dialog = new Dialog(context, R.style.FullHeightDialog);
    dialog.setContentView(layout);
    return dialog;
  }
  // ...
}


※ FullHeightDialog - styles.xml

  <!-- ... -->
  <style name="FullHeightDialog" parent="android:style/Theme.Dialog">
      <item name="android:windowNoTitle">true</item>
      <item name="android:windowBackground">@android:color/transparent</item>
  </style>
  <!-- ... -->


- 실제 화면


Posted by 홍규홍규
안드로이드2018. 8. 1. 11:17

- 안드로이드에서 해당 페이지로부터 데이터를 가져오는 작업.

3-1. build.gradle에 Volley 추가

implementation 'com.android.volley:volley:1.1.1'


3-2. 게시판 리스트를 출력할 Layout 작성 - activity_board.xml

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

    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:background="#FFF"
        android:textSize="20dp"
        android:textColor="#666"
        android:text="게시글 목록"/>

    <ImageView
        android:id="@+id/img_close"
        android:layout_width="28dp"
        android:layout_height="28dp"
        android:src="@drawable/btn_close"
        android:layout_marginTop="11dp"
        android:layout_marginEnd="18dp"
        android:layout_alignParentEnd="true"/>

    <View
        android:id="@+id/viewline_01"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_below="@id/title"
        android:background="#EEE" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_below="@id/viewline_01">

        <ListView
            android:id="@+id/listview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:dividerHeight="1dp"
            android:divider="#EEE"
            android:background="@drawable/custom_bg_01"/>

    </LinearLayout>

    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:alpha="0.3"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:visibility="gone" />

</RelativeLayout>


※ 화면은 다음과 같다.




4. Volley 객체를 생성한다. (싱글톤 패턴 적용)

public class MyVolley {
  private static MyVolley instance;
  private RequestQueue requestQueue;

  public static MyVolley getInstance(Context context) {
    if(instance == null)
      instance = new MyVolley(context);
    return instance;
  }

  private MyVolley(Context context) {
    requestQueue = Volley.newRequestQueue(context);
  }

  public RequestQueue getRequestQueue() {
    return requestQueue;
  }
}


4.서버사이드 VO와 동일한 Board VO를 생성해준다. (동일하므로 생략)


5. Volley 객체를 이용하여 게시판 데이터를 가져온다.

public class BoardActivity extends Activity {
  private Context mContext
  private ListView mListView;
  private ProgressBar progressBar;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mContext = this;
    setContentView(R.layout.activity_board);    

    mListView = findViewById(R.id.listview);
    progressBar = findViewById(R.id.progressBar);
    ImageView btnClose = findViewById(R.id.img_close);
    btnClose.setOnClickListener(new View.OnClickListener() { // X 버튼
      @Override
      public void onClick(View view) {
        finish();
      }
    });

    getBoardData(); // 게시판 데이터 가져오기
  }
  
  private void setProgressBar(int visibility) {
    progressBar.setVisibility(visibility);
  }

  private void getBoardData() {
    setProgressBar(View.VISIBLE);
    final String url = getString(R.string.url_get_board); // 서버사이드 페이지 웹 주소 
    RequestQueue queue = MyVolley.getInstance(mContext).getRequestQueue();
    JsonObjectRequest jsonRequest = new JsonObjectRequest(Request.Method.GET, url, new JSONObject(),
                                                          successListener(), errorListener());
    queue.add(jsonRequest);
  }
 
  private void parsingJSONData(String data) {
    List<Board> mList = new ArrayList<>();
    try {
      JSONArray jArray = new JSONArray(data);
      for(int i = 0; i < jArray.length(); i++) {
        Board board = new Board();
        JSONObject jObject = jArray.getJSONObject(i);
        board.setNno(Integer.parseInt(jObject.getString("nno")));
        board.setTitle(jObject.getString("title"));
        board.setContent(jObject.getString("content"));
        board.setCreateDate(jObject.getString("createDatet"));
        mList.add(board );
      }
      mListView.setAdapter(new BoardAdapter(mList));

    } catch(JSONException e) {
      e.printStackTrace();
    }
  }

  private Response.Listener<JSONObject> successListener() {
    return new Response.Listener<JSONObject>() {
      @Override
      public void onResponse(JSONObject response) {
        setProgressBar(View.GONE);
        String result = null;
        try {
          result = response.getString("data");
        } catch(JSONException e) {
          e.printStackTrace();
        }
        parsingJSONData(result);
      }
    };
  }

  private Response.ErrorListener errorListener() {
    return new Response.ErrorListener() {
      @Override
      public void onErrorResponse(VolleyError error) {
        // Util.showToast(mContext, getString(R.string.msg_network_error_01));
        // 에러 메시지 작성
      }
    };
  }
}


Posted by 홍규홍규