728x90

안드로이드 PUSH 서버, 메신저 만드는 방법을 검색해보다가 알게된 내용을 적어둔다.


아파치 웹서버

nginx

  • 쓰레드/프로세스 기반 구조
  • 클라이언트의 요청이 들어오면 쓰레드를 생성
  • 사용자가 많으면 많은 쓰레드 생성 ==> 메모리 및 CPU 낭비, Context-Switching Overhead 발생
  • 비동기(async) 이벤트(ioctl, send, recv, epoll)기반 구조
  • 다수의 연결을 효과적으로 처리
  • 대부분의 코어 모듈이 Apache보다 적은 리소스로 더 빠르게 동작


안드로이드 앱의 구성 요소와 데이터 전달




  • 제작 : 기획부터 개발까지 하나의 서비스를 온전히 만들어내는 것
  • 개발 : 결정된 기획과 디자인을 바탕으로 소프트웨어를 구현하는 것
  • 고객이 불편한 부분을 이해하고 체감해야 한다.
  • UI 쓰레드는 UI만 처리하게 하라.
  • 다양한 화면 해상도를 지원하라
  • 화면 해상도에 맞게 다양한 리소스를 제공하라.
  • 네트워크는 항상 느리다고 가정하라.
  • 다양한 하드웨어에 대비하라. (터치스크린, 키보드, 센서)
  • 좋은 코드를 작성하라 (CPU 사용량 낮고, 메모리 사용량 낮고, 가독성은 높게)
    - 필요한 기능을 최대한 간결히 작성하라
    - 클래스/메소드/변수 이름을 명확히 하라.
    - 코드를 어렵게/복잡하게 작성하지 마라.
  • 객체는 최대한 적게 생성하라
    - static 메소드를 사용해서 객체 생성을 줄일 수 있다.
    - 반복문에서는 객체 생성을 줄여야 한다.
    - 객체를 재사용한다.
  • 불필요한 코드를 제거하라
    - 쓸데없는 캐스팅을 줄여야 한다.
  • 메소드는 정적(static) 메소드로 선언하라.
  • 클래스 내에서는 Getter 와 Setter 를 사용해서 변수에 접근하지 말라.
  • 값이 고정된 변수는 상수로 선언하라.
  • enum은 되도록 사용하지 말아라.
  • 부동소수형은 되도록 사용하지 말아라.
    정수형이 부동소수형보다 일반적으로 2배 더 빠르다.
  • 네티브 코드는 되도록 사용하지 말아라.
    - 디바이스에 따라 호환되지 않을 수 있다.
    - 디버깅을 하는 것이 쉽지 않다.
  • 자바의 코드 노하우가 반드시 안드로이드의 코드 노하우는 아니다.
    - 가독성을 위해 중첩 클래스를 사용하지 마라.
    - 클래스는 되도록 작게 생성하라.
  • 버전은 어떤 범위까지 지정할 것인가?
    - 지원하려는 플랫폼 구버전의 범위를 지정하는 것은 재량이지만,
      최신 버전의 플랫폼을 지원하는 것은 기본으로 한다.
  • 오픈소스로 공개된 많은 커스텀된 GUI 컴포넌트 코드들이 있으며, 이를 구글 검색 등을 통해 쉽게 찾아낼 수 있다. https://github.com/wasabeef/awesome-android-ui
  • 안드로이드 내부에서 기본 이미지를 제공하지만 매우 제한적이다.
    구글이 Material Design 풍의 아이콘 셋들을 오픈소스로 공개했다.
    https://github.com/google/material-design-icons/releases
  • 안드로이드 앱 개발할 시에는 다양한 버전에서의 테스트가 필요한데, Genymotion을 이용하면 쉽게 해결할 수 있다. https://www.genymotion.com/
  • 출시할 때에는 꼭 앱이 디버깅용이 아닌 출시용으로 빌드가 됐는지 확인하고, 서버도 디버깅 모드로 배포되었는지 여부를 확인한다.
  • 모든 준비가 완료되었다면, Play 스토어 등과 같은 모바일 어플리케이션 마켓 플레이스에 배포를 진행하면 된다.


