2015-10-15 08:52:14 sbsujjbcy 阅读数 6426
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19223 人正在学习 去看看 任苹蜻

对于开发人员来说,设计模式有时候就是一道坎,但是设计模式又非常有用,过了这道坎,它可以让你水平提高一个档次。而在android开发中,必要的了解一些设计模式又是非常有必要的。对于想系统的学习设计模式的同学,这里推荐2本书。一本是Head First系列的Head Hirst Design Pattern,英文好的可以看英文,可以多读几遍。另外一本是大话设计模式。

这篇文章介绍一个模式,就是单例模式,因为个人觉得这个模式理解起来最容易,而且不是太复杂。

首先了解一些什么是单例,从名字中就可以听出来就是在内存中维护唯一对象。这样做有以下几个优点

  • 对于那些比较耗内存的类,只实例化一次可以大大提高性能,尤其是在移动开发中。
  • 保持程序运行的时候该中始终只有一个实例存在内存中

其实单例有很多种实现方式,但是个人比较倾向于其中1种。可以见单例模式

代码如下

public class Singleton {
    private static volatile Singleton instance = null;

    private Singleton(){
    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

要保证单例,需要做一下几步

  • 必须防止外部可以调用构造函数进行实例化,因此构造函数必须私有化。
  • 必须定义一个静态函数获得该单例
  • 单例使用volatile修饰
  • 使用synchronized 进行同步处理,并且双重判断是否为null,我们看到synchronized (Singleton.class)里面又进行了是否为null的判断,这是因为一个线程进入了该代码,如果另一个线程在等待,这时候前一个线程创建了一个实例出来完毕后,另一个线程获得锁进入该同步代码,实例已经存在,没必要再次创建,因此这个判断是否是null还是必须的。

至于单例的并发测试,可以使用CountDownLatch,使用await()等待锁释放,使用countDown()释放锁从而达到并发的效果。可以见下面的代码

public static void main(String[] args) {
    final CountDownLatch latch = new CountDownLatch(1);
    int threadCount = 1000;
    for (int i = 0; i < threadCount; i++) {
        new Thread() {
            @Override
            public void run() {
                try {
                    latch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Singleton.getInstance().hashCode());
            }
        }.start();
    }
    latch.countDown();
}

看看打印出来的hashCode会不会出现不一样即可,理论上是全部都一样的。

而在Android中,很多地方用到了单例。

比如Android-Universal-Image-Loader中的单例

private volatile static ImageLoader instance;
/** Returns singleton class instance */
public static ImageLoader getInstance() {
    if (instance == null) {
        synchronized (ImageLoader.class) {
            if (instance == null) {
                instance = new ImageLoader();
            }
        }
    }
    return instance;
}

比如EventBus中的单例

private static volatile EventBus defaultInstance;
public static EventBus getDefault() {
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
            if (defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}

上面的单例都是比较规规矩矩的,当然实际上有很多单例都是变了一个样子,单本质还是单例。

如InputMethodManager 中的单例

static InputMethodManager sInstance;
public static InputMethodManager getInstance() {
    synchronized (InputMethodManager.class) {
        if (sInstance == null) {
            IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
            IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
            sInstance = new InputMethodManager(service, Looper.getMainLooper());
        }
        return sInstance;
    }
}

AccessibilityManager 中的单例,看代码这么长,其实就是进行了一些判断,还是一个单例

private static AccessibilityManager sInstance;
public static AccessibilityManager getInstance(Context context) {
    synchronized (sInstanceSync) {
        if (sInstance == null) {
            final int userId;
            if (Binder.getCallingUid() == Process.SYSTEM_UID
                    || context.checkCallingOrSelfPermission(
                            Manifest.permission.INTERACT_ACROSS_USERS)
                                    == PackageManager.PERMISSION_GRANTED
                    || context.checkCallingOrSelfPermission(
                            Manifest.permission.INTERACT_ACROSS_USERS_FULL)
                                    == PackageManager.PERMISSION_GRANTED) {
                userId = UserHandle.USER_CURRENT;
            } else {
                userId = UserHandle.myUserId();
            }
            IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
            IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder);
            sInstance = new AccessibilityManager(context, service, userId);
        }
    }
    return sInstance;
}

当然单例还有很多种写法,比如恶汉式,有兴趣的自己去了解就好了。

最后,我们应用一下单例模式。典型的一个应用就是管理我们的Activity,下面这个可以作为一个工具类,代码也很简单,也不做什么解释了。

public class ActivityManager {

    private static volatile ActivityManager instance;
    private Stack<Activity> mActivityStack = new Stack<Activity>();

    private ActivityManager(){

    }

    public static ActivityManager getInstance(){
        if (instance == null) {
        synchronized (ActivityManager.class) {
            if (instance == null) {
                instance = new ActivityManager();
            }
        }
        return instance;
    }

    public void addActicity(Activity act){
        mActivityStack.push(act);
    }

    public void removeActivity(Activity act){
        mActivityStack.remove(act);
    }

    public void killMyProcess(){
        int nCount = mActivityStack.size();
        for (int i = nCount - 1; i >= 0; i--) {
            Activity activity = mActivityStack.get(i);
            activity.finish();
        }

        mActivityStack.clear();
        android.os.Process.killProcess(android.os.Process.myPid());
    }
}

这个类可以在开源中国的几个客户端中找到类似的源码

以上两个类是一样的,没区别。

2016-11-08 20:46:30 qq_30379689 阅读数 8124
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19223 人正在学习 去看看 任苹蜻

Retrofit2是什么

使用项目的原话:Android和Java中类型安全的HTTP客户端
项目地址:https://github.com/square/retrofit

Retrofit2的导入

这里Retrofit还需要导入它的Gson依赖库,因为返回的数据需要Gson来处理

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'

Retrofit2的基本使用

1、Get请求
2、Post请求
3、单、多文件上传

Retrofit2工具类的演示

演示提供的接口(该接口不支持post方式)

http://japi.juhe.cn/joke/content/list.from?key=488c65f3230c0280757b50686d1f1cd5&&sort=asc&&time=1418816972

get请求(支持普通请求)

/*
 * Get请求 
 * 参数已经封装在工具类的Url中
 */
Call<Info> call = RetrofitUtils.getInstance().get();
call.enqueue(new Callback<Info>() {
    @Override
    public void onResponse(Call<Info> call, Response<Info> response) {

    }

    @Override
    public void onFailure(Call<Info> call, Throwable t) {

    }
});

get请求(支持键值对参数)

//根据接口需求创建键值对
Map<String,String> map = new HashMap<>();
map.put("key","488c65f3230c0280757b50686d1f1cd5");
map.put("sort","asc");
map.put("time","1418816972");

/*
 * Get请求 
 * @param map 为get参数
 */
Call<Info> call = RetrofitUtils.getInstance().get(map);
call.enqueue(new Callback<Info>() {
    @Override
    public void onResponse(Call<Info> call, Response<Info> response) {

    }

    @Override
    public void onFailure(Call<Info> call, Throwable t) {

    }
});

Post请求(支持键值对参数)

//根据接口需求创建键值对
Map<String,String> map = new HashMap<>();
map.put("key","488c65f3230c0280757b50686d1f1cd5");
map.put("sort","asc");
map.put("time","1418816972");

/*
 * Post请求 
 * @param map 为Post参数
 */
Call<Info> call = RetrofitUtils.getInstance().post(map);
call.enqueue(new Callback<Info>() {
    @Override
    public void onResponse(Call<Info> call, Response<Info> response) {

    }

    @Override
    public void onFailure(Call<Info> call, Throwable t) {

    }
});

Post请求(支持获取返回的字符串)

//根据接口需求创建键值对
Map<String,String> map = new HashMap<>();
map.put("key","488c65f3230c0280757b50686d1f1cd5");
map.put("sort","asc");
map.put("time","1418816972");

/*
 * Post请求 
 * @param map 为Post参数
 */
Call<ResponseBody> call = RetrofitUtils.getInstance().post(map);
call.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        //这里采用Retrofit2自带的ResponseBody可以返回对应的字符串数据,get请求同理
        String body = response.body().string().toString();
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {

    }
});

Post请求(上传文件和参数)

//文件的封装
List<MultipartBody.Part> parts = null;
parts = RetrofitUtils.filesToMultipartBodyParts("imgs[]", photo_list);
//参数的封装
Map<String, RequestBody> params = new HashMap<>();
params.put("token", RetrofitUtils.convertToRequestBody("abcdefg"));
params.put("username", RetrofitUtils.convertToRequestBody("hensen"));
params.put("password", RetrofitUtils.convertToRequestBody("123456"));

//上传文件和参数
Call<Object> call = RetrofitUtils.getInstance().register(params, parts);
call.enqueue(new Callback<Object>() {
    @Override
    public void onResponse(Call<Object> call, Response<Object> response) {

    }

    @Override
    public void onFailure(Call<Object> call, Throwable t) {

    }
});

Retrofit2工具类的封装

Retrofit的请求是以REST请求方式发送请求的,所以工具的封装需要做两件事

