어느날 갑자기 styles.xml 파일의 Theme 부분에서
Cannot resolve symbol 'Theme' 라고 빨간색으로 나오는 이슈가 있었습니다.

이렇게 나오더라도, 빌드도 잘되며 Declaration 잘됩니다.

프로젝트에 아무 영향이 없지만,


찝찝한 마음을 떨쳐버릴수가 없어요. 난 이것을 없애 버려야겠다고 생각했습니다.



우선 구글링을 통해 3가지 공통적인 답을 얻을 수 있었습니다.


1.  menu > File > Sync Prjcet with Gradle files


2. menu > File > Invalidate Caches / Restart ....


3. .idea 폴더 / libraries 폴더 / Gradle__com_android_support_XXXXX.xml 파일 모두 지우기 




저와 같은 경우는 1,2 번은 별다른 효과를 얻지 못했습니다.


3번의 사항에서 파일들을 모두 제거하고,


Sync Prjcet with Gradle files을 실행하고 나니, 


아래와 같이 빨간색으로 된 Cannot resolve symbol 메시지들이 사라진 것을 확인 할 수 있었습니다~~

속이 후련하네요~






Android studio 설정 파일들 저장 위치 

User/사용자이름/라이브러리/Preferences/AndoridStudio3.0



default sdk 저장 위치

User/사용자이름/Android/SDK



studio 3.0 을 업그레이드 하고 나서 보니, 메소드에 이상한 hint가 붙어져 버렸습니다.

때에 따라서 유용할 수도 있겠지만, 저같은 경우는 불편한거 같아요.


메뉴 > Preference > Editor > General > show parameter name hints 의 체크 박스를 해제 합니다.



Assert    : 9777A9

Debug    : 6A98B9

Error      : FF6B68 (기본

Info        : 6A855A

Verbose : BBBBBB (기본)

Warning : BC7739




출처 : https://developers-kr.googleblog.com/2017/04/update-your-app-to-take-advantage-of.html


최신폰의 화면비에서 테스트 하다보니 화면이 짤려나와서 아래 코드를 매니페스트에

추가하였습니다. 화면비가 달라질때마다 이런 코드들이 추가되어야 한다니 여러모로 귀찮은일이네요.


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application>
        <activity/>

        <meta-data android:name="android.max_aspect" android:value="2.1" />
        
    </application>
</manifest>


android canvas 의 onDraw() 내에서

삼각형, 별, 하트 그리기 예제입니다.

Canvas 내 터치 영역에서 각 도형을 새로 그리는 예제도 TouchEvent 안에 적용되어 있습니다.


참고url

http://android-er.blogspot.kr/2014/05/draw-star-on-canvas.html


    


간단히 도형을 선택하는 버튼과 custom view가 정의 됩니다.

activity_main.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">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/bt_triangle"
        android:text="삼각형"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/bt_triangle"
        android:id="@+id/bt_star"
        android:text="별"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/bt_star"
        android:id="@+id/bt_heart"
        android:text="하트"/>

    <poisonrose.myapplication_canvas.MyView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="10dp"
        android:layout_below="@id/bt_triangle"
        android:id="@+id/my_view"/>

</RelativeLayout>



MainActivity.java

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

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

        final MyView my_view = (MyView) findViewById(R.id.my_view);

        Button bt_triangle = (Button) findViewById(R.id.bt_triangle);
        bt_triangle.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                my_view.drawTriangle();
            }
        });
        Button bt_star = (Button) findViewById(R.id.bt_star);
        bt_star.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                my_view.drawStar();
            }
        });
        Button bt_heart = (Button) findViewById(R.id.bt_heart);
        bt_heart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                my_view.drawHeart();
            }
        });
    }
}

MyView.java

생성자에서는 Paint 와 Path를 초기화 합니다.

실제 도형을 그리는 부분은 onDraw내의 canvas.drawPath() 에서 그리며,

포퍼먼스를 고려하여 항상, path의 reset(), close()를 잘 사용하여야 합니다.

코드내에서 보여지는 x, y 값이 선이 시작하는 부분이며,

