分类目录归档:android

PreferenceScreen的应用

PreferenceScreen preference是偏好。首选的意思,PreferenceScreen个人翻译成 “偏好显示”,明确这个意思就好。就是说依据特点灵活的定义显示内容风格,一个屏幕能够包括多个风格,像系统自带的声音设置界面。


实现这样的显示效果事实上非常easy。仅仅须要借助PreferenceScreen类就可以。在项目资源文件里新建xml目录。在里面新建preferences.xml文件.
根元素为PreferenceScreen 代表显示一整个屏幕。内部嵌套PreferenceCategory标签,表示偏好类别,在PreferenceCategory标签内部能够随便存放复选框,输入框,列表等显示控件.可包括的控件内容在android.preference包下可查阅.xml文件编写好后。须要载入到activity中,对于偏好显示的xml载入。能够使用PreferenceActivity中的addPreferencesFromResource(),所以Activity须要继承PreferenceActivity.既然显示的屏幕中包括复选框,输入框的控件,我们必定对选择与否,输入框内容感兴趣。我们要如何获取屏幕的内容呢?
复写activity中的onPreferenceTreeClick 方法。在对屏幕显示的内容进行操作时,会触发此方法。在方法内部通过调用

  1. SharedPreferences contentPreference = preference.getSharedPreferences();
  2.      boolean checkbox_toggle = contentPreference.getBoolean("checkbox_preference"false);
  3.      String animalName = contentPreference.getString("edittext_preference""default");

就可以得到屏幕上输入的内容。与使用SharedPreference对象一样,通过key-value 的形式获取,当中key是xml控件标签中key属性相应的值.
显示效果:

相应xml文件:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <PreferenceScreen
  3.         xmlns:android="http://schemas.android.com/apk/res/android">
  4.     <PreferenceCategory
  5.             android:title="显示一排偏好">
  6.         <CheckBoxPreference
  7.                 android:key="checkbox_preference"
  8.                 android:title="开关偏好"
  9.                 android:summary="这是一个开关button" />
  10.     </PreferenceCategory>
  11.     <PreferenceCategory
  12.             android:title="基于对话框的偏好">
  13.         <EditTextPreference
  14.                 android:key="edittext_preference"
  15.                 android:title="文本输入偏好"
  16.                 android:summary="使用一个文本框对话框"
  17.                 android:dialogTitle="输入你的宠物" />
  18.         <ListPreference
  19.                 android:key="list_preference"
  20.                 android:title="列表偏好"
  21.                 android:summary="使用一个列表对话框"
  22.                 android:entries="@array/entries_list_preference"
  23.                 android:entryValues="@array/entryvalues_list_preference"
  24.                 android:dialogTitle="选择一个" />
  25.     </PreferenceCategory>
  26.     <PreferenceCategory
  27.             android:title="启动偏好">
  28.         <PreferenceScreen
  29.                 android:key="screen_preference"
  30.                 android:title="屏幕"
  31.                 android:summary="显示还有一个偏好屏幕">
  32.             <!-- You can place more preferences here that will be shown on the next screen. -->
  33.             <CheckBoxPreference
  34.                     android:key="next_screen_checkbox_preference"
  35.                     android:title="开关偏好"
  36.                     android:summary="还有一个屏幕上的偏好" />
  37.         </PreferenceScreen>
  38.         <PreferenceScreen
  39.                 android:title="意图偏好"
  40.                 android:summary="通过意图启动一个Activity">
  41.             <intent android:action="android.intent.action.VIEW"
  42.                     android:data="http://www.android.com" />
  43.         </PreferenceScreen>
  44.     </PreferenceCategory>
  45.     <PreferenceCategory
  46.             android:title="偏好属性">
  47.         <CheckBoxPreference
  48.                 android:key="parent_checkbox_preference"
  49.                 android:title="父开关"
  50.                 android:summary="这是一个父开关" />
  51.         <CheckBoxPreference
  52.                 android:key="child_checkbox_preference"
  53.                 android:dependency="parent_checkbox_preference"
  54.                 android:layout="?android:attr/preferenceLayoutChild"
  55.                 android:title="子开关"
  56.                 android:summary="这是一个子开关" />
  57.     </PreferenceCategory>
  58. </PreferenceScreen>

AsyncTask使用解析和同步执行的问题

