2015年7月30日星期四

google analytics使用

第一部分

Analytics让我们知道用户如何与我们的应用进行交互,并帮助我们做出一些决策,例如:
  • 了解应用的哪些部分最受用户欢迎并集中开发些部分
  • 了解应用的哪些部分较少被用到,以便重新设计或清楚这些部分
  • 找到潜在的导向问题,获取更多信息等等。
所以,在应用中集成一个分析系统会使你的应用如虎添翼。

1、下载Google Analytics库

首先,我们需要从Google开发者网站上下载到所需要添加到工程的类。

2、在我们的Android工程中添加Google Analytics库

解压下载的文件,将jar文件添加到libs文件夹下,并在build路径中导入这些文件。

3、更新manifest文件

如果你的应用还没有允许以下权限,请添加下列内容:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

4、更新Activity代码

所有的Activity都必须重载onStart和onStop方法,以开启或停用Analytics功能。一个很好的作法是创建一个基本Activity并让所有其他Activity继承它。现在我们需要修改这个基本activity。
@Override
protected void onStart() {
    super.onStart();
    EasyTracker.getInstance(this).activityStart(this);
}

@Override
protected void onStop() {
    super.onStop();
    EasyTracker.getInstance(this).activityStop(this);
}

5、在values文件夹下添加Analytics设置

创建一个新的文件Analytics.xml。下面的这些参数足以配置好Google
Analytics。
<?xml version="1.0" encoding="utf-8" ?>

<resources>
    <!--Replace placeholder ID with your tracking ID-->
    <string name="ga_trackingId">UA-XXXX-Y</string>

    <!--Enable automatic activity tracking-->
    <bool name="ga_autoActivityTracking">true</bool>

    <!--Enable automatic exception tracking-->
    <bool name="ga_reportUncaughtExceptions">true</bool>
</resources>
这个文档提供了更多的设置方法。

6、创建Google Analytics账户

显然,第一个配置参数需要一个跟踪id,这需要你有一个Google Analytics账户
创建一个新的账户,将类型设置为应用。然后再输入几个简单的细节,你就会得到跟踪id, 并将其添加在配置文件中。

7、链接Google Analytics账户与Google Play开发者控制台

近期发布的新特性允许我们将这两个账号连接起来,让这两项服务相辅相成。我们只需在Administraion/Setup中启用Link Google Play应用。
接下来,我们就能获取更多用户使用我们应用的信息了。

总结

本文介绍的配置将为我们揭示访问量(新用户量以及当前访问量),位置以及一些其他的主要关于Activity的信息。
如需更多帮助,下一节会介绍如何在试图(view)中使用事件以及访问记录(例如在Fragment中),将使Google Analytics发挥更大的作用。

第二部分

上一节介绍了如何在你的安卓应用中集成Google Analytics。接下来我将要展示如何通过注册任意视图和事件的访问量来使Google Analytics的作用最大化。

如何注册视图

初始化配置只能捕捉到对Activity的访问。但是现在大部分应用都被分割成很多Fragment,所以能够获悉哪一个Fragment被加载了会非常有意义。下面的代码是必须的:
EasyTracker tracker = EasyTracker.getInstance(context);
tracker.set(Fields.SCREEN_NAME, name);
tracker.send(MapBuilder.createAppView().build());
在第二行,使用类名,或一个对查看统计数据的人更友好的名字来设置屏幕名称。

如何捕捉并触发事件

事件功能由网页分析继承而来。事件,表示用户在使用应用时进行的任意动作,需要最多4个参数:
  • 类别:根据需求的不同,我们的应用被分化到不同的类别。我倾向于针对我应用中的每一部分使用单独的类别。
  • 动作:事件的种类:按下,搜索,播放,停止……
  • 标签(可选):标签元素被包含在动作中。它可能代表某些特定的UI组件,如按一下按钮,或者其他动态捕捉,例如进行一次搜索,此时,标签可能是由用户执行的特定的搜索构成。
  • 值(可选):这个参数是一个Long型,用来给动作提供一个数值。比如,用户播放媒体文件的时间。
使用下面的代码来注册事件:
EasyTracker tracker = EasyTracker.getInstance(context);
tracker.send(MapBuilder
                .createEvent(category, action, label, value)
                .build()
        );
根据需求以及如何使用记录信息来设置Event中参数。

结论

Google Analytics 这款强大的工具让我们了解用户如何使用我们的应用。这些信息极大的帮助我们解决用户遇到的问题,改进最常用到的部分,或启用广告活动。让Google Analytics带领你的应用走向成功!