  • 对REST请求的API进行封装
  • Retrofit自身的封装

由于我们接口返回的JSON数据如下

{
    "error_code": 0,
    "reason": "Success",
    "result": {
        "data":[
            {
                "content":"学校论坛上有人问:“为啥明明用了除蟑螂的药,蟑螂却越来越多了。”某个学生回帖:“如果你家人不见了,你不出来找吗?你会不着急么?”",
                "hashId":"8196907ee902f3508b9be6ea59d2191c",
                "unixtime":1478598830,
                "updatetime":"2016-11-08 17:53:50"
            }
        ]
    }
}

所以这里需要对我们需要解析的数据进行Bean对象的封装

public class Info {

    @Override
    public String toString() {
        return "Info{" +
                "error_code=" + error_code +
                ", reason='" + reason + '\'' +
                ", result=" + result +
                '}';
    }

    private int error_code;
    private String reason;
    private ResultBean result;

    public static class ResultBean {
        @Override
        public String toString() {
            return "ResultBean{" +
                    "data=" + data +
                    '}';
        }

        private List<DataBean> data;

        public static class DataBean {
            private String content;
            private String hashId;
            private int unixtime;
            private String updatetime;

            @Override
            public String toString() {
                return "DataBean{" +
                        "content='" + content + '\'' +
                        ", hashId='" + hashId + '\'' +
                        ", unixtime=" + unixtime +
                        ", updatetime='" + updatetime + '\'' +
                        '}';
            }
        }
    }
}

对REST请求的API进行封装

Retrofit使用注解的方式来声明GET请求、POST请求、请求参数、请求头等进行的网络访问,下面是各个注解的表示的意思