Android UI是线程不安全的,如果想要在子线程里进行UI操作,就需要借助Android的异步消息处理机制。不过为了更加方便我们在子线程中更新UI元素,Android从1.5版本就引入了一个AsyncTask类,使用它就可以非常灵活方便地从子线程切换到UI线程。 AsyncTask 很早就出现在Android的API里了,所以我相信大多数朋友对它的用法都已经非常熟悉。不过今天我还是准备从AsyncTask的基本用法开始讲起, 然后我们再来一起分析下AsyncTask的并行执行情况

AsyncTask的基本用法

首先来看一下AsyncTask的基本用法,由于AsyncTask是一个抽象类,所以如果我们想使用它,就必须要创建一个子类去继承它。使用时需要继承这个类,然后调用execute()方法。注意继承时需要设定三个泛型Params,Progress和Result的类型,如AsyncTask<Void,Inetger,Void>:

  • Params是指调用execute()方法时传入的参数类型和doInBackgound()的参数类型
  • Progress是指更新进度时传递的参数类型,即publishProgress()和onProgressUpdate()的参数类型
  • Result是指doInBackground()的返回值类型
上面的说明涉及到几个方法:
  • doInBackgound() 这个方法是继承AsyncTask必须要实现的,运行于后台,耗时的操作可以在这里做
  • publishProgress() 更新进度,给onProgressUpdate()传递进度参数
  • onProgressUpdate() 在publishProgress()调用完被调用,更新进度

布局文件如下:

<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:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="显示异步的执行情况" android:id="@+id/tv_show"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动一个异步任务"
android:id="@+id/bt_start_AsyncTask" android:layout_below="@+id/tv_show" android:layout_alignLeft="@+id/tv_show"
android:layout_marginTop="12dp" android:focusableInTouchMode="true"/>

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动一个异步 长耗时 任务"
android:id="@+id/bt_start_long_AsyncTask"
android:focusableInTouchMode="true"
android:layout_above="@+id/bt_toast" android:layout_alignLeft="@+id/tv_show2"
android:layout_marginBottom="13dp"/>
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="弹出对话框"
android:id="@+id/bt_toast"
android:focusableInTouchMode="true"
android:layout_centerVertical="true" android:layout_alignLeft="@+id/bt_start_long_AsyncTask"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="显示长耗时情况"
android:id="@+id/tv_show2"
android:layout_above="@+id/bt_start_long_AsyncTask" android:layout_alignLeft="@+id/bt_start_AsyncTask"
android:layout_marginBottom="11dp"/>

</RelativeLayout>

源代码如下:

 package cn.iigrowing.android.MyAsyncTask;

import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

private Button bt_start_AsyncTask = null;
private Button bt_start_long_AsyncTask = null;
private Button bt_toast = null;

private TextView tv = null;
private TextView tv2 = null;

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

bt_start_AsyncTask = (Button) findViewById(R.id.bt_start_AsyncTask);
bt_start_long_AsyncTask = (Button) findViewById(R.id.bt_start_long_AsyncTask);
bt_toast = (Button) findViewById(R.id.bt_toast);

tv = (TextView) findViewById(R.id.tv_show);
tv2 = (TextView) findViewById(R.id.tv_show2);

bt_start_AsyncTask.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
update();
}
});
bt_start_long_AsyncTask.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
update2();
}
});
bt_toast.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
Toast.makeText(MainActivity.this, "点击了按钮", Toast.LENGTH_LONG).show();
}
});

}

private void update() {
UpdateTextTask updateTextTask = new UpdateTextTask(this, 1, tv);
updateTextTask.execute();
}