2015年7月29日星期三

google 패널리스틱 사용

https://www.google.com/analytics/web/?hl=ko&pli=1#report/app-overview/a65738651w102006579p106004094/


설정 개요 사용:https://support.google.com/analytics/answer/2587086

애널리틱스 시작하기:https://support.google.com/analytics/answer/1008015?hl=ko&topic=1726909&ctx=topic

2015年7月28日星期二

下载的图片保存到本地并立即生成问题

1.在网上下下来的图片保存到本地时并不会马上生成那个图片文件,
为了解决这个问题 可以使用
MediaStore.Images.Media.insertImage(context.getContentResolver(),file.getAbsolutePath(),file.getName(),file.getName());

但是这个方法只会保存到 安卓的存放照片的地址 也就是Camera


所以为了解决这个问题 使用下面的
 // Tell the media scanner about the new file so that it is
    // immediately available to the user.
    MediaScannerConnection.scanFile(this, new String[] { file.toString() }, null,
            new MediaScannerConnection.OnScanCompletedListener() {
                public void onScanCompleted(String path, Uri uri) {
                    Log.i("ExternalStorage", "Scanned " + path + ":");
                    Log.i("ExternalStorage", "-> uri=" + uri);
                }
    });

还可以使用 一下方法来 通知系统 重新扫描拍照文件
Intent localIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, camerafileUri);sendBroadcast(localIntent);

2015年7月24日星期五

android保存图片后相册中不能马上显示的解决、!

android保存图片后相册中不能马上显示的解决、!,有需要的朋友可以参考下。

图片保存至相册后不能马上保存是因为相册不是每次都直接扫描所有目录,而是主要在开机时才扫描,并将图片路径等信息存至
相应数据库,进入相册时直接从数据库读取所有扫描到的图片。所以直接保存图片至目录,相册不能立刻显示出来。解决方法是,
保存图片后,直接把路径等相关信息直接插入数据库即可。
public static boolean saveImgToGallery(String fileName) {
  boolean sdCardExist = Environment.getExternalStorageState().equals(
    android.os.Environment.MEDIA_MOUNTED); // 判断sd卡是否存在
  if (!sdCardExist)
   return false;

  try {
   // String url = MediaStore.Images.Media.insertImage(cr, bmp,
   // fileName,
   // "");
   // app.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri
   // .parse("file://"
   // + Environment.getExternalStorageDirectory())));

   // debug
   ContentValues values = new ContentValues();
   values.put("datetaken", new Date().toString());
   values.put("mime_type", "image/png");
   values.put("_data", fileName);
   // values.put("title", this.a.getString(2131230720));
   // values.put("_display_name", (String)localObject1);
   // values.put("orientation", "");
   // values.put("_size", Integer.valueOf(0));
   Application app = MyApplication.getThis();
   ContentResolver cr = app.getContentResolver();
   cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

  } catch (Exception e) {
   e.printStackTrace();
  }
  return true;
 }

2015年7月17日星期五

通知栏 启动应用

今天在做项目的时候遇到一个问题。点击常驻通知栏图标时,是重新启动了应用,我想实现的是如果应用已经启动则返回已经启动的应用,否则新启动该应用。
   可是这个要怎么实现呢,应该是要设置一下Intent,上网查了一下,果然是Intent要进行一些设置:
   Intent intent = new Intent(Intent.ACTION_MAIN);
     intent.addCategory(Intent.CATEGORY_LAUNCHER);
     intent.setClass(this, SplashScreenActivity.class);
     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
     Context mContext = getApplicationContext();
     PendingIntent contextIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
这样问题就解决了。

2015年7月15日星期三

弹出键盘在输入框的下边显示

android:windowSoftInputMode="adjustResize|stateUnchanged"

最常用的组合是上边.

如果edit包在scrollview里的话他就会自动在 edit下边显示

如果edit在scrollview的话
那么edit会覆盖scrollview的部分并显示在键盘上边