  • Get请求相关

    • @Get:发送Get请求
    • @Query:Get请求参数
    • @QueryMap:Get请求Map参数
  • Post请求相关

    • @Post:发送Post请求
    • @FormUrlEncoded:采用表单的方式,一般与@Post共用
    • @Field:Post请求参数
    • @FieldMap:Post请求Map参数
  • Header请求相关

    • @Headers:发送Header信息
    • @Header:Header信息参数
    • @HeaderMap:Header信息的Map参数
  • Path请求相关

    • @Path:访问路径,最终访问BaseUrl+@Path里面的内容

理解完意思之后,编写REST的API,其实就是请求接口,具体看下面的代码

public interface IRetrofitServer {

    String getUrl = "list.from";
    String postUrl = "list.from";

    /**
     * 传递参数的Get请求
     * @param key
     * @param sort
     * @param time
     * @return
     */
    @GET(getUrl)
    Call<Info> get(@Query("key") String key, @Query("sort") String sort, @Query("time") String time);

    /**
     * 封装好Url的Get的请求
     * @return
     */
    @GET(getUrl + "?key=488c65f3230c0280757b50686d1f1cd5&&sort=asc&&time=1418816972")
    Call<Info> get();

    /**
     * 传递Map键值对的Get请求
     * @param params
     * @return
     */
    @GET(getUrl)
    Call<Info> get(@QueryMap Map<String, String> params);