TouchEvent에서는 현재 터치값을 불러와서 도형을 그리는 형태로 코드를 작성했습니다.

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class MyView extends View {

    Paint m_Paint;
    Path m_Path;
    Canvas m_Canvas;

    enum Mode {
        TRIANGLE,
        STAR,
        HEART
    }

    private Mode mMode;

    private int mViewWidth = 0;
    private int mViewHeight = 0;

    public MyView(Context context) {
        super(context);
        initMyView();
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initMyView();
    }

    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initMyView();
    }

    public void initMyView(){
        m_Paint = new Paint();
        m_Paint.setAntiAlias(true);
        m_Paint.setDither(true);
        m_Paint.setColor(0xFFFF0000);
        m_Paint.setStyle(Paint.Style.STROKE);
        m_Paint.setStrokeJoin(Paint.Join.ROUND);
        m_Paint.setStrokeCap(Paint.Cap.ROUND);
        m_Paint.setStrokeWidth(4);

        m_Path = new Path();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mViewWidth = MeasureSpec.getSize(widthMeasureSpec);
        mViewHeight = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(mViewWidth, mViewHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        m_Canvas = canvas;
        m_Canvas.drawColor(0xFFFFFFFF);

        if(mMode == Mode.HEART) {
            float x = mViewWidth/2;
            float y = mViewHeight/2;
            m_Canvas.rotate(45,x,y);
        }
        // Path 갱신 영역
        m_Canvas.drawPath(m_Path, m_Paint);
    }

    public void drawTriangle() {
        float x = mViewWidth/2;
        float y = mViewHeight/2;
        drawTriangle(x, y);
    }

    public void drawTriangle(float x, float y) {
        mMode = Mode.TRIANGLE;
        int side = 200;  /** 삼각형 크기 */
        int height = 300;
        y = y - height;

        m_Path.reset();

        Point point1_draw = new Point((int)x, (int)y);        // 왼
        Point point2_draw = new Point((int)x-side, (int)y+height);  // 아래
        Point point3_draw = new Point((int)x+side, (int)y+height); // 오른
        m_Path.moveTo(point1_draw.x, point1_draw.y);
        m_Path.lineTo(point2_draw.x, point2_draw.y);
        m_Path.lineTo(point3_draw.x, point3_draw.y);
        m_Path.lineTo(point1_draw.x, point1_draw.y);

        m_Path.close();
        invalidate();
    }

    public void drawStar() {
        float x = mViewWidth/2;
        float y = mViewHeight/2;
        drawStar(x, y);
    }

    public void drawStar(float x, float y) {
        mMode = Mode.STAR;
        int radius = 200;   /** 별 크기 */
        y = y - radius;

        int numOfPt = 5;
        double section = 2.0 * Math.PI/numOfPt;
        int innerRadius = (int) (radius / 2.5);
        m_Path.reset();
        m_Path.moveTo(
                (float)(x + radius * Math.cos(0)),
                (float)(y + radius * Math.sin(0)));
        m_Path.lineTo(
                (float)(x + innerRadius * Math.cos(0 + section/2.0)),
                (float)(y + innerRadius * Math.sin(0 + section/2.0)));
        for(int i=1; i < numOfPt; i++){
            m_Path.lineTo(
                    (float)(x + radius * Math.cos(section * i)),
                    (float)(y + radius * Math.sin(section * i)));
            m_Path.lineTo(
                    (float)(x + innerRadius * Math.cos(section * i + section/2.0)),
                    (float)(y + innerRadius * Math.sin(section * i + section/2.0)));
        }
        m_Path.close();
        invalidate();
    }

    public void drawHeart() {
        float x = mViewWidth/2;
        float y = mViewHeight/2;
        drawHeart(x, y);
    }

    public void drawHeart(float x, float y) {
        mMode = Mode.HEART;
        float length = 200; // 하트 크기

        m_Path.reset();

        m_Path.moveTo(x,y);
        m_Path.lineTo(x-length, y);
        m_Path.arcTo(new RectF(x-length-(length/2),y-length,x-(length/2),y),90,180);
        m_Path.arcTo(new RectF(x-length,y-length-(length/2),x,y-(length/2)),180,180);
        m_Path.lineTo(x,y);

        m_Path.close();
        invalidate();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                touchDraw(x, y);
                break;

            case MotionEvent.ACTION_MOVE:
                touchDraw(x, y);
                break;

            case MotionEvent.ACTION_UP:
                touchDraw(x, y);
                break;
        }
        return true;
    }

    private void touchDraw(float x, float y) {
        if(mMode == Mode.TRIANGLE) {
            drawTriangle(x, y);
        } else if(mMode == Mode.STAR) {
            drawStar(x, y);
        } else if(mMode == Mode.HEART) {
            drawHeart(x, y);
        }
    }
}