블로그 이미지

Link2Me

,
728x90

// Back 버튼을 눌러도 종료되지 않게 처리
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if( keyCode == KeyEvent.KEYCODE_BACK ) {
        return true;
    }       
    return super.onKeyDown(keyCode, event);
 }


// Back 버튼을 누르면 어플 종료여부 확인 처리
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if( keyCode == KeyEvent.KEYCODE_BACK ) {
        new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert).setTitle("Quit").setMessage("어플을 종료하시겠습니까?").setPositiveButton("Yes", new DialogInterface.OnClickListener() {
            @Override
            public void onClick( DialogInterface dialog, int which) {
                moveTaskToBack(true); // 본 Activity finish후 다른 Activity가 뜨는 걸 방지.
                finish();
                //application 프로세스를 강제 종료
                android.os.Process.killProcess(android.os.Process.myPid() );
            }
        }).setNegativeButton( "No", null ).show();
        return true;
    }
    return super.onKeyDown(keyCode, event);
}




블로그 이미지

Link2Me

,
728x90

Android Studio 에서 연락처 저장하는 기능으로 구현에 필요한 내용은 모두 적어둔다.

서버에서 읽어온 사진 이미지까지 저장할 수 있도록 했다.

서버에서 사진 이미지를 읽어오고 나면 Cache에 저장했으므로

MemoryCache memoryCache = new MemoryCache();
Bitmap cachedImage = memoryCache.get(strPhoto);

를 했는데도 불구하고 null 값이 나온다.


연락처(Contacts)에 전화번호를 저장하는 기능은 검사하여 있으면 삭제후 다시 신규 저장하는 방식으로 구현되어 있는데, 이런 로직보다는 데이터가 있으면 비교하여 달라진 것이 있으면 Update 하고 동일하면 패스하는 로직으로 구현하는 것이 바람직하다. 이런 구현방식은 개발자의 몫이기 때문에 여기에는 적어놓지 않는다.


import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.Context;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.util.Log;
import android.widget.Toast;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;

public class Contacts {
    public Contacts(){
        
    }
    
     // 전화번호부에 존재하는 데이터인지 여부 검사
    // 표시 이름과 휴대폰번호를 기준으로 ContactId 구하기
    public long
ContactsIDExistCheck(ContentResolver cr, String display_name, String number) {
        long rawContactId = -1;

        Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
        String[] projection = { PhoneLookup._ID, PhoneLookup.TYPE, PhoneLookup.DISPLAY_NAME };
        Cursor cursor = null;
        try {
            cursor = cr.query(contactUri, projection, null, null, null);
            if (cursor.moveToFirst()) {
                do {
                    String PhoneName = cursor.getString(cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME));
                    if (display_name.equals(PhoneName)) {
                        rawContactId = cursor.getLong(cursor.getColumnIndex(PhoneLookup._ID));
                        System.out.println(" ContactId = " + rawContactId + " 성명 : " + PhoneName);
                    }
                } while (cursor.moveToNext());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        return rawContactId;
    }
   

    public void ContactsIDdelete(ContentResolver cr, Context context, Integer contactId){
        // 전화번호부 삭제
        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
           
        //remove contact from raw_contact table
        ops.add(ContentProviderOperation.newDelete(ContactsContract.RawContacts.CONTENT_URI).
        withSelection(ContactsContract.RawContacts.CONTACT_ID + "=?", new String[]{String.valueOf(contactId)}).
        build());              
               
        try {
            cr.applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public void ContactsIDinsert(ContentResolver cr, Context context, String strName, String strMobileNO) {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
        ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
                .build());

        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, strName)
                .build());

        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
                .withValue(Phone.NUMBER, strMobileNO)
                .withValue(Phone.TYPE, Phone.TYPE_MOBILE)
                .build());