    /**
     * 传递参数的Post请求
     * @param key
     * @param sort
     * @param time
     * @return
     */
    @FormUrlEncoded
    @POST(postUrl)
    Call<Info> post(@Field("key") String key, @Field("sort") String sort, @Field("time") String time);

    /**
     * 传递Map键值对的Post请求
     * @param map
     * @return
     */
    @FormUrlEncoded
    @POST(postUrl)
    Call<Info> post(@FieldMap Map<String, String> map);

    /**
     * 传递Map键值对的Post请求
     * @param map
     * @return 对应的字符串数据
     */
    @FormUrlEncoded
    @POST(postUrl)
    Call<ResponseBody> post(@FieldMap Map<String, String> map);

    /**
     * 传递Map键值对和Header的Post请求
     * @param key
     * @param sort
     * @param time
     * @return
     */
    @Headers({"os:Android", "version:2.0"})
    @FormUrlEncoded
    @POST(postUrl)
    Call<Info> postWithHeader(@Field("key") String key, @Field("sort") String sort, @Field("time") String time);

    /**
     * 传递Map键值对和Header的Post请求
     * @param os
     * @param key
     * @param sort
     * @param time
     * @return
     */
    @FormUrlEncoded
    @POST(postUrl)
    Call<Info> postWithHeader(@Header("os") String os, @Field("key") String key, @Field("sort") String sort, @Field("time") String time);

    /**
     * 传递Map键值对和Header的Post请求
     * @param map
     * @param key
     * @param sort
     * @param time
     * @return
     */
    @FormUrlEncoded
    @POST(postUrl)
    Call<Info> postWithHeader(@HeaderMap Map<String, String> map, @Field("key") String key, @Field("sort") String sort, @Field("time") String time);

    /**
     * 传递访问路径和键值对的Post请求
     * @param path
     * @param key
     * @param sort
     * @param time
     * @return
     */
    @FormUrlEncoded
    @POST("{path}")
    Call<Info> post(@Path("path") String path, @Field("key") String key, @Field("sort") String sort, @Field("time") String time);
}

Retrofit自身的封装

Retrofit和okHttp一样,采用构造者模式创建,采用单例模式防止使用多个对象

private static final String baseUrl = "http://japi.juhe.cn/joke/content/";
private static Retrofit retrofit = null;
private static IRetrofitServer iServer;

public static IRetrofitServer getInstance() {
    if (retrofit == null) {
        synchronized (RetrofitUtils.class) {
            if (retrofit == null) {
                retrofit = new Retrofit.Builder()
                        .baseUrl(baseUrl)
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();
                iServer = retrofit.create(IRetrofitServer.class);
            }
        }
    }
    return iServer;
}

上面代码做了三件事

  • 绑定请求URL
  • 采用GSON来处理返回的JSON数据
  • 创建并返回REST请求API接口iServer

下面就可以直接使用工具类拿到这个iServer,调用提供的接口方法

Call<Info> call = RetrofitUtils.getInstance().get();
call.enqueue(...);

单、双文件的上传

API接口的创建,比如说注册功能,需要上传两张身份证照片,这是我自己服务器的接口

public interface IRetrofitServer {