ContentProvider 기능이 필요해서 가져다 사용 하려는데,

현재 검색되는 코드들은 대부분 되는 것들이 없어서 (코드 자체로는 전혀 문제가 없었지만 추가사항이 있어서..) 코드 공유 합니다.


기본적인 설명으로는 여기를 

https://developer.android.com/guide/topics/providers/content-provider-creating.html?hl=ko


이외 코드 관련 부분은 아래에서 참고하였습니다.

참고URL : https://www.tutorialspoint.com/android/android_content_providers.htm



주의사항!

studio가 불안정한건지, 아님 저의 툴 설정이 문제인건지, 여러번 빌드시 이전 provider 설정들이 남아 있는건지

정상 동작하지 않던 문제가 있었습니다. 

저같은 경우는 항상 A,B 앱을 uninstall 후에 빌드 시 제대로된 결과을 얻을 수 있었습니다.

(Permission Denial: opening provider com.app.first.myContentProvider from ..... 등등이 나온다면...)



1. A앱 작업 Mainfests (퍼미션을 추가합니다. 프로바이더 내에서도 readPermission과 writePermission , exprted를 명시합니다.)

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.app.first">     <!-- 퍼미션 추가 --> <permission android:name="com.app.first.READ_DATABASE" android:protectionLevel="normal" /> <permission android:name="com.app.first.WRITE_DATABASE" android:protectionLevel="normal" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- 프로바이더 등록 --> <provider android:name=".myContentProvider" android:authorities="com.app.first.myContentProvider" android:exported="true" android:readPermission="com.app.first.READ_DATABASE" android:writePermission="com.app.first.WRITE_DATABASE"/> </application> </manifest>

activity_main.xml (레이아웃 만들기)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context="com.app.first.MainActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="데이터 불러오기"
        android:id="@+id/bt_renew"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:layout_below="@id/bt_renew"
        android:textSize="15sp"
        android:text="Hello World!"
        android:id="@+id/tv_text"/>

</RelativeLayout>

MainActivity.java (메인 화면 처리)

package com.app.first;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    DBHelper mDatabase;

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

        mDatabase = new DBHelper(getBaseContext());

        // 데이터 입력
        mDatabase.setDelete();
        List<ItemRow> mList = new ArrayList<>();
        mList.add(new ItemRow("식사","미역국",5000));
        mList.add(new ItemRow("간식","우유",4000));
        mList.add(new ItemRow("간식","바나나",3000));
        mList.add(new ItemRow("식사","오이",2000));
        mList.add(new ItemRow("식사","당근",1000));
        for(ItemRow item : mList) {
            mDatabase.setItem(item.contents, item.name, item.num);
        }

        Button bt_renew = (Button) findViewById(R.id.bt_renew);
        bt_renew.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 데이터 불러오기
                loadData();
            }
        });
    }

    private void loadData() {
        StringBuilder sb = new StringBuilder();
        List<ItemRow> row = mDatabase.getItem();
        sb.append("Total count : "+row.size()+"\n\n");
        for(ItemRow item : row) {
            sb.append(item.contents+" , "+item.name+" , "+item.num+"\n");
        }
        TextView tv_text = (TextView) findViewById(R.id.tv_text);
        tv_text.setText(sb.toString());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(mDatabase != null)
            mDatabase.close();
    }
}

class ItemRow {
    public String contents;
    public String name;
    public int num;

    public ItemRow(String contents, String name, int num) {
        this.contents = contents;
        this.name = name;
        this.num = num;
    }
}

DBHelper.java (디비 로직 작업)

package com.app.first;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;

import java.util.ArrayList;
import java.util.List;

public class DBHelper extends SQLiteOpenHelper {

    private static final int db_version = 1;					// Database Version
    private static final String DB_FILE_NAME = "UserData.db";

    private static final String [] COLUMNS = {"contents TEXT", "name TEXT", "num INTEGER"};
    public static String TABLE_NAME = "my_table";