        try {
            cr.applyBatch(ContactsContract.AUTHORITY, ops);
            Toast.makeText(context, "연락처가 저장되었습니다.", Toast.LENGTH_LONG).show();
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        } catch (Exception e) {
            Log.e("ContactsAdder", "Exceptoin encoutered while inserting contact: " + e);
        }
           
    }
    
    public void ContactsIDinsert(ContentResolver cr, Context context, String strName, String strMobileNO, String strOfficeNO, String strEmail, String strPhoto) {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
        ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
                .build());

        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, strName)
                .build());

        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
                .withValue(Phone.NUMBER, strMobileNO)
                .withValue(Phone.TYPE, Phone.TYPE_MOBILE)
                .build());

        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
                .withValue(Phone.NUMBER, strOfficeNO)
                .withValue(Phone.TYPE, Phone.TYPE_WORK)
                .build());

        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, Email.CONTENT_ITEM_TYPE)
                .withValue(Email.DATA, strEmail)
                .withValue(Email.TYPE, Email.TYPE_WORK)
                .build());

        MemoryCache memoryCache = new MemoryCache();
        Bitmap cachedImage = memoryCache.get(strPhoto);
        System.out.println("cachedImage ===" + cachedImage);
        if (cachedImage != null) {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            cachedImage.compress(Bitmap.CompressFormat.JPEG, 60, bos);

            byte[] bytes = bos.toByteArray();

            ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                    .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                    .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
                    .withValue(ContactsContract.CommonDataKinds.Photo.DATA15, bytes)
                    .build());
            try {
                bos.flush();
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        try {
            cr.applyBatch(ContactsContract.AUTHORITY, ops);
            Toast.makeText(context, "연락처가 저장되었습니다.", Toast.LENGTH_LONG).show();
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        } catch (Exception e) {
            Log.e("ContactsAdder", "Exceptoin encoutered while inserting contact: " + e);
        }          
    }   
}


메모리 캐쉬 파일을 수정했다.

import android.graphics.Bitmap;
import android.util.Log;

import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

public class MemoryCache {
    private static final String TAG = "MemoryCache";
    public static  Map<String, Bitmap> cache= Collections.synchronizedMap(
            new LinkedHashMap<String, Bitmap>(10,1.5f,true));//Last argument true for LRU ordering
    private long size=0;//current allocated size
    private long limit=1000000;//max memory in bytes

    public MemoryCache(){
        //use 25% of available heap size
        setLimit(Runtime.getRuntime().maxMemory()/4);
    }

    public void setLimit(long new_limit){
        limit=new_limit;
        Log.i(TAG, "MemoryCache will use up to "+limit/1024./1024.+"MB");
    }

    public static Bitmap get(String id){
        try{
            if(!cache.containsKey(id))
                return null;
            return cache.get(id);
        }catch(NullPointerException ex){
            ex.printStackTrace();
            return null;
        }
    }

    public void put(String id, Bitmap bitmap){
        try{
            if(cache.containsKey(id))
                size-=getSizeInBytes(cache.get(id));
            cache.put(id, bitmap);
            size+=getSizeInBytes(bitmap);
            checkSize();
        }catch(Throwable th){
            th.printStackTrace();
        }
    }

    private void checkSize() {
        Log.i(TAG, "cache size="+size+" length="+cache.size());
        if(size>limit){
            Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator();//least recently accessed item will be the first one iterated
            while(iter.hasNext()){
                Entry<String, Bitmap> entry=iter.next();
                size-=getSizeInBytes(entry.getValue());
                iter.remove();
                if(size<=limit)
                    break;
            }
            Log.i(TAG, "Clean cache. New size "+cache.size());
        }
    }

    public void clear() {
        try{
            //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
            cache.clear();
            size=0;
        }catch(NullPointerException ex){
            ex.printStackTrace();
        }
    }

    long getSizeInBytes(Bitmap bitmap) {
        if(bitmap==null)
            return 0;
        return bitmap.getRowBytes() * bitmap.getHeight();
    }
}