    @Multipart
    @POST("app/register")
    Call<Object> register(@PartMap Map<String, RequestBody> map, @Part List<MultipartBody.Part> parts);
}
  • @PartMap:表示参数的上传
  • @Part:表示文件列表

创建两个方法辅助PartMap和Part的创建

//这里的key则是后台服务器的字段名,即使H5中input的name的名字
//如果是单文件,filePaths的大小就为1
public static List<MultipartBody.Part> filesToMultipartBodyParts(String key, List<String> filePaths) {
    List<MultipartBody.Part> parts = new ArrayList<>(filePaths.size());
    for (String filePath : filePaths) {
        File file = new File(filePath);
        //这里的image/*表示上传的是相片的所有格式,你可以替换成你需要的格式
        RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), file);
        MultipartBody.Part part = MultipartBody.Part.createFormData(key, file.getName(), requestBody);
        parts.add(part);
    }
    return parts;
}

public static RequestBody convertToRequestBody(String param) {
    //这里的text/plain表示参数都是文本
    RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"), param);
    return requestBody;
}

到这里,你就可以回过头去看下文章开头的演示部分,那里就是RetrofitUtils的使用

工具类下载:RetrofitUtils

由于文件上传是我在做项目的时候用上的,工具类缺少文件上传的内容,大家可以自行去拷贝代码

2013-07-04 23:30:19 u010142437 阅读数 6312
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19223 人正在学习 去看看 任苹蜻

随时随地阅读更多技术实战干货,获取项目源码、学习资料,请关注源代码社区公众号(ydmsq666)、博主微信(guyun297890152)、QQ技术交流群(183198395)。

在前文中总结了SQLite数据库的基本用法,本文中将使用SQLiteOpenHelper和单例模式来操作数据库。SQLiteOpenHelper是Android提供的一个管理数据库的工具类,可以用于管理数据库的创建和版本更新。一般的用法是创建它的子类,并扩展它的onCreate()和onUpgrade方法。

SQLiteOpenHelper包含如下方法:

同上文一样,数据仍是手动写死的,实际情况应该根据业务需求从界面或其他地方获取,实例代码如下,关键是后面两个类:

Activity:

package com.lovo.activity;

import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import com.lovo.dao.StuDao;
import com.lovo.databasetest.R;

public class DatabaseTestActivity extends Activity {
	private TextView show;
	private StuDao dao;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		show = (TextView) findViewById(R.id.main_tv_show);
		dao = new StuDao(this);
	}

	public void click(View v) {
		switch (v.getId()) {

		case R.id.main_btn_insert:
			// 添加数据
			dao.insert("张三", 24, "男");
			break;
		case R.id.main_btn_delete:
			// 根据指定ID删除数据
			dao.del(2);
			break;
		case R.id.main_btn_update:
			// 根据指定ID修改数据
			dao.update("王斌", 34, "男", 1);
			break;
		case R.id.main_btn_find:
			StringBuffer sb = new StringBuffer();
			// 查询所有数据
			Cursor cursor = dao.findAll();
			// 根据指定ID查询数据
			// Cursor cursor=dao.findById(1);
			while (cursor.moveToNext()) {
				int id = cursor.getInt(cursor.getColumnIndex("_id"));
				String name = cursor.getString(cursor.getColumnIndex("s_name"));
				String sex = cursor.getString(cursor.getColumnIndex("s_sex"));
				int age = cursor.getInt(cursor.getColumnIndex("s_age"));
				sb.append(id + " " + name + " " + sex + " " + age + "\n");
			}
			show.setText(sb.toString());
			break;

		}
	}

}

布局XML:

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


    <Button
        android:id="@+id/main_btn_insert"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="click"
        android:text="添加" />

    <Button
        android:id="@+id/main_btn_delete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="click"
        android:text="删除" />

    <Button
        android:id="@+id/main_btn_update"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="click"
        android:text="修改" />

    <Button
        android:id="@+id/main_btn_find"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="click"
        android:text="查找" />

    <TextView
        android:id="@+id/main_tv_show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

SQLiteOpenHelper的子类(DBUtil):

package com.lovo.dao;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;