    public DBHelper(Context context) {
        // TODO  http://stackoverflow.com/questions/4547461/closing-the-database-in-a-contentprovider
        super(context, DB_FILE_NAME, null, db_version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "create table " + TABLE_NAME +
                " (" + BaseColumns._ID + " integer primary key autoincrement ";
        for (int i = 0; i < COLUMNS.length; i++) {
            sql += ", " + COLUMNS[i];
        }
        sql += " ) ";
        db.execSQL(sql);
    }

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

    public List<ItemRow> getItem() {
        List<ItemRow> list = new ArrayList<>();
        try {
            beginTransaction();
            Cursor c = getAll(TABLE_NAME);
            if (c != null) {
                int total = c.getCount();
                if (total > 0) {
                    c.moveToFirst();
                    while (!c.isAfterLast()) {
                        String contents = c.getString(1);
                        String name = c.getString(2);
                        int num = c.getInt(3);
                        list.add(new ItemRow(contents, name, num));
                        c.moveToNext();
                    }
                }
                c.close();
            }
        } catch (SQLiteException e) {
            e.printStackTrace();
        } finally {
            endTransaction();
        }
        return list;
    }

    public void setItem(String contents, String name, int num) throws SQLiteException{
        ContentValues values = new ContentValues();
        values.put("contents", contents);
        values.put("name", name);
        values.put("num", num);
        insert(TABLE_NAME, values);
    }

    public void setDelete() {
        AllDelete(TABLE_NAME);
    }

    protected Cursor getAll(String tableName) throws SQLiteException {
        return getReadableDatabase().query(tableName, null, null, null, null, null, /*"date desc"*/null);
    }

    protected void beginTransaction() {
        getWritableDatabase().beginTransaction();
    }
    protected void endTransaction() {
        getWritableDatabase().setTransactionSuccessful();   // db 속도 향상
        getWritableDatabase().endTransaction();
    }

    protected void insert(String tableName, ContentValues values) throws SQLiteException {
        getWritableDatabase().insert(tableName, null, values);
    }

    protected void AllDelete(String tableName) throws SQLiteException{
        getWritableDatabase().delete(tableName, null, null);
    }
}

myContentProvider.java (컨텐트프로바이더 내의 쿼리 처리)

package com.app.first; import android.content.ContentProvider; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; import java.util.HashMap; public class myContentProvider extends ContentProvider { private SQLiteDatabase mDatabase; static final String PROVIDER_NAME = "com.app.first.myContentProvider"; private static HashMap<String, String> STUDENTS_PROJECTION_MAP; static final int GET_ALL = 1; static final int INSERT = 2; static final int UPDATE = 3; static final int DELETE = 4; static final UriMatcher uriMatcher; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(PROVIDER_NAME, "getAll", GET_ALL); uriMatcher.addURI(PROVIDER_NAME, "insert", INSERT); } @Override public boolean onCreate() { DBHelper dbHelper = new DBHelper(getContext()); mDatabase = dbHelper.getWritableDatabase(); return (mDatabase == null)? false:true; } @Nullable @Override public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { Log.d("test","uri : "+uri); SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables("my_table"); //switch (uriMatcher.match(uri)) { // case STUDENTS: // qb.setProjectionMap(STUDENTS_PROJECTION_MAP); // break; // case STUDENT_ID: // qb.appendWhere( _ID + "=" + uri.getPathSegments().get(1)); // break; // default: // } qb.setProjectionMap(STUDENTS_PROJECTION_MAP); if (sortOrder == null || sortOrder == ""){ sortOrder = /*NAME*/"contents"; } Cursor c = qb.query(mDatabase, projection, selection, selectionArgs,null, null, sortOrder); c.setNotificationUri(getContext().getContentResolver(), uri); return c; } @Nullable @Override public String getType(@NonNull Uri uri) { return null; } @Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { return null; } @Override public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { return 0; } @Override public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { return 0; } }


2. B앱 Mainfests (퍼미션 설정을 추가합니다.)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.app.second">

    <!-- 퍼미션 설정 -->
    <uses-permission android:name="com.app.first.READ_DATABASE" />
    <uses-permission android:name="com.app.first.WRITE_DATABASE" />
    <!-- 퍼미션 설정 -->

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.app.second.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:id="@+id/text"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>
MainActivity.java (A앱의 myContentProvider에 쿼리를 날려 데이터를 가져옵니다.)
package com.app.second;

import android.database.Cursor;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    String authority = "com.app.first.myContentProvider";

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

        Cursor c = getContentResolver().query(Uri.parse("content://"+authority+"/getdataall"), null, null, null, null);
        if(c == null)
            return;
        Log.e("test","aaabbb "+c.getCount());

        StringBuilder aa = new StringBuilder();
        while(c.moveToNext()) {
            String str = c.getLong(0) + " , " + c.getString(1)+" , "+c.getString(2)+" , "+c.getInt(3);
            System.out.println(str);
            aa.append(str+"\n");
        }
        c.close();

        TextView text = (TextView) findViewById(R.id.text);
        text.setText(aa);
    }
}