private void update2() {
UpdateTextTask updateTextTask = new UpdateTextTask(this, 10, tv2);
updateTextTask.execute();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

class UpdateTextTask extends AsyncTask<Void, Integer, Integer> {
private Context context;
private TextView mytv = null;

private int sleepTime = 1;

UpdateTextTask(Context context, int sleepSecond, TextView tv) {
this.context = context;
sleepTime = sleepSecond;
this.mytv = tv;
}

/**
* 运行在UI线程中,在调用doInBackground()之前执行
*/
@Override
protected void onPreExecute() {
Toast.makeText(context, "开始执行", Toast.LENGTH_SHORT).show();
}

/**
* 后台运行的方法,可以运行非UI线程,可以执行耗时的方法
*/
@Override
protected Integer doInBackground(Void... params) {
int i = 0;
while (i < 10) {
i++;
publishProgress(i);
try {
Thread.sleep(1000 * sleepTime);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}

/**
* 运行在ui线程中,在doInBackground()执行完毕后执行
*/
@Override
protected void onPostExecute(Integer integer) {
Toast.makeText(context, "执行完毕", Toast.LENGTH_SHORT).show();
}

/**
* 在publishProgress()被调用以后执行,publishProgress()用于更新进度
*/
@Override
protected void onProgressUpdate(Integer... values) {
this.mytv.setText(this.mytv.getText() + " " + values[0]);
}
}
}

通过上面的例子发现, 在同时点击两个测试按钮时, 两个文本框不能同时更新, 证明两个异步任务没有并行执行!!

查找网络资料有如下:研 究过Android系统源码的同学会发现:AsyncTask在android2.3的时候线程池是一个核心数为5线程,队列可容纳10线程,最大执行 128个任务,这存在一个问题,当你真的有138个并发时,即使手机没被你撑爆,那么超出这个指标应用绝对crash掉。 后来升级到3.0,为了避免并发带来的一些列问题,AsyncTask竟然成为序列执行器了,也就是你即使你同时execute N个AsyncTask,它也是挨个排队执行的。 这一点请同学们一定注意,AsyncTask在3.0以后,是异步的没错,但不是并发的。关于这一点的改进办法,我之前写过一篇《Thread并发请求封装——深入理解AsyncTask类》没有看过的同学可以看这里,本文是在这个基础上对AsyncTask做进一步的优化。参考:http://my.oschina.net/kymjs/blog/350565

程序源代码

链接: http://pan.baidu.com/s/1Eqw3O 密码: 6kll

解决android studio Gradle警告GBK编码的不可映射字符的问题2

前面用as开发android项目中, 遇到编码问题, 查找了各种办法, 但是没有好的解决
在前面的给出了一个比较不好的解决办法将编码转换成gbk然后进行编译
今天重新查找了些文章, 仔细阅读, 再三尝试, 终于可以把代码编译成utf8方式了,相关过程如下:

1. 编译项目后, 发现如下错误

android studio编译时出现的问题
android studio编译时出现的问题

2. 启动cmd窗口, 到dos下 ,用下面命令进行编译,获取编译的详细信息

gradlew compileDebug --stacktrace 1> a.log 2>&1

上面命令将编译的详细信息, 输出到a.log中, 然后查看日志文件

进入cmd(控制台)进行编译, 获取详细编译信息

进入cmd(控制台)进行编译, 获取详细编译信息

3. 查看日志文件,根据日志文件定位, 代码中那个代码有问题

 

查看android studio详细日志文件 查看android studio详细日志文件

 

查看今天的android studio编译错误
查看具体的android studio编译错误

4. 设置项目的模块编译特性为utf8 ,然后问题解决

设置 android studio的utf-8方式编译代码解决编译错误
设置 android studio的utf-8方式编译代码解决编译错误

为了更好的进行设置,记录了一下处理过程。
链接: http://pan.baidu.com/s/1sj4sqG9 密码: usqi
tasks.withType(Compile){
options.encoding = "UTF-8"
}

Android Studio导入类库

     最近实在是受够了Eclipse的速度,于是准备切换到Android Studio,这个开发环境对gradle有良好的支持,对于UI开发也更好,不过新的开发环境毕竟要适应一段时间,初次导入类库就遇到了麻烦。

对于jar的类库,非常简单,只要在项目根目录下新建一个libs目录,然后把jar复制进去,在jar上点击右键,选择Add as library,即可完成依赖的添加。

为了方便,录制了一段添加视频, 供参考:

链接: http://pan.baidu.com/s/1c0cYxpQ 密码: xns5

 

新建好了Android项目,添加一个第三方已经打包好的jar文件进你项目,下面就已添加一个ActiveAndroid-master的一个包

一。  粘贴第三方jar包, 如下图

粘贴要在android studio中导入的jar文件到libs中
粘贴要在android studio中导入的jar文件到libs中

直接通过COPY/PAST 把你下载的jar文件添加到libs文件夹下

二。 设置被粘贴的文件为库文件, 经过测试这个设置可以通知ide,系统中多了个jar, 然后在你需要导入类时, ide可以帮助你进行, 也可以进行编译检查。

在android studio中将粘贴进的文件设置为库
在android studio中将粘贴进的文件设置为库

然后在libs文件夹和添加的*.jar文件下鼠标单击菜单 add as library

三。 设置gradle的编译文件, 通过测试, 不设置这个文件, 程序没办法最后编译成功
在android studio中导入jar文件的关键一步设置build.gradle文件
在android studio中导入jar文件的关键一步设置build.gradle文件

打开App目录下有个build.gradle文件应该项目结构文件,上述的动作只是为了在在文件下添加

dependencies {

compile files('libs/android-support-v13.jar')

compile files('libs/ActiveAndroid-master.jar')

}

 

 

 

android studio中http访问网站的几种异常情况

Android对HTTP(超文本传输协议)也提供了很好的支持,这里包括两种接口:

1、标准Java接口(java.net) ----HttpURLConnection,可以实现简单的基于URL请求、响应功能;

2、Apache接口(org.appache.http)----HttpClient,使用起来更方面更强大。一般来说,用这种接口。

本文主要是探索几种http使用方式的不正确的情况,这些情况都会引起不正确的异常程序关闭

第一种情况: 在android的事件处理函数中,直接调用网络函数进行网络访问,这种情况,会直接导致android程序停止运行

第二种情况:在android的事件出来函数中,启动一个线程, 在线程中访问网络, 网络访问完成后, 将数据传递给android的界面中的临时变量, 但是这个情况下, 事件出来函数中不知道什么时候网络完成,因此例子里面用的是线程的join方法, 这个方法可以等待另外线程(网络访问)完成, 然后在事件处理函数进行数据的处理,这个的问题是, join时事件处理线程(UI)不能在响应其他请求,特别是网络线程中有网络异常例如连接超时,网络速度缓慢, 也有些情况下,在网络访问线程中有死锁或者sleep等类似操作等,都会造成事件处理函数的 等待,严重影响用户体验甚至不能工作

第三种情况: 在网络处理函数中直接将 获取到的数据设置到 android界面中, 这个情况下, 事件处理函数不用在等待了, 他直接启动线程就完成了。但是这个情况下,android程序会直接退出。android禁止在非 ui(非主线程)线程中 访问ui元素,界面控件等

本程序中网络方面采用HttpURLConnection进行http的访问, 相关HttpURLConnection情况如下, 具体代码见下面的链接。

HttpURLConnection继承自 URLConnection类,用它可以发送和接口任何类型和长度的数据,且预先不用知道数据流的长度,可以设置请求方式get或post、超时时间。

下面直接贴代码,代码目的有两个,一是访问百度首页,获取其返回的html字符串,二是给定URL下载个图片并显示出来。后续将展开系列博文介绍HTTP相关知识。

两个核心文件都略了, 稍后提供完整的源代码, 如下:

链接: http://pan.baidu.com/s/1nt5guxj 密码: dmp3

activity_main.xml

MainActivity.java

必须注意的是:
AndroidManifest.xml 里记得加访问网络的权限:

<uses-permission android:name="android.permission.INTERNET"/>

否则访问不能成功

注意事项:

1、 使用HttpURLConnection的步骤是先实例化一个URL对象,通过URL的openConnection实例化 HttpURLConnection对象。然后设置参数,注意此时并没有发生连接。真正发生连接是在获得流时即conn.getInputStream这 一句时,这点跟TCP Socket是一样的。并非阻塞在ServerSocket.accept()而是阻塞在获取流。所以在获取流之前应该设置好所有的参数。

2、Android4.0后所有网络方面的操作都不能再主线程!!!在获取网页响应字符串时本文代码使用了Thread,在下载图片(后面在提供例子)时使用了AsyncTask,可以对比其使用的异同。很明显,AsyncTask更加方面。在onPreExecute和onPostExecute里可以很方面的做主线程UI的事。

3、 在获取网页字符串时,使用了线程的Thread.join函数,这会使在onClick里在join处进行阻塞,直到Thread的run执行完才会进行 判断,界面卡死。因此在实际开发中要尽量避免之中,解决方法是使用Thread+Handle的方式,或AsyncTask。实际上后者就是前者的封装。

下面是集中工作情况的截图,供参考:

 

在android的事件处理函数中进行的网络操作例子(异常退出)
在android的事件处理函数中进行的网络操作例子(异常退出)

运行结果如下:

android 程序异常退出

启动一个线程, 在线程中调用网络访问, 在网络访问中用sleep模拟长时间不返回的情况

这个情况下, 点击其他按钮是没有响应的
这个情况下, 点击其他按钮是没有响应的
在非ui线程中访问 android的ui元素,造成异常退出
在非ui线程中访问 android的ui元素,造成异常退出

运行结果:

异常退出