public class DBUtil extends SQLiteOpenHelper {
	private static DBUtil dbUtil;

	private DBUtil(Context context, String name, CursorFactory factory,
			int version) {
		super(context, name, factory, version);
	}

	public static SQLiteDatabase getInstance(Context context) {
		if (dbUtil == null) {
			// 指定数据库名为student,需修改时在此修改;此处使用默认工厂;指定版本为1
			dbUtil = new DBUtil(context, "student", null, 1);
		}
		return dbUtil.getReadableDatabase();
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		try {
			db.execSQL("create table t_stu(_id integer primary key,s_name text,s_age integer,s_sex text)");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		System.out.println("-----onUpgrade Called-----" + oldVersion + "--->"
				+ newVersion);
	}

}

StuDao类:封装数据操作的方法

package com.lovo.dao;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

public class StuDao {
	private SQLiteDatabase db;

	public StuDao(Context context) {
		db = DBUtil.getInstance(context);
	}

	/**
	 * 查询所有数据
	 * 
	 * @return Cursor
	 */
	public Cursor findAll() {
		Cursor cursor = db.rawQuery("select * from t_stu", null);
		return cursor;
	}

	/**
	 * 添加数据
	 * 
	 * @param name  姓名
	 * @param age  年龄
	 * @param sex  性别
	 */
	public void insert(String name, int age, String sex) {
		db.execSQL("insert into t_stu values(null,?,?,?)", new String[] { name,
				age + "", sex });
	}

	/**
	 * 删除数据
	 * 
	 * @param id
	 */
	public void del(int id) {
		db.execSQL("delete from t_stu where _id=?", new String[] { id + "" });
	}

	/**
	 * 根据id查询数据
	 * 
	 * @param id
	 * @return Cursor
	 */
	public Cursor findById(int id) {
		Cursor cursor = db.rawQuery("select * from t_stu where _id=?",
				new String[] { id + "" });
		return cursor;
	}

	/**
	 * 修改数据
	 * 
	 * @param name 姓名
	 * @param age  年龄
	 * @param sex  性别
	 * @param id   id
	 */
	public void update(String name, int age, String sex, int id) {
		db.execSQL("update t_stu set s_name=?,s_age=?,s_sex=? where _id=?",
				new Object[] { name, age, sex, id });
	}
}





 

 

2017-06-01 16:00:39 jinkui 阅读数 3813
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19223 人正在学习 去看看 任苹蜻

单例的实现方法,可以通过同伴对象,或者 lazy。
示例:

class Hello private constructor() {
    companion object {
        val instance = Hello()
    }
}

通过 lazy 实现

class Hello private constructor() {

    private object Holder { val INSTANCE = Hello() }
    companion object {
        val instance: Hello by lazy { Holder.INSTANCE }
    }
}

参考
《Programming Kotlin》Stephen Samuel ,Stefan Bocutiu
《Kotlin in Action》Dmitry Jemerov,Svetlana Isakova

2015-12-23 13:31:08 qq_26643421 阅读数 2564
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19223 人正在学习 去看看 任苹蜻

原文链接:http://blog.csdn.net/qq_26643421/article/details/50386431

PopupWindow弹窗不消失,但是事件向下传递
设置了PopupWindow的background,点击Back键或者点击弹窗的外部区域,弹窗就会dismiss.
  相反,如果不设置PopupWindow的background,那么点击back键和点击弹窗的外部区域,弹窗是不会消失的.
  那么,如果我想要一个效果,点击外部区域,弹窗不消失,但是点击事件会向下面的activity传递,比如下面是一个WebView,我想点击里面的链接等.

  研究了半天,说是要给Window设置一个Flag,

WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL

  看了源码,这个Flag的设置与否是由一个叫mNotTouchModal的字段控制,但是设置该字段的set方法被标记为@hide。
  所以要通过反射的方法调用:

/**
     * Set whether this window is touch modal or if outside touches will be sent
     * to
     * other windows behind it.
     *
     */
    public static void setPopupWindowTouchModal(PopupWindow popupWindow,
            boolean touchModal) {
        if (null == popupWindow) {
            return;
        }
        Method method;
        try {

            method = PopupWindow.class.getDeclaredMethod("setTouchModal",
                    boolean.class);
            method.setAccessible(true);
            method.invoke(popupWindow, touchModal);

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

    }

然后在程序中: 

UIUtils.setPopupWindowTouchModal(popupWindow, false);

该popupWindow外部的事件就可以传递给下面的Activity了。

popupwindow的布局文件
common_media.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="wrap_content"
    android:padding="20dp"
    android:background="@color/colorPrimary"
    android:orientation="vertical">

    <Button
        android:id="@+id/common_media_photo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="拍 照" />

    <Button
        android:id="@+id/common_media_record"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="录 音" />

    <Button
        android:id="@+id/common_media_video"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="视 频" />
</LinearLayout>

封装popupwindow的类
CommonMediaPop.java

package com.depart.deqing.view;

import android.content.Context;
import android.graphics.drawable.BitmapDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.PopupWindow;

import com.depart.deqing.R;

/**
 * Created by yx on 2015/12/21.
 */
public class CommonMediaPop implements View.OnClickListener, View.OnTouchListener {
    private Context mContext;
    private OnMediaClick mOnMediaClick;
    private PopupWindow mPopupWindow;

    public CommonMediaPop(Context context) {
        this.mContext = context;
    }

    @Override
    public void onClick(View v) {
        mPopupWindow.dismiss();
        if (mOnMediaClick == null) {
            return;
        }
        switch (v.getId()) {
            case R.id.common_media_photo:
                mOnMediaClick.onPhotoClick();
                break;
            case R.id.common_media_record:
                mOnMediaClick.onRecordClick();
                break;
            case R.id.common_media_video:
                mOnMediaClick.onVideoClick();
                break;
        }
    }

    public void setOnMediaClick(OnMediaClick onMediaClick) {
        this.mOnMediaClick = onMediaClick;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (null != mPopupWindow && mPopupWindow.isShowing()) {
            mPopupWindow.dismiss();
            mPopupWindow = null;
        }
        return false;
    }

    public interface OnMediaClick {
        public void onPhotoClick();

        public void onRecordClick();

        public void onVideoClick();

    }
    /**初始化控件 , 实现控件点击事件*/
    private void init(View v) {
        View convertView = LayoutInflater.from(mContext).inflate(R.layout.common_media, null);
        Button photo = (Button) convertView.findViewById(R.id.common_media_photo);
        Button record = (Button) convertView.findViewById(R.id.common_media_record);
        Button video = (Button) convertView.findViewById(R.id.common_media_video);
        photo.setOnClickListener(this);
        record.setOnClickListener(this);
        video.setOnClickListener(this);
        mPopupWindow = new PopupWindow(convertView, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT, true);
        convertView.setOnTouchListener(this);//触摸事件 , 在其他区域触摸屏幕 , 取消popupwindow.

        mPopupWindow.setBackgroundDrawable(new BitmapDrawable());//保证popupwindow响应返回按钮事件.
        mPopupWindow.showAtLocation(v, Gravity.BOTTOM, 0, 0);//在底部显示popupwindow.
    }

    public CommonMediaPop showPop(View v) {
        if (null != mPopupWindow) {
            mPopupWindow.dismiss();
        } else {
            init(v);
        }
        return this;
    }

    public boolean disMissPop() {
        boolean isshowing = false;
        if (null != mPopupWindow) {
            isshowing = mPopupWindow.isShowing();
            mPopupWindow.dismiss();
        }
        return isshowing;
    }

}

使用时调用

//activity中 , 只需要一行代码就可以实现调用
new CommonMediaPop(this).showPop(v).setOnMediaClick(this);

android事件分发

阅读数 45

没有更多推荐了,返回首页