下边是举例

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:orientation="vertical">

    <ScrollView
        android:layout_weight="1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scrollbars="none">
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:orientation="vertical">
            <LinearLayout
                android:layout_width="fill_parent"
                android:layout_height="@dimen/item_height"
                android:orientation="horizontal"
                android:background="@drawable/view_item_line"
                android:gravity="center_vertical"
                android:layout_margin="@dimen/dp10">
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:textSize="@dimen/alim_create_item_text_size"
                    android:textColor="@color/black"
                    android:background="@null"
                    android:gravity="center_vertical"
                    android:text="원아명"
                    android:layout_marginLeft="@dimen/dp10"
                    android:visibility="gone"/>
                <TextView
                    android:id="@+id/gallary_lool_class_name_textview"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:textSize="@dimen/alim_create_item_text_size"
                    android:textColor="@color/black"
                    android:background="@null"
                    android:gravity="center_vertical"
                    android:layout_marginLeft="@dimen/dp10"
                    android:text="반명"
                    android:layout_weight="0"
                    />
                <TextView
                    android:id="@+id/gallary_lool_student_name_textview"
                    android:layout_width="fill_parent"
                    android:layout_height="match_parent"
                    android:textSize="@dimen/alim_create_item_text_size"
                    android:textColor="@color/black"
                    android:background="@null"
                    android:gravity="center_vertical"
                    android:layout_marginLeft="@dimen/dp10"
                    android:text="원아명"
                    android:layout_weight="1"
                    />

                <TextView
                    android:id="@+id/gallary_photo_look_golist_textview"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:textSize="@dimen/alim_create_item_text_size"
                    android:textColor="@color/black"
                    android:background="@null"
                    android:gravity="center_vertical"
                    android:layout_marginLeft="@dimen/dp10"
                    android:text="목록보기"
                    android:layout_weight="0"
                    android:paddingRight="@dimen/dp5"
                    android:paddingLeft="@dimen/dp10"
                    />
            </LinearLayout>
            <LinearLayout
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/dp10"
                android:layout_marginRight="@dimen/dp10"
                android:paddingRight="@dimen/dp10"
                android:paddingLeft="@dimen/dp10"
                android:paddingBottom="@dimen/dp10"
                android:background="@drawable/view_item_line"
                android:orientation="vertical">
                <LinearLayout
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal"
                    android:layout_marginTop="@dimen/dp10">
                    <ImageView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:src="@drawable/gallary_list_item_title_icon"/>
                    <TextView
                        android:id="@+id/gallary_photo_look_title_textview"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="@dimen/dp10"
                        android:textSize="@dimen/alim_create_item_text_size"
                        android:textColor="@color/black"
                        />
                </LinearLayout>
                <LinearLayout
                    android:id="@+id/gallary_photo_look_imgs_layout"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">
                </LinearLayout>
                <TextView
                    android:id="@+id/gallary_photo_look_content_textview"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:textSize="16dp"
                    android:layout_marginTop="@dimen/dp10"
                    android:textColor="@color/black"/>
            </LinearLayout>

            <!-- 댓글 보기 영역 -->
            <LinearLayout
                android:id="@+id/alim_look_component_list_layout"
                android:layout_weight="1"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:background="@drawable/alim_look_comment_list_bg"
                android:layout_marginTop="@dimen/dp10"
                android:paddingBottom="@dimen/dp10"
                android:visibility="invisible">
            </LinearLayout>
        </LinearLayout>
    </ScrollView>


    <!-- 댓글 쓰기 모듈-->
    <LinearLayout
        android:layout_weight="0"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:paddingTop="7dp"
        android:paddingBottom="7dp"
        android:paddingLeft="@dimen/dp10"
        android:gravity="center">
        <EditText
            android:id="@+id/alimt_comment_input_edit"
            android:background="@drawable/view_item_line"
            android:layout_width="fill_parent"
            android:layout_height="30dp"
            android:textSize="12dp"
            android:textColor="#818181"
            android:paddingLeft="6dp"
            android:hint="댓글쓰기"
            android:layout_weight="1"/>
        <ImageView
            android:id="@id/alim_comment_submit_image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/comment_send_icon"
            android:paddingLeft="16dp"
            android:paddingRight="13dp"/>
    </LinearLayout>


</LinearLayout>



2015年7月10日星期五

android 完全退出应用方法

1.一般我全退出的时候会把所有的activity都finish掉
2.除此之外我们还应该把该应用的现成也得关掉这样才能释放全部内存
 android.os.Process.killProcess(android.os.Process.myPid());

2015年7月8日星期三

(转)Android手动回收bitmap,引发Canvas: trying to use a recycled bitmap处理

在做Android的开发的时候,在ListView 或是 GridView中需要加载大量的图片,为了避免加载过多的图片引起OutOfMemory错误,设置了一个图片缓存列表 Map<String, SoftReference<Bitmap>> imageCache , 并对其进行维护,在图片加载到一定数量的时候,就手动回收掉之前加载图片的bitmap,此时就引起了如下错误:

Java代码  收藏代码
  1. java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@41de4380  
  2.     at android.graphics.Canvas.throwIfRecycled(Canvas.java:1026)  
  3.     at android.graphics.Canvas.drawBitmap(Canvas.java:1127)  
  4.     at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:393)  
  5.     at android.widget.ImageView.onDraw(ImageView.java:961)  
  6.     at android.view.View.draw(View.java:13458)  
  7.     at android.view.View.draw(View.java:13342)  
  8.     at android.view.ViewGroup.drawChild(ViewGroup.java:2929)  
  9.     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2799)  
  10.     at android.view.View.draw(View.java:13461)  
  11.     at android.view.View.draw(View.java:13342)  


图片手动回收部分代码:

Java代码  收藏代码
  1. Bitmap removeBitmap = softReference.get();  
  2. if(removeBitmap != null && !removeBitmap.isRecycled()){  
  3.     removeBitmap.recycle(); //此句造成的以上异常  
  4.     removeBitmap = null;  
  5. }  

网上有好多人说应该把recycle()去掉,个人认为去掉后会引起内存持续增长,虽然将bitmap设置为了null,但是系统并没有对其进行真正的回收,仍然占有内存,即是调用了System.gc() 强制回后以后,内存仍然没有下去,如果依靠内存达到上限时系统自己回收的话,个人觉得太晚了,已经对应用造成了影响,应用应该是比较卡了,所以还是赞同加上bitmap.recycle() ,但是又会引起  Canvas: trying to use a recycled bitmap 异常,困扰了很久,开始尝试从其它方面着手来解决这个问题,即然是异常就应该能够捕获到,但是在Adapter里的getView()方法里进行捕获的时候,时机晚了,没有捕获到。现在换到在ImageViewonDraw()里进行捕获,上面的异常能够捕获。

解决方法(继承ImageView 重写onDraw()方法,捕获异常):
在重写onDraw()方法中,其实什么都没有做,只是添加了一个异常捕获,即可捕捉到上面的错误
Java代码  收藏代码
  1. import android.content.Context;  
  2. import android.graphics.Canvas;  
  3. import android.util.AttributeSet;  
  4. import android.widget.ImageView;  
  5.   
  6. /** 
  7.  * 重写ImageView,避免引用已回收的bitmap异常 
  8.  *  
  9.  * @author zwn 
  10.  *  
  11.  */  
  12. public class MyImageView extends ImageView {  
  13.   
  14.     public MyImageView (Context context, AttributeSet attrs) {  
  15.         super(context, attrs);  
  16.     }  
  17.   
  18.     @Override  
  19.     protected void onDraw(Canvas canvas) {  
  20.         try {  
  21.             super.onDraw(canvas);  
  22.         } catch (Exception e) {  
  23.             System.out  
  24.                     .println("MyImageView  -> onDraw() Canvas: trying to use a recycled bitmap");  
  25.         }  
  26.     }  
  27.   
  28. }  

2015年7月7日星期二

malloc的使用

char m;
scanf(" %c",&m); //前面加空格是为了去掉空格、回车等操作
NSLog(@"the character is %c",m);

    上面这个程序是各位比较熟悉的两个方法一个输入、一个输出,但是如果我改一下改成

char *m;
NSLog(@"\n请输入一个字符");
scanf(" %c",m);
NSLog(@"\nthis is %c",*m);

    是否正确呢,编译时是否会报错,运行时是否会出问题?
    其实这个程序,如果编译的时候不会出现异常,但是如果运行的话,会出现运行时异常(出现lldb命令,使用kill命令结束即可),原因是就是我们定义了一个char指针m,这个指针没有进行初始化赋值,导致程序运行时无法找到存储这个字符的内存空间,如果改成

char *m;
m=(char *)malloc(sizeof(char));//malloc()动态分配内存,malloc分配内存的首地址,然后赋值给m
NSLog(@"\n请输入一个字符");
scanf(" %c",m);
NSLog(@"\nthis is %c",*m);

      如果使用malloc方法进行分配空间之后,程序便可以正常进行,sizeof方法获得对应类型的空间大小

   趁热再来一发,因为使用malloc进行动态分配空间,所以我们可以使用char指针输出字符串,如下:
char *a;
a=(char *)malloc(sizeof(char)*100); //动态分配100个连续的char内存地址
NSLog(@"\n请输入一个字符串");
scanf(" %s",a);
NSLog(@"\nthis is %s",a);

C语言memset函数详解与误用