MainActivity.java 파일 내에 ListViewAdapter 부분

 private class ListViewAdapter extends BaseAdapter {
    ImageLoader imageLoader;
    Context context;

    public ListViewAdapter(Context context) {
        this.context = context;
        imageLoader = new ImageLoader(context);
    }

    @Override
    public int getCount() {
        return arrayList.size(); // 데이터 개수 리턴
    }

    @Override
    public Object getItem(int position) {
        return arrayList.get(position);
    }

    // 지정한 위치(position)에 있는 데이터 리턴
    @Override
    public long getItemId(int position) {
        return position;
    }

    // position에 위치한 데이터를 화면에 출력하는데 사용될 View를 리턴
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final ViewHolder viewHolder;
        final Context context = parent.getContext();

        // 화면에 표시될 View
        if(convertView == null){
            viewHolder = new ViewHolder();

            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.address_item,parent,false);

            convertView.setBackgroundColor(0x00FFFFFF);
            convertView.invalidate();

            // 화면에 표시될 View 로부터 위젯에 대한 참조 획득
            viewHolder.profile_Image = (ImageView) convertView.findViewById(R.id.profile_Image);
            viewHolder.tv_name = (TextView) convertView.findViewById(R.id.child_name);
            viewHolder.tv_mobileNO = (TextView) convertView.findViewById(R.id.child_mobileNO);
            viewHolder.tv_officeNO = (TextView) convertView.findViewById(R.id.child_officeNO);
            viewHolder.child_btn = (ImageView) convertView.findViewById(R.id.child_Btn);

            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        // PersonData 에서 position 에 위치한 데이터 참조 획득
        final Address_Item addressItem = arrayList.get(position);

        // 아이템 내 각 위젯에 데이터 반영
        // 선택된 row의 데이터를 표시한다. 표시될 view는 address_itemm.xml 의 각 항목을 이용하여 표시한다.
        //System.out.println("imageurl==" + addressItem.getProfile_image());
        if(addressItem.getProfile_image().equals("")){
            final Bitmap Base_Profile = PHPComm.autoresize_decodeResource(getResources(), R.mipmap.photo_base, 160);
            viewHolder.profile_Image.setImageBitmap(Base_Profile);
        } else {
            String photoURL = Value.IPADDRESS + "/photos/" + addressItem.getProfile_image();
            imageLoader.DisplayImage(photoURL, viewHolder.profile_Image);
        }

        viewHolder.tv_name.setText(addressItem.getName());
        viewHolder.tv_mobileNO.setText(PhoneNumberUtils.formatNumber(addressItem.getMobileNO()));
        viewHolder.tv_officeNO.setText(PhoneNumberUtils.formatNumber(addressItem.getOfficeNO()));

        final String[] items ={"휴대폰 전화걸기","사무실전화 걸기", "연락처 저장"};
        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle("해당작업을 선택하세요");
        builder.setItems(items, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                //Toast.makeText(context, items[which] + "선택했습니다.", Toast.LENGTH_SHORT).show();
                switch (which){
                    case 0:
                        if(addressItem.getMobileNO().length() ==0){
                            Toast.makeText(context, "전화걸 휴대폰 번호가 없습니다.",Toast.LENGTH_SHORT).show();
                            break;
                        }
                        AlertDialog dialog1 = new AlertDialog.Builder(context)
                                .setTitle(addressItem.getName())
                                .setMessage(PhoneNumberUtils.formatNumber(addressItem.getMobileNO()) + " 통화하시겠습니까?")
                                .setPositiveButton("예",
                                        new DialogInterface.OnClickListener() {
                                            public void onClick(DialogInterface dialog, int which) {

                                                Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + PhoneNumberUtils.formatNumber(addressItem.getMobileNO())));
                                                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                                if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
                                                   // TODO: Consider calling
                                                   if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
                                                       requestPermissions(new String[]{Manifest.permission.CALL_PHONE},1000);
                                                   }

                                                   return;
                                                }
                                                startActivity(intent);
                                            }
                                        })
                                .setNegativeButton(
                                        "아니오",
                                        new DialogInterface.OnClickListener() {
                                            public void onClick(DialogInterface dialog,int which) {
                                                dialog.dismiss();
                                            }
                                        }).create();
                        dialog1.show();
                        break;
                    case 1:
                        if(addressItem.getOfficeNO().length() ==0){
                            Toast.makeText(context, "전화걸 사무실 번호가 없습니다.",Toast.LENGTH_SHORT).show();
                            break;
                        }
                        AlertDialog dialog2 = new AlertDialog.Builder(context)
                                .setTitle(addressItem.getName())
                                .setMessage(PhoneNumberUtils.formatNumber(addressItem.getOfficeNO()) + " 통화하시겠습니까?")
                                .setPositiveButton("예",
                                        new DialogInterface.OnClickListener() {
                                            public void onClick(DialogInterface dialog, int which) {

                                                Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + PhoneNumberUtils.formatNumber(addressItem.getOfficeNO())));
                                                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                                if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
                                                    // TODO: Consider calling
                                                    return;
                                                }
                                                startActivity(intent);
                                            }
                                        })
                                .setNegativeButton(
                                        "아니오",
                                        new DialogInterface.OnClickListener() {
                                            public void onClick(DialogInterface dialog,int which) {
                                                dialog.dismiss();
                                            }
                                        }).create();
                        dialog2.show();
                        break;
                    case 2:
                        // 연락처 저장 함수 호출
                        AlertDialog.Builder SaveContact = new AlertDialog.Builder(context);
                        SaveContact.setMessage("전화번호를 저장하시겠습니까?");
                        DialogInterface.OnClickListener save = new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                int rawContactId = 0;
                                Contacts phonebook = new Contacts(); // 전화번호부 객체 생성
                                ContentResolver cr = getContentResolver();
                                String strContactName = addressItem.getName();
                                String strMobileNO = addressItem.getMobileNO();
                                String strofficeNO =addressItem.getOfficeNO();
                                String strEmail ="";
                                String strPhoto ="";
                                if(addressItem.getProfile_image().length()>0){
                                    strPhoto =Value.IPADDRESS + "/photos/" + addressItem.getProfile_image();
                                }
                                //System.out.println("strPhoto ==="+ strPhoto);

                                rawContactId = phonebook.ContactsIDExistCheck(cr, strContactName,strMobileNO);
                                if(rawContactId > 0){
                                    // 기존 전화번호가 존재하면 삭제하고 새로 입력
                                    phonebook.ContactsIDdelete(cr, context, rawContactId);
                                }
                                phonebook.ContactsIDinsert(cr, context, strContactName, strMobileNO, strofficeNO, strEmail, strPhoto);
                            }
                        };

                        DialogInterface.OnClickListener cancel = new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {

                            }
                        };
                        SaveContact.setPositiveButton("저장", save);
                        SaveContact.setNegativeButton("취소", cancel);
                        SaveContact.show();
                        break;
                }
            }
        });
        builder.create();

        viewHolder.child_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                builder.show();
            }
        });

        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(getApplicationContext(), "상세보기를 눌렀습니다 ==="+ addressItem.getUid(), Toast.LENGTH_SHORT).show();
            }
        });

        return convertView;
    }

    // 아이템 데이터 추가를 위한 메소드
    public void addItem(String profile_image, String uid, String name, String mobileNO, String officeNO){
        Address_Item item = new Address_Item();
        item.setProfile_image(profile_image);
        item.setUid(uid);
        item.setName(name);
        item.setMobileNO(mobileNO);
        item.setOfficeNO(officeNO);

        arrayList.add(item);
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == 1000) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(MainActivity.this, "권한 요청을 승인했습니다.", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(MainActivity.this, "권한 요청을 거부했습니다.", Toast.LENGTH_SHORT).show();
            }
        }
    }

}


블로그 이미지

Link2Me

,
728x90

같은 PC에서 Android Studio 와 Eclipse 를 같이 사용하다보니 SDK 를 같이 사용하면 문제가 생기더라.

그래서 SDK 를 각각 설치해서 사용하는데 간혹 Android Studio 에서 만든 예제가 Eclipse 기반 SDK를 사용하는 것이 있는지 헷갈린다.

그래서 아예 경로를 변경해버렸다.





이렇게 변경하면 나중에 백업할 때 파일 용량이 커서 문제가 좀 되기도 한다.


Eclipse 나 Android Studio 모두 설치된 경로를 그대로 백업하고 나중에 같은 경로에 폴더를 설치하면 그냥 동작한다.


블로그 이미지

Link2Me

,