3. 결과 화면 


A앱                                                         B앱

    


기본적으로 SearchView 를 사용 할 경우에는 (그림과 같은) Done 버튼이 정삭적으로 사용이 가능하지만

이 ActionBar의 경우는 여러가지 처리를 위해 커스텀으로 만들어졌습니다.

그래서 Done 버튼의 이벤트를 받기 위해서는 별도의 작업을 해줘야 사용이 가능합니다.



EditText (최신 대응은 AppCompatEditText) 를 상속받아 별도의 클래스를 만들어 줍니다. 

public class CustomEditText extends AppCompatEditText {

    public CustomEditText(Context context) {
        super(context);
    }

    public CustomEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
        InputConnection conn = super.onCreateInputConnection(outAttrs);
        outAttrs.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
        return conn;
    }
}


레이아웃 xml 에서 커스텀 eidtText를 정의합니다.

<com.myApplication.CustomEditText
	android:id="@+id/search_view"
	android:layout_width="match_parent"
	android:layout_height="?attr/actionBarSize"
	android:layout_weight="1"
	android:background="@android:color/transparent"
	android:gravity="center_vertical"
	android:hint="@string/txt_search"
	android:imeOptions="actionSearch"
	android:maxLines="1"
	android:paddingLeft="2dp"
	android:textColor="@color/colorActionBar"
	android:textColorHint="@color/colorActionBar" />


마지막으로 Java 코드 내에서 

EditText search_view = (EditText) findViewbyId(R.id.search_view);
search_view.setOnEditorActionListener(new TextView.OnEditorActionListener() {
	@Override
	public boolean onEditorAction(TextView textView, int keyCode, KeyEvent event) {
		Log.e("test","keyEvent "+keyCode);
		// TODO :: work for
		if(keyCode == event.KEYCODE_HOME){
			loadAddress();
		}
		return false;
	}
});


개발할때 간단한 아이콘은 어디서 긁어다 쓰고 싶지만 저작권 문제도 있고, 

잉크스페이스 같은 툴로 svg 파일로 시도를 해보았지만

내용들이 전부 base64 로 인코딩 되어있어 xml 로 사용하지 못하였습니다. 

그래서 찾다보니 이런게 있어서 공유합니다.  


참고 url

https://developers-kr.googleblog.com/2015/10/androidstudio14.html



1. File > New > Vector Asset 메뉴로 이동합니다.




2. icon 옆에 캐릭터를 클릭을 하면 3번과 같이 사용 가능 리스트가 나옵니다.




3. 원하는 이미지를 선택합니다.


완성


깔끔하게 만들어진 벡터이미지를 확인 할수 있습니다.


메뉴상 local file (svg, psd) 라고 있는 걸로 봐서는 다른것도 가능할 듯 싶으나,

저는 포토샵이 없어 위의 original 파일이 없는 관계로 테스트는 못해봤습니다.


- 끝 -

내 앱의 캐쉬 데이터 지우기 예제 입니다.

getCacheDir() 에서부터 정보를 불러와서 Folder 스캔하여 아래에 있는 파일을 삭제 하는 방식입니다.

적당히 남겨두어야 하는 부분은 주석을 참조하여 사용하시면 됩니다.


/**
 * 앱 캐시 지우기
 * @param context
 */
public static void clearApplicationData(Context context) {
	File cache = context.getCacheDir();
	File appDir = new File(cache.getParent());
	if (appDir.exists()) {
		String[] children = appDir.list();
		for (String s : children) {
			//다운로드 파일은 지우지 않도록 설정
			//if(s.equals("lib") || s.equals("files")) continue;
			deleteDir(new File(appDir, s));
			Log.d("test", "File /data/data/"+context.getPackageName()+"/" + s + " DELETED");
		}
	}
}

private static boolean deleteDir(File dir) {
	if (dir != null && dir.isDirectory()) {
		String[] children = dir.list();
		for (int i = 0; i < children.length; i++) {
			boolean success = deleteDir(new File(dir, children[i]));
			if (!success) {
				return false;
			}
		}
	}
	return dir.delete();
}


+ Recent posts