memset为内存填充函数,包含在<string.h>头文件中,可以用它对一片内存空间进行初始化,其原型为  
void *memset(void *s, int v, size_t n);  
英文释义如下: 
Copies the value v (converted to type unsigned char) to the first n bytes pointed to by s; returns s.  
这里s可以是数组名,也可以是指向某一内在空间的指针;v为要填充的值;n为要填充的字节数,通常为sizeof(s); 
使用memset时要注意的是,memset是逐字节进行填充,所以s一般为char *型。
对于其它类型的s,可以填充的值有两个,0和-1。这是因为计算机中用二进制补码表示数字,0的二进制补码为全0,-1的二进制补码为全1。如果要初始化为其它的值,可以用一个for循环,如下:
 for (int i=0; i<n; i++)
     s[i] = v; 
  
memset() 函数常用于内存空间初始化。如:
char str[100];
memset(str,0,100);
memset可以方便的清空一个结构类型的变量或数组。
  如:
  struct sample_struct
  {
  char csName[16];
  int iSeq;
  int iType;
  };
  对于变量
  struct sample_strcut stTest;
  一般情况下,清空stTest的方法:
  stTest.csName[0]='/0';
  stTest.iSeq=0;
  stTest.iType=0;
  用memset就非常方便:
  memset(&stTest,0,sizeof(struct sample_struct));
  如果是数组:
  struct sample_struct TEST[10];
  则
  memset(TEST,0,sizeof(struct sample_struct)*10);
  
对于赋特定的值,需注意
 char a[5];
     memset(a,1,5);  //成功赋值为0x01
     int a[5];
     memset(a,1,5);//这里改成memset(a,1,5 *sizeof(int))也是不可以的 
   因为第一个程序的数组a是字符型的,字符型占据内存大小是1Byte,而memset函数也是以字节为单位进行赋值的。
 而第二个程序a是整型的,使用memset还是按字节赋值,这样赋值完以后,每个数组元素的值实际上是0x01010101即十进制的16843009。


 memset,memcpy,strcpy 的区别
一.函数原型
   strcpy
   extern char *strcpy(char *dest,char *src);
   #include <string.h>
   功能:把src所指由NULL结束的字符串复制到dest所指的数组中
   说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
   返回指向dest的指针


memcpy
extern void *memcpy(void *dest,void *src,unsigned int count);
#include <string.h>
   功能:由src所指内存区域复制count个字符串到dest所指内存区域.
   说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针.
 
   memset
   extern void *memset(void *buffer,int c,int count);
   #include <string.h>
   功能:把buffer所指内存区域的前count个字节设置成字符c
   说明:返回指向buffer的指针.



二.区别
    memset 用来对一段内存空间全部设置为某个字符,一般用于在对定义的字符串初始化为' '或者'\0';
    例: char a[100];
          memset(a,'\0',sizeof(a));
   
   memcpy 是用来做内存拷贝,可以用来拷贝任何数据类型的对象,可以指定拷贝的数据长度;
   例:
           char a[100],b[50];
           memcpy(b,a,sizeof(b));   //注意:如果使用sizeof(a),会造成内存溢出
   mem是一段内存,他的长度,必须自己记住.memcpy是见着什么拷贝什么。
   
    strcpy 就只能拷贝字符串,它遇到'\0'就结束拷贝;
      例:char a[100],b[50];
              strcpy(a,b);
              如用strcpy(b,a)要注意a中的字符串长度(第一个'\0'之前) 是否超过50,如果超过,则会造成b的
内存溢出.它是不会拷贝'\0'的,所以一般还有加一个语句:
              *a='\0';
 
三.使用技巧
      memset 可以方便的清空一个数据结构的变量或数组.
      如:
        struct sample_struct
       {
              char csName[16];
              int iSeq;
              int iType;
       };
       对于变量
       struct sample_struct stTest;
       一般情况下,初始化stTest的方法:
        stTest.csName[0]='\0';
        stTest.iSeq=0;
        stTest.iType=0;
    而用memset:
       memset(&stTest,0,sizeof(struct sample_struct));
    如果是数组:
    struct sample_struct TEST[100];
    memset(TEST,0,sizeof(struct sample_struct)*100);

strcpy是拷贝字符串,以\0为标志结束(即一旦遇到数据值为0的内存地址拷贝过程即停止)
strcpy的原型为
char *strcpy(char *dest, const char *src)
而memcpy是给定来源和目标后,拷贝指定大小n的内存数据,而不管拷贝的内容是什么(不仅限于字符)
memcpy的原型为
void *memcpy(void *dest, const void *src, size_t n);